blob: 3c381ceadb98f7d62486551a720d056eb598ca9e [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200259 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_nullfunc_retries = 3,
261 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300262 .keep_alive_interval = 55000,
263 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200265 .itrim = {
266 .enable = false,
267 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200268 },
269 .pm_config = {
270 .host_clk_settling_time = 5000,
271 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300272 },
273 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 .trigger_pacing = 1,
275 .avg_weight_rssi_beacon = 20,
276 .avg_weight_rssi_data = 10,
277 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100278 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200279 },
280 .scan = {
281 .min_dwell_time_active = 7500,
282 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100283 .min_dwell_time_passive = 100000,
284 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200285 .num_probe_reqs = 2,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
300 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200301 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 70,
305 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200306 .dynamic_memory = 0,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200307 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200310 },
311 .mem_wl128x = {
312 .num_stations = 1,
313 .ssid_profiles = 1,
314 .rx_block_num = 40,
315 .tx_min_block_num = 40,
316 .dynamic_memory = 1,
317 .min_req_tx_blocks = 45,
318 .min_req_rx_blocks = 22,
319 .tx_min = 27,
320 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300321};
322
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200323static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200324static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200325
326
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200327static void wl1271_device_release(struct device *dev)
328{
329
330}
331
332static struct platform_device wl1271_device = {
333 .name = "wl1271",
334 .id = -1,
335
336 /* device model insists to have a release function */
337 .dev = {
338 .release = wl1271_device_release,
339 },
340};
341
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300342static LIST_HEAD(wl_list);
343
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300344static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
345 void *arg)
346{
347 struct net_device *dev = arg;
348 struct wireless_dev *wdev;
349 struct wiphy *wiphy;
350 struct ieee80211_hw *hw;
351 struct wl1271 *wl;
352 struct wl1271 *wl_temp;
353 int ret = 0;
354
355 /* Check that this notification is for us. */
356 if (what != NETDEV_CHANGE)
357 return NOTIFY_DONE;
358
359 wdev = dev->ieee80211_ptr;
360 if (wdev == NULL)
361 return NOTIFY_DONE;
362
363 wiphy = wdev->wiphy;
364 if (wiphy == NULL)
365 return NOTIFY_DONE;
366
367 hw = wiphy_priv(wiphy);
368 if (hw == NULL)
369 return NOTIFY_DONE;
370
371 wl_temp = hw->priv;
372 list_for_each_entry(wl, &wl_list, list) {
373 if (wl == wl_temp)
374 break;
375 }
376 if (wl != wl_temp)
377 return NOTIFY_DONE;
378
379 mutex_lock(&wl->mutex);
380
381 if (wl->state == WL1271_STATE_OFF)
382 goto out;
383
384 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
385 goto out;
386
Ido Yariva6208652011-03-01 15:14:41 +0200387 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300388 if (ret < 0)
389 goto out;
390
391 if ((dev->operstate == IF_OPER_UP) &&
392 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
393 wl1271_cmd_set_sta_state(wl);
394 wl1271_info("Association completed.");
395 }
396
397 wl1271_ps_elp_sleep(wl);
398
399out:
400 mutex_unlock(&wl->mutex);
401
402 return NOTIFY_OK;
403}
404
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100405static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200406 struct regulatory_request *request)
407{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100408 struct ieee80211_supported_band *band;
409 struct ieee80211_channel *ch;
410 int i;
411
412 band = wiphy->bands[IEEE80211_BAND_5GHZ];
413 for (i = 0; i < band->n_channels; i++) {
414 ch = &band->channels[i];
415 if (ch->flags & IEEE80211_CHAN_DISABLED)
416 continue;
417
418 if (ch->flags & IEEE80211_CHAN_RADAR)
419 ch->flags |= IEEE80211_CHAN_NO_IBSS |
420 IEEE80211_CHAN_PASSIVE_SCAN;
421
422 }
423
424 return 0;
425}
426
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300427static void wl1271_conf_init(struct wl1271 *wl)
428{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300429
430 /*
431 * This function applies the default configuration to the driver. This
432 * function is invoked upon driver load (spi probe.)
433 *
434 * The configuration is stored in a run-time structure in order to
435 * facilitate for run-time adjustment of any of the parameters. Making
436 * changes to the configuration structure will apply the new values on
437 * the next interface up (wl1271_op_start.)
438 */
439
440 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300441 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300442}
443
444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445static int wl1271_plt_init(struct wl1271 *wl)
446{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200447 struct conf_tx_ac_category *conf_ac;
448 struct conf_tx_tid *conf_tid;
449 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450
Shahar Levi49d750ca2011-03-06 16:32:09 +0200451 if (wl->chip.id == CHIP_ID_1283_PG20)
452 ret = wl128x_cmd_general_parms(wl);
453 else
454 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200455 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200456 return ret;
457
Shahar Levi49d750ca2011-03-06 16:32:09 +0200458 if (wl->chip.id == CHIP_ID_1283_PG20)
459 ret = wl128x_cmd_radio_parms(wl);
460 else
461 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200462 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200463 return ret;
464
Shahar Levi49d750ca2011-03-06 16:32:09 +0200465 if (wl->chip.id != CHIP_ID_1283_PG20) {
466 ret = wl1271_cmd_ext_radio_parms(wl);
467 if (ret < 0)
468 return ret;
469 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200470 if (ret < 0)
471 return ret;
472
Shahar Levi48a61472011-03-06 16:32:08 +0200473 /* Chip-specific initializations */
474 ret = wl1271_chip_specific_init(wl);
475 if (ret < 0)
476 return ret;
477
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200478 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200479 if (ret < 0)
480 return ret;
481
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482 ret = wl1271_acx_init_mem_config(wl);
483 if (ret < 0)
484 return ret;
485
Luciano Coelho12419cc2010-02-18 13:25:44 +0200486 /* PHY layer config */
487 ret = wl1271_init_phy_config(wl);
488 if (ret < 0)
489 goto out_free_memmap;
490
491 ret = wl1271_acx_dco_itrim_params(wl);
492 if (ret < 0)
493 goto out_free_memmap;
494
495 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200496 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200497 if (ret < 0)
498 goto out_free_memmap;
499
500 /* Bluetooth WLAN coexistence */
501 ret = wl1271_init_pta(wl);
502 if (ret < 0)
503 goto out_free_memmap;
504
505 /* Energy detection */
506 ret = wl1271_init_energy_detection(wl);
507 if (ret < 0)
508 goto out_free_memmap;
509
Gery Kahn1ec610e2011-02-01 03:03:08 -0600510 ret = wl1271_acx_sta_mem_cfg(wl);
511 if (ret < 0)
512 goto out_free_memmap;
513
Luciano Coelho12419cc2010-02-18 13:25:44 +0200514 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100515 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200516 if (ret < 0)
517 goto out_free_memmap;
518
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200519 /* Default TID/AC configuration */
520 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200521 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200522 conf_ac = &wl->conf.tx.ac_conf[i];
523 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
524 conf_ac->cw_max, conf_ac->aifsn,
525 conf_ac->tx_op_limit);
526 if (ret < 0)
527 goto out_free_memmap;
528
Luciano Coelho12419cc2010-02-18 13:25:44 +0200529 conf_tid = &wl->conf.tx.tid_conf[i];
530 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
531 conf_tid->channel_type,
532 conf_tid->tsid,
533 conf_tid->ps_scheme,
534 conf_tid->ack_policy,
535 conf_tid->apsd_conf[0],
536 conf_tid->apsd_conf[1]);
537 if (ret < 0)
538 goto out_free_memmap;
539 }
540
Luciano Coelho12419cc2010-02-18 13:25:44 +0200541 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200542 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200544 goto out_free_memmap;
545
546 /* Configure for CAM power saving (ie. always active) */
547 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
548 if (ret < 0)
549 goto out_free_memmap;
550
551 /* configure PM */
552 ret = wl1271_acx_pm_config(wl);
553 if (ret < 0)
554 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200557
558 out_free_memmap:
559 kfree(wl->target_mem_map);
560 wl->target_mem_map = NULL;
561
562 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300563}
564
Arik Nemtsovb622d992011-02-23 00:22:31 +0200565static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
566{
567 bool fw_ps;
568
569 /* only regulate station links */
570 if (hlid < WL1271_AP_STA_HLID_START)
571 return;
572
573 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
574
575 /*
576 * Wake up from high level PS if the STA is asleep with too little
577 * blocks in FW or if the STA is awake.
578 */
579 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
580 wl1271_ps_link_end(wl, hlid);
581
582 /* Start high-level PS if the STA is asleep with enough blocks in FW */
583 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
584 wl1271_ps_link_start(wl, hlid, true);
585}
586
587static void wl1271_irq_update_links_status(struct wl1271 *wl,
588 struct wl1271_fw_ap_status *status)
589{
590 u32 cur_fw_ps_map;
591 u8 hlid;
592
593 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
594 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
595 wl1271_debug(DEBUG_PSM,
596 "link ps prev 0x%x cur 0x%x changed 0x%x",
597 wl->ap_fw_ps_map, cur_fw_ps_map,
598 wl->ap_fw_ps_map ^ cur_fw_ps_map);
599
600 wl->ap_fw_ps_map = cur_fw_ps_map;
601 }
602
603 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
604 u8 cnt = status->tx_lnk_free_blks[hlid] -
605 wl->links[hlid].prev_freed_blks;
606
607 wl->links[hlid].prev_freed_blks =
608 status->tx_lnk_free_blks[hlid];
609 wl->links[hlid].allocated_blks -= cnt;
610
611 wl1271_irq_ps_regulate_link(wl, hlid,
612 wl->links[hlid].allocated_blks);
613 }
614}
615
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300616static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200617 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200619 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200620 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200621 u32 old_tx_blk_count = wl->tx_blocks_available;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 u32 total = 0;
623 int i;
624
Shahar Levi13b107d2011-03-06 16:32:12 +0200625 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200626 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
627 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200628 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200629 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
630 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300631
Shahar Levi13b107d2011-03-06 16:32:12 +0200632 /* Update tx total blocks change */
633 wl->tx_total_diff +=
634 ((struct wl1271_fw_sta_status *)status)->tx_total -
635 wl->tx_new_total;
636
637 /* Update total tx blocks */
638 wl->tx_new_total =
639 ((struct wl1271_fw_sta_status *)status)->tx_total;
640 }
641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
643 "drv_rx_counter = %d, tx_results_counter = %d)",
644 status->intr,
645 status->fw_rx_counter,
646 status->drv_rx_counter,
647 status->tx_results_counter);
648
649 /* update number of available TX blocks */
650 for (i = 0; i < NUM_TX_QUEUES; i++) {
Shahar Levi13b107d2011-03-06 16:32:12 +0200651 total += le32_to_cpu(status->tx_released_blks[i]) -
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300652 wl->tx_blocks_freed[i];
653
654 wl->tx_blocks_freed[i] =
655 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200656
657 }
658
659 /*
660 * By adding the freed blocks to tx_total_diff we are actually
661 * moving them to the RX pool.
662 */
663 wl->tx_total_diff += total;
664
665 /* if we have positive difference, add the blocks to the TX pool */
666 if (wl->tx_total_diff >= 0) {
667 wl->tx_blocks_available += wl->tx_total_diff;
668 wl->tx_total_diff = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 }
670
Ido Yariva5225502010-10-12 14:49:10 +0200671 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200672 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200673 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674
Arik Nemtsovb622d992011-02-23 00:22:31 +0200675 /* for AP update num of allocated TX blocks per link and ps status */
676 if (wl->bss_type == BSS_TYPE_AP_BSS)
677 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200680 getnstimeofday(&ts);
681 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
682 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683}
684
Ido Yariva6208652011-03-01 15:14:41 +0200685static void wl1271_flush_deferred_work(struct wl1271 *wl)
686{
687 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200688
Ido Yariva6208652011-03-01 15:14:41 +0200689 /* Pass all received frames to the network stack */
690 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
691 ieee80211_rx_ni(wl->hw, skb);
692
693 /* Return sent skbs to the network stack */
694 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
695 ieee80211_tx_status(wl->hw, skb);
696}
697
698static void wl1271_netstack_work(struct work_struct *work)
699{
700 struct wl1271 *wl =
701 container_of(work, struct wl1271, netstack_work);
702
703 do {
704 wl1271_flush_deferred_work(wl);
705 } while (skb_queue_len(&wl->deferred_rx_queue));
706}
707
708#define WL1271_IRQ_MAX_LOOPS 256
709
710irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300713 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200714 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200715 struct wl1271 *wl = (struct wl1271 *)cookie;
716 bool done = false;
717 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200718 unsigned long flags;
719
720 /* TX might be handled here, avoid redundant work */
721 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
722 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723
724 mutex_lock(&wl->mutex);
725
726 wl1271_debug(DEBUG_IRQ, "IRQ work");
727
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200728 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300729 goto out;
730
Ido Yariva6208652011-03-01 15:14:41 +0200731 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 if (ret < 0)
733 goto out;
734
Ido Yariva6208652011-03-01 15:14:41 +0200735 while (!done && loopcount--) {
736 /*
737 * In order to avoid a race with the hardirq, clear the flag
738 * before acknowledging the chip. Since the mutex is held,
739 * wl1271_ps_elp_wakeup cannot be called concurrently.
740 */
741 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
742 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200743
744 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200745 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200746 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200747 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200748 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200749 continue;
750 }
751
Eliad Pellerccc83b02010-10-27 14:09:57 +0200752 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
753 wl1271_error("watchdog interrupt received! "
754 "starting recovery.");
755 ieee80211_queue_work(wl->hw, &wl->recovery_work);
756
757 /* restarting the chip. ignore any other interrupt. */
758 goto out;
759 }
760
Ido Yariva6208652011-03-01 15:14:41 +0200761 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200762 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
763
Ido Yariv8aad2462011-03-01 15:14:38 +0200764 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200765
Ido Yariva5225502010-10-12 14:49:10 +0200766 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200767 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200768 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200769 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200770 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200771 /*
772 * In order to avoid starvation of the TX path,
773 * call the work function directly.
774 */
775 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200776 } else {
777 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200778 }
779
Ido Yariv8aad2462011-03-01 15:14:38 +0200780 /* check for tx results */
781 if (wl->fw_status->common.tx_results_counter !=
782 (wl->tx_results_count & 0xff))
783 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200784
785 /* Make sure the deferred queues don't get too long */
786 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
787 skb_queue_len(&wl->deferred_rx_queue);
788 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
789 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200790 }
791
792 if (intr & WL1271_ACX_INTR_EVENT_A) {
793 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
794 wl1271_event_handle(wl, 0);
795 }
796
797 if (intr & WL1271_ACX_INTR_EVENT_B) {
798 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
799 wl1271_event_handle(wl, 1);
800 }
801
802 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
803 wl1271_debug(DEBUG_IRQ,
804 "WL1271_ACX_INTR_INIT_COMPLETE");
805
806 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
807 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 }
809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810 wl1271_ps_elp_sleep(wl);
811
812out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200813 spin_lock_irqsave(&wl->wl_lock, flags);
814 /* In case TX was not handled here, queue TX work */
815 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
816 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
817 wl->tx_queue_count)
818 ieee80211_queue_work(wl->hw, &wl->tx_work);
819 spin_unlock_irqrestore(&wl->wl_lock, flags);
820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200822
823 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824}
Ido Yariva6208652011-03-01 15:14:41 +0200825EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827static int wl1271_fetch_firmware(struct wl1271 *wl)
828{
829 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200830 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831 int ret;
832
Arik Nemtsov166d5042010-10-16 21:44:57 +0200833 switch (wl->bss_type) {
834 case BSS_TYPE_AP_BSS:
835 fw_name = WL1271_AP_FW_NAME;
836 break;
837 case BSS_TYPE_IBSS:
838 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200839 if (wl->chip.id == CHIP_ID_1283_PG20)
840 fw_name = WL128X_FW_NAME;
841 else
842 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200843 break;
844 default:
845 wl1271_error("no compatible firmware for bss_type %d",
846 wl->bss_type);
847 return -EINVAL;
848 }
849
850 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
851
852 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853
854 if (ret < 0) {
855 wl1271_error("could not get firmware: %d", ret);
856 return ret;
857 }
858
859 if (fw->size % 4) {
860 wl1271_error("firmware size is not multiple of 32 bits: %zu",
861 fw->size);
862 ret = -EILSEQ;
863 goto out;
864 }
865
Arik Nemtsov166d5042010-10-16 21:44:57 +0200866 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300868 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869
870 if (!wl->fw) {
871 wl1271_error("could not allocate memory for the firmware");
872 ret = -ENOMEM;
873 goto out;
874 }
875
876 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200877 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 ret = 0;
879
880out:
881 release_firmware(fw);
882
883 return ret;
884}
885
886static int wl1271_fetch_nvs(struct wl1271 *wl)
887{
888 const struct firmware *fw;
889 int ret;
890
Shahar Levi5aa42342011-03-06 16:32:07 +0200891 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892
893 if (ret < 0) {
894 wl1271_error("could not get nvs file: %d", ret);
895 return ret;
896 }
897
Shahar Levibc765bf2011-03-06 16:32:10 +0200898 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
900 if (!wl->nvs) {
901 wl1271_error("could not allocate memory for the nvs file");
902 ret = -ENOMEM;
903 goto out;
904 }
905
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200906 wl->nvs_len = fw->size;
907
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908out:
909 release_firmware(fw);
910
911 return ret;
912}
913
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200914static void wl1271_recovery_work(struct work_struct *work)
915{
916 struct wl1271 *wl =
917 container_of(work, struct wl1271, recovery_work);
918
919 mutex_lock(&wl->mutex);
920
921 if (wl->state != WL1271_STATE_ON)
922 goto out;
923
924 wl1271_info("Hardware recovery in progress.");
925
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200926 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
927 ieee80211_connection_loss(wl->vif);
928
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200929 /* reboot the chipset */
930 __wl1271_op_remove_interface(wl);
931 ieee80211_restart_hw(wl->hw);
932
933out:
934 mutex_unlock(&wl->mutex);
935}
936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937static void wl1271_fw_wakeup(struct wl1271 *wl)
938{
939 u32 elp_reg;
940
941 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300942 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943}
944
945static int wl1271_setup(struct wl1271 *wl)
946{
947 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
948 if (!wl->fw_status)
949 return -ENOMEM;
950
951 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
952 if (!wl->tx_res_if) {
953 kfree(wl->fw_status);
954 return -ENOMEM;
955 }
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957 return 0;
958}
959
960static int wl1271_chip_wakeup(struct wl1271 *wl)
961{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300962 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 int ret = 0;
964
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200965 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200966 ret = wl1271_power_on(wl);
967 if (ret < 0)
968 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200970 wl1271_io_reset(wl);
971 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 /* We don't need a real memory partition here, because we only want
974 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300975 memset(&partition, 0, sizeof(partition));
976 partition.reg.start = REGISTERS_BASE;
977 partition.reg.size = REGISTERS_DOWN_SIZE;
978 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
980 /* ELP module wake up */
981 wl1271_fw_wakeup(wl);
982
983 /* whal_FwCtrl_BootSm() */
984
985 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200986 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
988 /* 1. check if chip id is valid */
989
990 switch (wl->chip.id) {
991 case CHIP_ID_1271_PG10:
992 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
993 wl->chip.id);
994
995 ret = wl1271_setup(wl);
996 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 break;
999 case CHIP_ID_1271_PG20:
1000 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1001 wl->chip.id);
1002
1003 ret = wl1271_setup(wl);
1004 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001005 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 break;
1007 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001010 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 }
1012
Arik Nemtsov166d5042010-10-16 21:44:57 +02001013 /* Make sure the firmware type matches the BSS type */
1014 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 ret = wl1271_fetch_firmware(wl);
1016 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001017 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 }
1019
1020 /* No NVS from netlink, try to get it from the filesystem */
1021 if (wl->nvs == NULL) {
1022 ret = wl1271_fetch_nvs(wl);
1023 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001024 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 }
1026
1027out:
1028 return ret;
1029}
1030
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031int wl1271_plt_start(struct wl1271 *wl)
1032{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001033 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 int ret;
1035
1036 mutex_lock(&wl->mutex);
1037
1038 wl1271_notice("power up");
1039
1040 if (wl->state != WL1271_STATE_OFF) {
1041 wl1271_error("cannot go into PLT state because not "
1042 "in off state: %d", wl->state);
1043 ret = -EBUSY;
1044 goto out;
1045 }
1046
Arik Nemtsov166d5042010-10-16 21:44:57 +02001047 wl->bss_type = BSS_TYPE_STA_BSS;
1048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001049 while (retries) {
1050 retries--;
1051 ret = wl1271_chip_wakeup(wl);
1052 if (ret < 0)
1053 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001055 ret = wl1271_boot(wl);
1056 if (ret < 0)
1057 goto power_off;
1058
1059 ret = wl1271_plt_init(wl);
1060 if (ret < 0)
1061 goto irq_disable;
1062
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001063 wl->state = WL1271_STATE_PLT;
1064 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001065 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 goto out;
1067
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001068irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001069 mutex_unlock(&wl->mutex);
1070 /* Unlocking the mutex in the middle of handling is
1071 inherently unsafe. In this case we deem it safe to do,
1072 because we need to let any possibly pending IRQ out of
1073 the system (and while we are WL1271_STATE_OFF the IRQ
1074 work function will not do anything.) Also, any other
1075 possible concurrent operations will fail due to the
1076 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001077 wl1271_disable_interrupts(wl);
1078 wl1271_flush_deferred_work(wl);
1079 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001080 mutex_lock(&wl->mutex);
1081power_off:
1082 wl1271_power_off(wl);
1083 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001085 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1086 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087out:
1088 mutex_unlock(&wl->mutex);
1089
1090 return ret;
1091}
1092
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001093int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094{
1095 int ret = 0;
1096
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 wl1271_notice("power down");
1098
1099 if (wl->state != WL1271_STATE_PLT) {
1100 wl1271_error("cannot power down because not in PLT "
1101 "state: %d", wl->state);
1102 ret = -EBUSY;
1103 goto out;
1104 }
1105
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 wl1271_power_off(wl);
1107
1108 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001109 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001112 wl1271_disable_interrupts(wl);
1113 wl1271_flush_deferred_work(wl);
1114 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001115 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001116 mutex_lock(&wl->mutex);
1117out:
1118 return ret;
1119}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001120
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001121int wl1271_plt_stop(struct wl1271 *wl)
1122{
1123 int ret;
1124
1125 mutex_lock(&wl->mutex);
1126 ret = __wl1271_plt_stop(wl);
1127 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128 return ret;
1129}
1130
Johannes Berg7bb45682011-02-24 14:42:06 +01001131static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132{
1133 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001134 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001135 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001136 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
Ido Yarivb07d4032011-03-01 15:14:43 +02001138 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1139
1140 if (wl->bss_type == BSS_TYPE_AP_BSS)
1141 hlid = wl1271_tx_get_hlid(skb);
1142
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001143 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001144
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001145 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001146
1147 /*
1148 * The workqueue is slow to process the tx_queue and we need stop
1149 * the queue here, otherwise the queue will get too long.
1150 */
1151 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1152 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1153 ieee80211_stop_queues(wl->hw);
1154 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1155 }
1156
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001157 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001158 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001159 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1160 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1161 } else {
1162 skb_queue_tail(&wl->tx_queue[q], skb);
1163 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164
1165 /*
1166 * The chip specific setup must run before the first TX packet -
1167 * before that, the tx_work will not be initialized!
1168 */
1169
Ido Yarivb07d4032011-03-01 15:14:43 +02001170 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1171 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001172 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001173
1174 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175}
1176
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001177static struct notifier_block wl1271_dev_notifier = {
1178 .notifier_call = wl1271_dev_notify,
1179};
1180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181static int wl1271_op_start(struct ieee80211_hw *hw)
1182{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001183 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1184
1185 /*
1186 * We have to delay the booting of the hardware because
1187 * we need to know the local MAC address before downloading and
1188 * initializing the firmware. The MAC address cannot be changed
1189 * after boot, and without the proper MAC address, the firmware
1190 * will not function properly.
1191 *
1192 * The MAC address is first known when the corresponding interface
1193 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001194 *
1195 * In addition, we currently have different firmwares for AP and managed
1196 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001197 */
1198
1199 return 0;
1200}
1201
1202static void wl1271_op_stop(struct ieee80211_hw *hw)
1203{
1204 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1205}
1206
1207static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1208 struct ieee80211_vif *vif)
1209{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001211 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001212 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001214 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001216 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1217 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218
1219 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001220 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001221 wl1271_debug(DEBUG_MAC80211,
1222 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001223 ret = -EBUSY;
1224 goto out;
1225 }
1226
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001227 switch (vif->type) {
1228 case NL80211_IFTYPE_STATION:
1229 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001230 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001231 break;
1232 case NL80211_IFTYPE_ADHOC:
1233 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001234 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001235 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001236 case NL80211_IFTYPE_AP:
1237 wl->bss_type = BSS_TYPE_AP_BSS;
1238 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001239 default:
1240 ret = -EOPNOTSUPP;
1241 goto out;
1242 }
1243
1244 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
1246 if (wl->state != WL1271_STATE_OFF) {
1247 wl1271_error("cannot start because not in off state: %d",
1248 wl->state);
1249 ret = -EBUSY;
1250 goto out;
1251 }
1252
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001253 while (retries) {
1254 retries--;
1255 ret = wl1271_chip_wakeup(wl);
1256 if (ret < 0)
1257 goto power_off;
1258
1259 ret = wl1271_boot(wl);
1260 if (ret < 0)
1261 goto power_off;
1262
1263 ret = wl1271_hw_init(wl);
1264 if (ret < 0)
1265 goto irq_disable;
1266
Eliad Peller71125ab2010-10-28 21:46:43 +02001267 booted = true;
1268 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001270irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001271 mutex_unlock(&wl->mutex);
1272 /* Unlocking the mutex in the middle of handling is
1273 inherently unsafe. In this case we deem it safe to do,
1274 because we need to let any possibly pending IRQ out of
1275 the system (and while we are WL1271_STATE_OFF the IRQ
1276 work function will not do anything.) Also, any other
1277 possible concurrent operations will fail due to the
1278 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001279 wl1271_disable_interrupts(wl);
1280 wl1271_flush_deferred_work(wl);
1281 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001282 mutex_lock(&wl->mutex);
1283power_off:
1284 wl1271_power_off(wl);
1285 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286
Eliad Peller71125ab2010-10-28 21:46:43 +02001287 if (!booted) {
1288 wl1271_error("firmware boot failed despite %d retries",
1289 WL1271_BOOT_RETRIES);
1290 goto out;
1291 }
1292
1293 wl->vif = vif;
1294 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001295 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001296
1297 /* update hw/fw version info in wiphy struct */
1298 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001299 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001300 sizeof(wiphy->fw_version));
1301
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001302 /*
1303 * Now we know if 11a is supported (info from the NVS), so disable
1304 * 11a channels if not supported
1305 */
1306 if (!wl->enable_11a)
1307 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1308
1309 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1310 wl->enable_11a ? "" : "not ");
1311
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001312out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 mutex_unlock(&wl->mutex);
1314
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001315 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001316 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001317
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 return ret;
1319}
1320
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001321static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323 int i;
1324
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001325 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001327 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001329 list_del(&wl->list);
1330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 WARN_ON(wl->state != WL1271_STATE_ON);
1332
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001333 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001334 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001335 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001336
Luciano Coelho08688d62010-07-08 17:50:07 +03001337 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001338 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1339 kfree(wl->scan.scanned_ch);
1340 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001341 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001342 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 }
1344
1345 wl->state = WL1271_STATE_OFF;
1346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 mutex_unlock(&wl->mutex);
1348
Ido Yariva6208652011-03-01 15:14:41 +02001349 wl1271_disable_interrupts(wl);
1350 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001351 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001352 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001354 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001355 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356
1357 mutex_lock(&wl->mutex);
1358
1359 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001360 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361 wl1271_power_off(wl);
1362
1363 memset(wl->bssid, 0, ETH_ALEN);
1364 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1365 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001367 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001368 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369
1370 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001371 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1373 wl->tx_blocks_available = 0;
1374 wl->tx_results_count = 0;
1375 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001376 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001377 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378 wl->time_offset = 0;
1379 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001380 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001381 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001382 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001383 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001384 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001385 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001386 wl->ap_fw_ps_map = 0;
1387 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001388 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001389
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390 for (i = 0; i < NUM_TX_QUEUES; i++)
1391 wl->tx_blocks_freed[i] = 0;
1392
1393 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001394
1395 kfree(wl->fw_status);
1396 wl->fw_status = NULL;
1397 kfree(wl->tx_res_if);
1398 wl->tx_res_if = NULL;
1399 kfree(wl->target_mem_map);
1400 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001401}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001402
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001403static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1404 struct ieee80211_vif *vif)
1405{
1406 struct wl1271 *wl = hw->priv;
1407
1408 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001409 /*
1410 * wl->vif can be null here if someone shuts down the interface
1411 * just when hardware recovery has been started.
1412 */
1413 if (wl->vif) {
1414 WARN_ON(wl->vif != vif);
1415 __wl1271_op_remove_interface(wl);
1416 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001417
Juuso Oikarinen67353292010-11-18 15:19:02 +02001418 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001419 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420}
1421
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001422static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1423{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001424 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001425
1426 /* combine requested filters with current filter config */
1427 filters = wl->filters | filters;
1428
1429 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1430
1431 if (filters & FIF_PROMISC_IN_BSS) {
1432 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1433 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1434 wl->rx_config |= CFG_BSSID_FILTER_EN;
1435 }
1436 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1437 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1438 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1439 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1440 }
1441 if (filters & FIF_OTHER_BSS) {
1442 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1443 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1444 }
1445 if (filters & FIF_CONTROL) {
1446 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1447 wl->rx_filter |= CFG_RX_CTL_EN;
1448 }
1449 if (filters & FIF_FCSFAIL) {
1450 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1451 wl->rx_filter |= CFG_RX_FCS_ERROR;
1452 }
1453}
1454
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001455static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001456{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001457 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001458 /* we need to use a dummy BSSID for now */
1459 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1460 0xad, 0xbe, 0xef };
1461
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001462 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1463
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001464 /* pass through frames from all BSS */
1465 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1466
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001467 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001468 if (ret < 0)
1469 goto out;
1470
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001471 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001472
1473out:
1474 return ret;
1475}
1476
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001477static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001478{
1479 int ret;
1480
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001481 /*
1482 * One of the side effects of the JOIN command is that is clears
1483 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1484 * to a WPA/WPA2 access point will therefore kill the data-path.
1485 * Currently there is no supported scenario for JOIN during
1486 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1487 * must be handled somehow.
1488 *
1489 */
1490 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1491 wl1271_info("JOIN while associated.");
1492
1493 if (set_assoc)
1494 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1495
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001496 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1497 if (ret < 0)
1498 goto out;
1499
1500 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1501
1502 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1503 goto out;
1504
1505 /*
1506 * The join command disable the keep-alive mode, shut down its process,
1507 * and also clear the template config, so we need to reset it all after
1508 * the join. The acx_aid starts the keep-alive process, and the order
1509 * of the commands below is relevant.
1510 */
1511 ret = wl1271_acx_keep_alive_mode(wl, true);
1512 if (ret < 0)
1513 goto out;
1514
1515 ret = wl1271_acx_aid(wl, wl->aid);
1516 if (ret < 0)
1517 goto out;
1518
1519 ret = wl1271_cmd_build_klv_null_data(wl);
1520 if (ret < 0)
1521 goto out;
1522
1523 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1524 ACX_KEEP_ALIVE_TPL_VALID);
1525 if (ret < 0)
1526 goto out;
1527
1528out:
1529 return ret;
1530}
1531
1532static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001533{
1534 int ret;
1535
1536 /* to stop listening to a channel, we disconnect */
1537 ret = wl1271_cmd_disconnect(wl);
1538 if (ret < 0)
1539 goto out;
1540
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001541 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001542 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001543
1544 /* stop filterting packets based on bssid */
1545 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001546
1547out:
1548 return ret;
1549}
1550
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001551static void wl1271_set_band_rate(struct wl1271 *wl)
1552{
1553 if (wl->band == IEEE80211_BAND_2GHZ)
1554 wl->basic_rate_set = wl->conf.tx.basic_rate;
1555 else
1556 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1557}
1558
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001559static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001560{
1561 int ret;
1562
1563 if (idle) {
1564 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1565 ret = wl1271_unjoin(wl);
1566 if (ret < 0)
1567 goto out;
1568 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001569 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001570 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001571 if (ret < 0)
1572 goto out;
1573 ret = wl1271_acx_keep_alive_config(
1574 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1575 ACX_KEEP_ALIVE_TPL_INVALID);
1576 if (ret < 0)
1577 goto out;
1578 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1579 } else {
1580 /* increment the session counter */
1581 wl->session_counter++;
1582 if (wl->session_counter >= SESSION_COUNTER_MAX)
1583 wl->session_counter = 0;
1584 ret = wl1271_dummy_join(wl);
1585 if (ret < 0)
1586 goto out;
1587 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1588 }
1589
1590out:
1591 return ret;
1592}
1593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1595{
1596 struct wl1271 *wl = hw->priv;
1597 struct ieee80211_conf *conf = &hw->conf;
1598 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001599 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001600
1601 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1602
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001603 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1604 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605 channel,
1606 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001607 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001608 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1609 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001611 /*
1612 * mac80211 will go to idle nearly immediately after transmitting some
1613 * frames, such as the deauth. To make sure those frames reach the air,
1614 * wait here until the TX queue is fully flushed.
1615 */
1616 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1617 (conf->flags & IEEE80211_CONF_IDLE))
1618 wl1271_tx_flush(wl);
1619
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 mutex_lock(&wl->mutex);
1621
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001622 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1623 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001624 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001625 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001626
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001627 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1628
Ido Yariva6208652011-03-01 15:14:41 +02001629 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001630 if (ret < 0)
1631 goto out;
1632
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001633 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001634 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1635 ((wl->band != conf->channel->band) ||
1636 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001637 wl->band = conf->channel->band;
1638 wl->channel = channel;
1639
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001640 if (!is_ap) {
1641 /*
1642 * FIXME: the mac80211 should really provide a fixed
1643 * rate to use here. for now, just use the smallest
1644 * possible rate for the band as a fixed rate for
1645 * association frames and other control messages.
1646 */
1647 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1648 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001649
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001650 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1651 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001652 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001653 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001654 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001655
1656 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1657 ret = wl1271_join(wl, false);
1658 if (ret < 0)
1659 wl1271_warning("cmd join on channel "
1660 "failed %d", ret);
1661 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001662 }
1663 }
1664
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001665 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1666 ret = wl1271_sta_handle_idle(wl,
1667 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001668 if (ret < 0)
1669 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670 }
1671
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001672 /*
1673 * if mac80211 changes the PSM mode, make sure the mode is not
1674 * incorrectly changed after the pspoll failure active window.
1675 */
1676 if (changed & IEEE80211_CONF_CHANGE_PS)
1677 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1678
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001679 if (conf->flags & IEEE80211_CONF_PS &&
1680 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1681 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682
1683 /*
1684 * We enter PSM only if we're already associated.
1685 * If we're not, we'll enter it when joining an SSID,
1686 * through the bss_info_changed() hook.
1687 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001688 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001689 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001690 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001691 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001692 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001694 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001695 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001697 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001699 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001700 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001701 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702 }
1703
1704 if (conf->power_level != wl->power_level) {
1705 ret = wl1271_acx_tx_power(wl, conf->power_level);
1706 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001707 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708
1709 wl->power_level = conf->power_level;
1710 }
1711
1712out_sleep:
1713 wl1271_ps_elp_sleep(wl);
1714
1715out:
1716 mutex_unlock(&wl->mutex);
1717
1718 return ret;
1719}
1720
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001721struct wl1271_filter_params {
1722 bool enabled;
1723 int mc_list_length;
1724 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1725};
1726
Jiri Pirko22bedad2010-04-01 21:22:57 +00001727static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1728 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001729{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001730 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001731 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001732 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001733
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001734 if (unlikely(wl->state == WL1271_STATE_OFF))
1735 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001736
Juuso Oikarinen74441132009-10-13 12:47:53 +03001737 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001738 if (!fp) {
1739 wl1271_error("Out of memory setting filters.");
1740 return 0;
1741 }
1742
1743 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001744 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001745 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1746 fp->enabled = false;
1747 } else {
1748 fp->enabled = true;
1749 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001750 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001751 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001752 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001753 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001754 }
1755
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001756 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001757}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001758
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001759#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1760 FIF_ALLMULTI | \
1761 FIF_FCSFAIL | \
1762 FIF_BCN_PRBRESP_PROMISC | \
1763 FIF_CONTROL | \
1764 FIF_OTHER_BSS)
1765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1767 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001768 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001770 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001772 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773
Arik Nemtsov7d057862010-10-16 19:25:35 +02001774 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1775 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001776
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001777 mutex_lock(&wl->mutex);
1778
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001779 *total &= WL1271_SUPPORTED_FILTERS;
1780 changed &= WL1271_SUPPORTED_FILTERS;
1781
1782 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001783 goto out;
1784
Ido Yariva6208652011-03-01 15:14:41 +02001785 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001786 if (ret < 0)
1787 goto out;
1788
Arik Nemtsov7d057862010-10-16 19:25:35 +02001789 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1790 if (*total & FIF_ALLMULTI)
1791 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1792 else if (fp)
1793 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1794 fp->mc_list,
1795 fp->mc_list_length);
1796 if (ret < 0)
1797 goto out_sleep;
1798 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001800 /* determine, whether supported filter values have changed */
1801 if (changed == 0)
1802 goto out_sleep;
1803
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001804 /* configure filters */
1805 wl->filters = *total;
1806 wl1271_configure_filters(wl, 0);
1807
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001808 /* apply configured filters */
1809 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1810 if (ret < 0)
1811 goto out_sleep;
1812
1813out_sleep:
1814 wl1271_ps_elp_sleep(wl);
1815
1816out:
1817 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001818 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819}
1820
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001821static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1822 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1823 u16 tx_seq_16)
1824{
1825 struct wl1271_ap_key *ap_key;
1826 int i;
1827
1828 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1829
1830 if (key_size > MAX_KEY_SIZE)
1831 return -EINVAL;
1832
1833 /*
1834 * Find next free entry in ap_keys. Also check we are not replacing
1835 * an existing key.
1836 */
1837 for (i = 0; i < MAX_NUM_KEYS; i++) {
1838 if (wl->recorded_ap_keys[i] == NULL)
1839 break;
1840
1841 if (wl->recorded_ap_keys[i]->id == id) {
1842 wl1271_warning("trying to record key replacement");
1843 return -EINVAL;
1844 }
1845 }
1846
1847 if (i == MAX_NUM_KEYS)
1848 return -EBUSY;
1849
1850 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1851 if (!ap_key)
1852 return -ENOMEM;
1853
1854 ap_key->id = id;
1855 ap_key->key_type = key_type;
1856 ap_key->key_size = key_size;
1857 memcpy(ap_key->key, key, key_size);
1858 ap_key->hlid = hlid;
1859 ap_key->tx_seq_32 = tx_seq_32;
1860 ap_key->tx_seq_16 = tx_seq_16;
1861
1862 wl->recorded_ap_keys[i] = ap_key;
1863 return 0;
1864}
1865
1866static void wl1271_free_ap_keys(struct wl1271 *wl)
1867{
1868 int i;
1869
1870 for (i = 0; i < MAX_NUM_KEYS; i++) {
1871 kfree(wl->recorded_ap_keys[i]);
1872 wl->recorded_ap_keys[i] = NULL;
1873 }
1874}
1875
1876static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1877{
1878 int i, ret = 0;
1879 struct wl1271_ap_key *key;
1880 bool wep_key_added = false;
1881
1882 for (i = 0; i < MAX_NUM_KEYS; i++) {
1883 if (wl->recorded_ap_keys[i] == NULL)
1884 break;
1885
1886 key = wl->recorded_ap_keys[i];
1887 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1888 key->id, key->key_type,
1889 key->key_size, key->key,
1890 key->hlid, key->tx_seq_32,
1891 key->tx_seq_16);
1892 if (ret < 0)
1893 goto out;
1894
1895 if (key->key_type == KEY_WEP)
1896 wep_key_added = true;
1897 }
1898
1899 if (wep_key_added) {
1900 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1901 if (ret < 0)
1902 goto out;
1903 }
1904
1905out:
1906 wl1271_free_ap_keys(wl);
1907 return ret;
1908}
1909
1910static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1911 u8 key_size, const u8 *key, u32 tx_seq_32,
1912 u16 tx_seq_16, struct ieee80211_sta *sta)
1913{
1914 int ret;
1915 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1916
1917 if (is_ap) {
1918 struct wl1271_station *wl_sta;
1919 u8 hlid;
1920
1921 if (sta) {
1922 wl_sta = (struct wl1271_station *)sta->drv_priv;
1923 hlid = wl_sta->hlid;
1924 } else {
1925 hlid = WL1271_AP_BROADCAST_HLID;
1926 }
1927
1928 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1929 /*
1930 * We do not support removing keys after AP shutdown.
1931 * Pretend we do to make mac80211 happy.
1932 */
1933 if (action != KEY_ADD_OR_REPLACE)
1934 return 0;
1935
1936 ret = wl1271_record_ap_key(wl, id,
1937 key_type, key_size,
1938 key, hlid, tx_seq_32,
1939 tx_seq_16);
1940 } else {
1941 ret = wl1271_cmd_set_ap_key(wl, action,
1942 id, key_type, key_size,
1943 key, hlid, tx_seq_32,
1944 tx_seq_16);
1945 }
1946
1947 if (ret < 0)
1948 return ret;
1949 } else {
1950 const u8 *addr;
1951 static const u8 bcast_addr[ETH_ALEN] = {
1952 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1953 };
1954
1955 addr = sta ? sta->addr : bcast_addr;
1956
1957 if (is_zero_ether_addr(addr)) {
1958 /* We dont support TX only encryption */
1959 return -EOPNOTSUPP;
1960 }
1961
1962 /* The wl1271 does not allow to remove unicast keys - they
1963 will be cleared automatically on next CMD_JOIN. Ignore the
1964 request silently, as we dont want the mac80211 to emit
1965 an error message. */
1966 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1967 return 0;
1968
1969 ret = wl1271_cmd_set_sta_key(wl, action,
1970 id, key_type, key_size,
1971 key, addr, tx_seq_32,
1972 tx_seq_16);
1973 if (ret < 0)
1974 return ret;
1975
1976 /* the default WEP key needs to be configured at least once */
1977 if (key_type == KEY_WEP) {
1978 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1979 wl->default_key);
1980 if (ret < 0)
1981 return ret;
1982 }
1983 }
1984
1985 return 0;
1986}
1987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1989 struct ieee80211_vif *vif,
1990 struct ieee80211_sta *sta,
1991 struct ieee80211_key_conf *key_conf)
1992{
1993 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001995 u32 tx_seq_32 = 0;
1996 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 u8 key_type;
1998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2000
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002001 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002002 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002003 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 key_conf->keylen, key_conf->flags);
2005 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002007 mutex_lock(&wl->mutex);
2008
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002009 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2010 ret = -EAGAIN;
2011 goto out_unlock;
2012 }
2013
Ido Yariva6208652011-03-01 15:14:41 +02002014 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015 if (ret < 0)
2016 goto out_unlock;
2017
Johannes Berg97359d12010-08-10 09:46:38 +02002018 switch (key_conf->cipher) {
2019 case WLAN_CIPHER_SUITE_WEP40:
2020 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021 key_type = KEY_WEP;
2022
2023 key_conf->hw_key_idx = key_conf->keyidx;
2024 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002025 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026 key_type = KEY_TKIP;
2027
2028 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002029 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2030 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002032 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 key_type = KEY_AES;
2034
2035 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002036 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2037 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002039 case WL1271_CIPHER_SUITE_GEM:
2040 key_type = KEY_GEM;
2041 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2042 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2043 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002045 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046
2047 ret = -EOPNOTSUPP;
2048 goto out_sleep;
2049 }
2050
2051 switch (cmd) {
2052 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002053 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2054 key_conf->keyidx, key_type,
2055 key_conf->keylen, key_conf->key,
2056 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 if (ret < 0) {
2058 wl1271_error("Could not add or replace key");
2059 goto out_sleep;
2060 }
2061 break;
2062
2063 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002064 ret = wl1271_set_key(wl, KEY_REMOVE,
2065 key_conf->keyidx, key_type,
2066 key_conf->keylen, key_conf->key,
2067 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068 if (ret < 0) {
2069 wl1271_error("Could not remove key");
2070 goto out_sleep;
2071 }
2072 break;
2073
2074 default:
2075 wl1271_error("Unsupported key cmd 0x%x", cmd);
2076 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077 break;
2078 }
2079
2080out_sleep:
2081 wl1271_ps_elp_sleep(wl);
2082
2083out_unlock:
2084 mutex_unlock(&wl->mutex);
2085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086 return ret;
2087}
2088
2089static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002090 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091 struct cfg80211_scan_request *req)
2092{
2093 struct wl1271 *wl = hw->priv;
2094 int ret;
2095 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002096 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002097
2098 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2099
2100 if (req->n_ssids) {
2101 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002102 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103 }
2104
2105 mutex_lock(&wl->mutex);
2106
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002107 if (wl->state == WL1271_STATE_OFF) {
2108 /*
2109 * We cannot return -EBUSY here because cfg80211 will expect
2110 * a call to ieee80211_scan_completed if we do - in this case
2111 * there won't be any call.
2112 */
2113 ret = -EAGAIN;
2114 goto out;
2115 }
2116
Ido Yariva6208652011-03-01 15:14:41 +02002117 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002118 if (ret < 0)
2119 goto out;
2120
Luciano Coelho5924f892010-08-04 03:46:22 +03002121 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122
2123 wl1271_ps_elp_sleep(wl);
2124
2125out:
2126 mutex_unlock(&wl->mutex);
2127
2128 return ret;
2129}
2130
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002131static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2132{
2133 struct wl1271 *wl = hw->priv;
2134 int ret = 0;
2135
2136 mutex_lock(&wl->mutex);
2137
2138 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2139 ret = -EAGAIN;
2140 goto out;
2141 }
2142
Ido Yariva6208652011-03-01 15:14:41 +02002143 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002144 if (ret < 0)
2145 goto out;
2146
2147 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2148 if (ret < 0)
2149 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2150
2151 wl1271_ps_elp_sleep(wl);
2152
2153out:
2154 mutex_unlock(&wl->mutex);
2155
2156 return ret;
2157}
2158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2160{
2161 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002162 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163
2164 mutex_lock(&wl->mutex);
2165
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002166 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2167 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002168 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002169 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002170
Ido Yariva6208652011-03-01 15:14:41 +02002171 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 if (ret < 0)
2173 goto out;
2174
2175 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2176 if (ret < 0)
2177 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2178
2179 wl1271_ps_elp_sleep(wl);
2180
2181out:
2182 mutex_unlock(&wl->mutex);
2183
2184 return ret;
2185}
2186
Arik Nemtsove78a2872010-10-16 19:07:21 +02002187static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002188 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002189{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002190 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002191
2192 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002193 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002194 if (ptr[0] == WLAN_EID_SSID) {
2195 wl->ssid_len = ptr[1];
2196 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002197 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002198 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002199 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002200 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002201
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002202 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002203 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002204}
2205
Arik Nemtsove78a2872010-10-16 19:07:21 +02002206static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2207 struct ieee80211_bss_conf *bss_conf,
2208 u32 changed)
2209{
2210 int ret = 0;
2211
2212 if (changed & BSS_CHANGED_ERP_SLOT) {
2213 if (bss_conf->use_short_slot)
2214 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2215 else
2216 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2217 if (ret < 0) {
2218 wl1271_warning("Set slot time failed %d", ret);
2219 goto out;
2220 }
2221 }
2222
2223 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2224 if (bss_conf->use_short_preamble)
2225 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2226 else
2227 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2228 }
2229
2230 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2231 if (bss_conf->use_cts_prot)
2232 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2233 else
2234 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2235 if (ret < 0) {
2236 wl1271_warning("Set ctsprotect failed %d", ret);
2237 goto out;
2238 }
2239 }
2240
2241out:
2242 return ret;
2243}
2244
2245static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2246 struct ieee80211_vif *vif,
2247 struct ieee80211_bss_conf *bss_conf,
2248 u32 changed)
2249{
2250 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2251 int ret = 0;
2252
2253 if ((changed & BSS_CHANGED_BEACON_INT)) {
2254 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2255 bss_conf->beacon_int);
2256
2257 wl->beacon_int = bss_conf->beacon_int;
2258 }
2259
2260 if ((changed & BSS_CHANGED_BEACON)) {
2261 struct ieee80211_hdr *hdr;
2262 int ieoffset = offsetof(struct ieee80211_mgmt,
2263 u.beacon.variable);
2264 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2265 u16 tmpl_id;
2266
2267 if (!beacon)
2268 goto out;
2269
2270 wl1271_debug(DEBUG_MASTER, "beacon updated");
2271
2272 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2273 if (ret < 0) {
2274 dev_kfree_skb(beacon);
2275 goto out;
2276 }
2277 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2278 CMD_TEMPL_BEACON;
2279 ret = wl1271_cmd_template_set(wl, tmpl_id,
2280 beacon->data,
2281 beacon->len, 0,
2282 wl1271_tx_min_rate_get(wl));
2283 if (ret < 0) {
2284 dev_kfree_skb(beacon);
2285 goto out;
2286 }
2287
2288 hdr = (struct ieee80211_hdr *) beacon->data;
2289 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2290 IEEE80211_STYPE_PROBE_RESP);
2291
2292 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2293 CMD_TEMPL_PROBE_RESPONSE;
2294 ret = wl1271_cmd_template_set(wl,
2295 tmpl_id,
2296 beacon->data,
2297 beacon->len, 0,
2298 wl1271_tx_min_rate_get(wl));
2299 dev_kfree_skb(beacon);
2300 if (ret < 0)
2301 goto out;
2302 }
2303
2304out:
2305 return ret;
2306}
2307
2308/* AP mode changes */
2309static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002310 struct ieee80211_vif *vif,
2311 struct ieee80211_bss_conf *bss_conf,
2312 u32 changed)
2313{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002314 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002315
Arik Nemtsove78a2872010-10-16 19:07:21 +02002316 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2317 u32 rates = bss_conf->basic_rates;
2318 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319
Arik Nemtsove78a2872010-10-16 19:07:21 +02002320 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2321 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2322 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2323 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324
Arik Nemtsove78a2872010-10-16 19:07:21 +02002325 /* update the AP management rate policy with the new rates */
2326 mgmt_rc.enabled_rates = wl->basic_rate_set;
2327 mgmt_rc.long_retry_limit = 10;
2328 mgmt_rc.short_retry_limit = 10;
2329 mgmt_rc.aflags = 0;
2330 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2331 ACX_TX_AP_MODE_MGMT_RATE);
2332 if (ret < 0) {
2333 wl1271_error("AP mgmt policy change failed %d", ret);
2334 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002335 }
2336 }
2337
Arik Nemtsove78a2872010-10-16 19:07:21 +02002338 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2339 if (ret < 0)
2340 goto out;
2341
2342 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2343 if (bss_conf->enable_beacon) {
2344 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2345 ret = wl1271_cmd_start_bss(wl);
2346 if (ret < 0)
2347 goto out;
2348
2349 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2350 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002351
2352 ret = wl1271_ap_init_hwenc(wl);
2353 if (ret < 0)
2354 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002355 }
2356 } else {
2357 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2358 ret = wl1271_cmd_stop_bss(wl);
2359 if (ret < 0)
2360 goto out;
2361
2362 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2363 wl1271_debug(DEBUG_AP, "stopped AP");
2364 }
2365 }
2366 }
2367
2368 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2369 if (ret < 0)
2370 goto out;
2371out:
2372 return;
2373}
2374
2375/* STA/IBSS mode changes */
2376static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2377 struct ieee80211_vif *vif,
2378 struct ieee80211_bss_conf *bss_conf,
2379 u32 changed)
2380{
2381 bool do_join = false, set_assoc = false;
2382 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002383 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002384 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002385 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002386 bool sta_exists = false;
2387 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002388
2389 if (is_ibss) {
2390 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2391 changed);
2392 if (ret < 0)
2393 goto out;
2394 }
2395
2396 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2397 do_join = true;
2398
2399 /* Need to update the SSID (for filtering etc) */
2400 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2401 do_join = true;
2402
2403 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002404 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2405 bss_conf->enable_beacon ? "enabled" : "disabled");
2406
2407 if (bss_conf->enable_beacon)
2408 wl->set_bss_type = BSS_TYPE_IBSS;
2409 else
2410 wl->set_bss_type = BSS_TYPE_STA_BSS;
2411 do_join = true;
2412 }
2413
Arik Nemtsove78a2872010-10-16 19:07:21 +02002414 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002415 bool enable = false;
2416 if (bss_conf->cqm_rssi_thold)
2417 enable = true;
2418 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2419 bss_conf->cqm_rssi_thold,
2420 bss_conf->cqm_rssi_hyst);
2421 if (ret < 0)
2422 goto out;
2423 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2424 }
2425
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002426 if ((changed & BSS_CHANGED_BSSID) &&
2427 /*
2428 * Now we know the correct bssid, so we send a new join command
2429 * and enable the BSSID filter
2430 */
2431 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002432 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002433
Eliad Pellerfa287b82010-12-26 09:27:50 +01002434 if (!is_zero_ether_addr(wl->bssid)) {
2435 ret = wl1271_cmd_build_null_data(wl);
2436 if (ret < 0)
2437 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002438
Eliad Pellerfa287b82010-12-26 09:27:50 +01002439 ret = wl1271_build_qos_null_data(wl);
2440 if (ret < 0)
2441 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002442
Eliad Pellerfa287b82010-12-26 09:27:50 +01002443 /* filter out all packets not from this BSSID */
2444 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002445
Eliad Pellerfa287b82010-12-26 09:27:50 +01002446 /* Need to update the BSSID (for filtering etc) */
2447 do_join = true;
2448 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002449 }
2450
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002451 rcu_read_lock();
2452 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2453 if (sta) {
2454 /* save the supp_rates of the ap */
2455 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2456 if (sta->ht_cap.ht_supported)
2457 sta_rate_set |=
2458 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002459 sta_ht_cap = sta->ht_cap;
2460 sta_exists = true;
2461 }
2462 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002463
Arik Nemtsova1008852011-02-12 23:24:20 +02002464 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002465 /* handle new association with HT and HT information change */
2466 if ((changed & BSS_CHANGED_HT) &&
2467 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002468 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002469 true);
2470 if (ret < 0) {
2471 wl1271_warning("Set ht cap true failed %d",
2472 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002473 goto out;
2474 }
2475 ret = wl1271_acx_set_ht_information(wl,
2476 bss_conf->ht_operation_mode);
2477 if (ret < 0) {
2478 wl1271_warning("Set ht information failed %d",
2479 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002480 goto out;
2481 }
2482 }
2483 /* handle new association without HT and disassociation */
2484 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002485 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002486 false);
2487 if (ret < 0) {
2488 wl1271_warning("Set ht cap false failed %d",
2489 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002490 goto out;
2491 }
2492 }
2493 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002494
Arik Nemtsove78a2872010-10-16 19:07:21 +02002495 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002497 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002498 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002499 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002500 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002501
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002502 wl->ps_poll_failures = 0;
2503
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002504 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002505 * use basic rates from AP, and determine lowest rate
2506 * to use with control frames.
2507 */
2508 rates = bss_conf->basic_rates;
2509 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2510 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002511 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002512 if (sta_rate_set)
2513 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2514 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002515 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002516 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002517 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002518
2519 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002520 * with wl1271, we don't need to update the
2521 * beacon_int and dtim_period, because the firmware
2522 * updates it by itself when the first beacon is
2523 * received after a join.
2524 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2526 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002527 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002528
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002529 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002530 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002531 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002532 dev_kfree_skb(wl->probereq);
2533 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2534 ieoffset = offsetof(struct ieee80211_mgmt,
2535 u.probe_req.variable);
2536 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002537
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002538 /* enable the connection monitoring feature */
2539 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002541 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002542
2543 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002544 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2545 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002546 enum wl1271_cmd_ps_mode mode;
2547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002548 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002549 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002550 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002551 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002553 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002555 } else {
2556 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002557 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002558 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002559 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002560
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002561 /* free probe-request template */
2562 dev_kfree_skb(wl->probereq);
2563 wl->probereq = NULL;
2564
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002565 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002566 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002567
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002568 /* revert back to minimum rates for the current band */
2569 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002570 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002571 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002572 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002573 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002574
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002575 /* disable connection monitor features */
2576 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002577
2578 /* Disable the keep-alive feature */
2579 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002580 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002581 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002582
2583 /* restore the bssid filter and go to dummy bssid */
2584 wl1271_unjoin(wl);
2585 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 }
2587 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002588
Arik Nemtsove78a2872010-10-16 19:07:21 +02002589 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2590 if (ret < 0)
2591 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002593 if (changed & BSS_CHANGED_ARP_FILTER) {
2594 __be32 addr = bss_conf->arp_addr_list[0];
2595 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2596
Eliad Pellerc5312772010-12-09 11:31:27 +02002597 if (bss_conf->arp_addr_cnt == 1 &&
2598 bss_conf->arp_filter_enabled) {
2599 /*
2600 * The template should have been configured only upon
2601 * association. however, it seems that the correct ip
2602 * isn't being set (when sending), so we have to
2603 * reconfigure the template upon every ip change.
2604 */
2605 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2606 if (ret < 0) {
2607 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002608 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002609 }
2610
2611 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002612 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002613 addr);
2614 } else
2615 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002616
2617 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002618 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002619 }
2620
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002621 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002622 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002623 if (ret < 0) {
2624 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002625 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002626 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002627 }
2628
Arik Nemtsove78a2872010-10-16 19:07:21 +02002629out:
2630 return;
2631}
2632
2633static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2634 struct ieee80211_vif *vif,
2635 struct ieee80211_bss_conf *bss_conf,
2636 u32 changed)
2637{
2638 struct wl1271 *wl = hw->priv;
2639 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2640 int ret;
2641
2642 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2643 (int)changed);
2644
2645 mutex_lock(&wl->mutex);
2646
2647 if (unlikely(wl->state == WL1271_STATE_OFF))
2648 goto out;
2649
Ido Yariva6208652011-03-01 15:14:41 +02002650 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002651 if (ret < 0)
2652 goto out;
2653
2654 if (is_ap)
2655 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2656 else
2657 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659 wl1271_ps_elp_sleep(wl);
2660
2661out:
2662 mutex_unlock(&wl->mutex);
2663}
2664
Kalle Valoc6999d82010-02-18 13:25:41 +02002665static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2666 const struct ieee80211_tx_queue_params *params)
2667{
2668 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002669 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002670 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002671
2672 mutex_lock(&wl->mutex);
2673
2674 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2675
Kalle Valo4695dc92010-03-18 12:26:38 +02002676 if (params->uapsd)
2677 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2678 else
2679 ps_scheme = CONF_PS_SCHEME_LEGACY;
2680
Arik Nemtsov488fc542010-10-16 20:33:45 +02002681 if (wl->state == WL1271_STATE_OFF) {
2682 /*
2683 * If the state is off, the parameters will be recorded and
2684 * configured on init. This happens in AP-mode.
2685 */
2686 struct conf_tx_ac_category *conf_ac =
2687 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2688 struct conf_tx_tid *conf_tid =
2689 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2690
2691 conf_ac->ac = wl1271_tx_get_queue(queue);
2692 conf_ac->cw_min = (u8)params->cw_min;
2693 conf_ac->cw_max = params->cw_max;
2694 conf_ac->aifsn = params->aifs;
2695 conf_ac->tx_op_limit = params->txop << 5;
2696
2697 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2698 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2699 conf_tid->tsid = wl1271_tx_get_queue(queue);
2700 conf_tid->ps_scheme = ps_scheme;
2701 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2702 conf_tid->apsd_conf[0] = 0;
2703 conf_tid->apsd_conf[1] = 0;
2704 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002705 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002706 if (ret < 0)
2707 goto out;
2708
2709 /*
2710 * the txop is confed in units of 32us by the mac80211,
2711 * we need us
2712 */
2713 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2714 params->cw_min, params->cw_max,
2715 params->aifs, params->txop << 5);
2716 if (ret < 0)
2717 goto out_sleep;
2718
2719 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2720 CONF_CHANNEL_TYPE_EDCF,
2721 wl1271_tx_get_queue(queue),
2722 ps_scheme, CONF_ACK_POLICY_LEGACY,
2723 0, 0);
2724 if (ret < 0)
2725 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002726
2727out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002728 wl1271_ps_elp_sleep(wl);
2729 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002730
2731out:
2732 mutex_unlock(&wl->mutex);
2733
2734 return ret;
2735}
2736
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002737static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2738{
2739
2740 struct wl1271 *wl = hw->priv;
2741 u64 mactime = ULLONG_MAX;
2742 int ret;
2743
2744 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2745
2746 mutex_lock(&wl->mutex);
2747
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002748 if (unlikely(wl->state == WL1271_STATE_OFF))
2749 goto out;
2750
Ido Yariva6208652011-03-01 15:14:41 +02002751 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002752 if (ret < 0)
2753 goto out;
2754
2755 ret = wl1271_acx_tsf_info(wl, &mactime);
2756 if (ret < 0)
2757 goto out_sleep;
2758
2759out_sleep:
2760 wl1271_ps_elp_sleep(wl);
2761
2762out:
2763 mutex_unlock(&wl->mutex);
2764 return mactime;
2765}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766
John W. Linvilleece550d2010-07-28 16:41:06 -04002767static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2768 struct survey_info *survey)
2769{
2770 struct wl1271 *wl = hw->priv;
2771 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002772
John W. Linvilleece550d2010-07-28 16:41:06 -04002773 if (idx != 0)
2774 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002775
John W. Linvilleece550d2010-07-28 16:41:06 -04002776 survey->channel = conf->channel;
2777 survey->filled = SURVEY_INFO_NOISE_DBM;
2778 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002779
John W. Linvilleece550d2010-07-28 16:41:06 -04002780 return 0;
2781}
2782
Arik Nemtsov409622e2011-02-23 00:22:29 +02002783static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002784 struct ieee80211_sta *sta,
2785 u8 *hlid)
2786{
2787 struct wl1271_station *wl_sta;
2788 int id;
2789
2790 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2791 if (id >= AP_MAX_STATIONS) {
2792 wl1271_warning("could not allocate HLID - too much stations");
2793 return -EBUSY;
2794 }
2795
2796 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002797 __set_bit(id, wl->ap_hlid_map);
2798 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2799 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002800 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002801 return 0;
2802}
2803
Arik Nemtsov409622e2011-02-23 00:22:29 +02002804static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002805{
2806 int id = hlid - WL1271_AP_STA_HLID_START;
2807
Arik Nemtsov409622e2011-02-23 00:22:29 +02002808 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2809 return;
2810
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002811 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002812 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002813 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002814 __clear_bit(hlid, &wl->ap_ps_map);
2815 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002816}
2817
2818static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2819 struct ieee80211_vif *vif,
2820 struct ieee80211_sta *sta)
2821{
2822 struct wl1271 *wl = hw->priv;
2823 int ret = 0;
2824 u8 hlid;
2825
2826 mutex_lock(&wl->mutex);
2827
2828 if (unlikely(wl->state == WL1271_STATE_OFF))
2829 goto out;
2830
2831 if (wl->bss_type != BSS_TYPE_AP_BSS)
2832 goto out;
2833
2834 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2835
Arik Nemtsov409622e2011-02-23 00:22:29 +02002836 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002837 if (ret < 0)
2838 goto out;
2839
Ido Yariva6208652011-03-01 15:14:41 +02002840 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002841 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002842 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002843
2844 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2845 if (ret < 0)
2846 goto out_sleep;
2847
2848out_sleep:
2849 wl1271_ps_elp_sleep(wl);
2850
Arik Nemtsov409622e2011-02-23 00:22:29 +02002851out_free_sta:
2852 if (ret < 0)
2853 wl1271_free_sta(wl, hlid);
2854
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002855out:
2856 mutex_unlock(&wl->mutex);
2857 return ret;
2858}
2859
2860static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2861 struct ieee80211_vif *vif,
2862 struct ieee80211_sta *sta)
2863{
2864 struct wl1271 *wl = hw->priv;
2865 struct wl1271_station *wl_sta;
2866 int ret = 0, id;
2867
2868 mutex_lock(&wl->mutex);
2869
2870 if (unlikely(wl->state == WL1271_STATE_OFF))
2871 goto out;
2872
2873 if (wl->bss_type != BSS_TYPE_AP_BSS)
2874 goto out;
2875
2876 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2877
2878 wl_sta = (struct wl1271_station *)sta->drv_priv;
2879 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2880 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2881 goto out;
2882
Ido Yariva6208652011-03-01 15:14:41 +02002883 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002884 if (ret < 0)
2885 goto out;
2886
2887 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2888 if (ret < 0)
2889 goto out_sleep;
2890
Arik Nemtsov409622e2011-02-23 00:22:29 +02002891 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002892
2893out_sleep:
2894 wl1271_ps_elp_sleep(wl);
2895
2896out:
2897 mutex_unlock(&wl->mutex);
2898 return ret;
2899}
2900
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002901int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002902 enum ieee80211_ampdu_mlme_action action,
2903 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2904 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002905{
2906 struct wl1271 *wl = hw->priv;
2907 int ret;
2908
2909 mutex_lock(&wl->mutex);
2910
2911 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2912 ret = -EAGAIN;
2913 goto out;
2914 }
2915
Ido Yariva6208652011-03-01 15:14:41 +02002916 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002917 if (ret < 0)
2918 goto out;
2919
2920 switch (action) {
2921 case IEEE80211_AMPDU_RX_START:
2922 if (wl->ba_support) {
2923 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2924 true);
2925 if (!ret)
2926 wl->ba_rx_bitmap |= BIT(tid);
2927 } else {
2928 ret = -ENOTSUPP;
2929 }
2930 break;
2931
2932 case IEEE80211_AMPDU_RX_STOP:
2933 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2934 if (!ret)
2935 wl->ba_rx_bitmap &= ~BIT(tid);
2936 break;
2937
2938 /*
2939 * The BA initiator session management in FW independently.
2940 * Falling break here on purpose for all TX APDU commands.
2941 */
2942 case IEEE80211_AMPDU_TX_START:
2943 case IEEE80211_AMPDU_TX_STOP:
2944 case IEEE80211_AMPDU_TX_OPERATIONAL:
2945 ret = -EINVAL;
2946 break;
2947
2948 default:
2949 wl1271_error("Incorrect ampdu action id=%x\n", action);
2950 ret = -EINVAL;
2951 }
2952
2953 wl1271_ps_elp_sleep(wl);
2954
2955out:
2956 mutex_unlock(&wl->mutex);
2957
2958 return ret;
2959}
2960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961/* can't be const, mac80211 writes to this */
2962static struct ieee80211_rate wl1271_rates[] = {
2963 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002964 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2965 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002967 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2968 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2970 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002971 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2972 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2974 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002975 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2976 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002977 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2978 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002979 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2980 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002982 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2983 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002985 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2986 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002988 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2989 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002991 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2992 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002993 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002994 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2995 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002997 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2998 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002999 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003000 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3001 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002};
3003
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003004/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003005static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003006 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003007 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003008 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3009 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3010 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003011 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003012 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3013 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3014 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003015 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003016 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3017 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3018 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003019 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003020};
3021
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003022/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003023static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003024 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003025 7, /* CONF_HW_RXTX_RATE_MCS7 */
3026 6, /* CONF_HW_RXTX_RATE_MCS6 */
3027 5, /* CONF_HW_RXTX_RATE_MCS5 */
3028 4, /* CONF_HW_RXTX_RATE_MCS4 */
3029 3, /* CONF_HW_RXTX_RATE_MCS3 */
3030 2, /* CONF_HW_RXTX_RATE_MCS2 */
3031 1, /* CONF_HW_RXTX_RATE_MCS1 */
3032 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003033
3034 11, /* CONF_HW_RXTX_RATE_54 */
3035 10, /* CONF_HW_RXTX_RATE_48 */
3036 9, /* CONF_HW_RXTX_RATE_36 */
3037 8, /* CONF_HW_RXTX_RATE_24 */
3038
3039 /* TI-specific rate */
3040 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3041
3042 7, /* CONF_HW_RXTX_RATE_18 */
3043 6, /* CONF_HW_RXTX_RATE_12 */
3044 3, /* CONF_HW_RXTX_RATE_11 */
3045 5, /* CONF_HW_RXTX_RATE_9 */
3046 4, /* CONF_HW_RXTX_RATE_6 */
3047 2, /* CONF_HW_RXTX_RATE_5_5 */
3048 1, /* CONF_HW_RXTX_RATE_2 */
3049 0 /* CONF_HW_RXTX_RATE_1 */
3050};
3051
Shahar Levie8b03a22010-10-13 16:09:39 +02003052/* 11n STA capabilities */
3053#define HW_RX_HIGHEST_RATE 72
3054
Shahar Levi00d20102010-11-08 11:20:10 +00003055#ifdef CONFIG_WL12XX_HT
3056#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003057 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3058 .ht_supported = true, \
3059 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3060 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3061 .mcs = { \
3062 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3063 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3064 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3065 }, \
3066}
Shahar Levi18357852010-10-13 16:09:41 +02003067#else
Shahar Levi00d20102010-11-08 11:20:10 +00003068#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003069 .ht_supported = false, \
3070}
3071#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073/* can't be const, mac80211 writes to this */
3074static struct ieee80211_supported_band wl1271_band_2ghz = {
3075 .channels = wl1271_channels,
3076 .n_channels = ARRAY_SIZE(wl1271_channels),
3077 .bitrates = wl1271_rates,
3078 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003079 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080};
3081
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003082/* 5 GHz data rates for WL1273 */
3083static struct ieee80211_rate wl1271_rates_5ghz[] = {
3084 { .bitrate = 60,
3085 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3086 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3087 { .bitrate = 90,
3088 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3089 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3090 { .bitrate = 120,
3091 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3092 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3093 { .bitrate = 180,
3094 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3095 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3096 { .bitrate = 240,
3097 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3098 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3099 { .bitrate = 360,
3100 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3101 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3102 { .bitrate = 480,
3103 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3104 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3105 { .bitrate = 540,
3106 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3107 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3108};
3109
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003110/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003111static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003112 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003113 { .hw_value = 8, .center_freq = 5040},
3114 { .hw_value = 9, .center_freq = 5045},
3115 { .hw_value = 11, .center_freq = 5055},
3116 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003117 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003118 { .hw_value = 34, .center_freq = 5170},
3119 { .hw_value = 36, .center_freq = 5180},
3120 { .hw_value = 38, .center_freq = 5190},
3121 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003122 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003123 { .hw_value = 44, .center_freq = 5220},
3124 { .hw_value = 46, .center_freq = 5230},
3125 { .hw_value = 48, .center_freq = 5240},
3126 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003127 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003128 { .hw_value = 60, .center_freq = 5300},
3129 { .hw_value = 64, .center_freq = 5320},
3130 { .hw_value = 100, .center_freq = 5500},
3131 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003132 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003133 { .hw_value = 112, .center_freq = 5560},
3134 { .hw_value = 116, .center_freq = 5580},
3135 { .hw_value = 120, .center_freq = 5600},
3136 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003137 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003138 { .hw_value = 132, .center_freq = 5660},
3139 { .hw_value = 136, .center_freq = 5680},
3140 { .hw_value = 140, .center_freq = 5700},
3141 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003142 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003143 { .hw_value = 157, .center_freq = 5785},
3144 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003145 { .hw_value = 165, .center_freq = 5825},
3146};
3147
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003148/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003149static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003150 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003151 7, /* CONF_HW_RXTX_RATE_MCS7 */
3152 6, /* CONF_HW_RXTX_RATE_MCS6 */
3153 5, /* CONF_HW_RXTX_RATE_MCS5 */
3154 4, /* CONF_HW_RXTX_RATE_MCS4 */
3155 3, /* CONF_HW_RXTX_RATE_MCS3 */
3156 2, /* CONF_HW_RXTX_RATE_MCS2 */
3157 1, /* CONF_HW_RXTX_RATE_MCS1 */
3158 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003159
3160 7, /* CONF_HW_RXTX_RATE_54 */
3161 6, /* CONF_HW_RXTX_RATE_48 */
3162 5, /* CONF_HW_RXTX_RATE_36 */
3163 4, /* CONF_HW_RXTX_RATE_24 */
3164
3165 /* TI-specific rate */
3166 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3167
3168 3, /* CONF_HW_RXTX_RATE_18 */
3169 2, /* CONF_HW_RXTX_RATE_12 */
3170 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3171 1, /* CONF_HW_RXTX_RATE_9 */
3172 0, /* CONF_HW_RXTX_RATE_6 */
3173 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3174 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3175 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3176};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003177
3178static struct ieee80211_supported_band wl1271_band_5ghz = {
3179 .channels = wl1271_channels_5ghz,
3180 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3181 .bitrates = wl1271_rates_5ghz,
3182 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003183 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003184};
3185
Tobias Klausera0ea9492010-05-20 10:38:11 +02003186static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003187 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3188 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3189};
3190
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003191static const struct ieee80211_ops wl1271_ops = {
3192 .start = wl1271_op_start,
3193 .stop = wl1271_op_stop,
3194 .add_interface = wl1271_op_add_interface,
3195 .remove_interface = wl1271_op_remove_interface,
3196 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003197 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198 .configure_filter = wl1271_op_configure_filter,
3199 .tx = wl1271_op_tx,
3200 .set_key = wl1271_op_set_key,
3201 .hw_scan = wl1271_op_hw_scan,
3202 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003204 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003205 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003206 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003207 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003208 .sta_add = wl1271_op_sta_add,
3209 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003210 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003211 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212};
3213
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003214
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003215u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003216{
3217 u8 idx;
3218
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003219 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003220
3221 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3222 wl1271_error("Illegal RX rate from HW: %d", rate);
3223 return 0;
3224 }
3225
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003226 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003227 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3228 wl1271_error("Unsupported RX rate from HW: %d", rate);
3229 return 0;
3230 }
3231
3232 return idx;
3233}
3234
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003235static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3236 struct device_attribute *attr,
3237 char *buf)
3238{
3239 struct wl1271 *wl = dev_get_drvdata(dev);
3240 ssize_t len;
3241
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003242 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003243
3244 mutex_lock(&wl->mutex);
3245 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3246 wl->sg_enabled);
3247 mutex_unlock(&wl->mutex);
3248
3249 return len;
3250
3251}
3252
3253static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3254 struct device_attribute *attr,
3255 const char *buf, size_t count)
3256{
3257 struct wl1271 *wl = dev_get_drvdata(dev);
3258 unsigned long res;
3259 int ret;
3260
3261 ret = strict_strtoul(buf, 10, &res);
3262
3263 if (ret < 0) {
3264 wl1271_warning("incorrect value written to bt_coex_mode");
3265 return count;
3266 }
3267
3268 mutex_lock(&wl->mutex);
3269
3270 res = !!res;
3271
3272 if (res == wl->sg_enabled)
3273 goto out;
3274
3275 wl->sg_enabled = res;
3276
3277 if (wl->state == WL1271_STATE_OFF)
3278 goto out;
3279
Ido Yariva6208652011-03-01 15:14:41 +02003280 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003281 if (ret < 0)
3282 goto out;
3283
3284 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3285 wl1271_ps_elp_sleep(wl);
3286
3287 out:
3288 mutex_unlock(&wl->mutex);
3289 return count;
3290}
3291
3292static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3293 wl1271_sysfs_show_bt_coex_state,
3294 wl1271_sysfs_store_bt_coex_state);
3295
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003296static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3297 struct device_attribute *attr,
3298 char *buf)
3299{
3300 struct wl1271 *wl = dev_get_drvdata(dev);
3301 ssize_t len;
3302
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003303 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003304
3305 mutex_lock(&wl->mutex);
3306 if (wl->hw_pg_ver >= 0)
3307 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3308 else
3309 len = snprintf(buf, len, "n/a\n");
3310 mutex_unlock(&wl->mutex);
3311
3312 return len;
3313}
3314
3315static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3316 wl1271_sysfs_show_hw_pg_ver, NULL);
3317
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003318int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319{
3320 int ret;
3321
3322 if (wl->mac80211_registered)
3323 return 0;
3324
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003325 ret = wl1271_fetch_nvs(wl);
3326 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003327 /* NOTE: The wl->nvs->nvs element must be first, in
3328 * order to simplify the casting, we assume it is at
3329 * the beginning of the wl->nvs structure.
3330 */
3331 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003332
3333 wl->mac_addr[0] = nvs_ptr[11];
3334 wl->mac_addr[1] = nvs_ptr[10];
3335 wl->mac_addr[2] = nvs_ptr[6];
3336 wl->mac_addr[3] = nvs_ptr[5];
3337 wl->mac_addr[4] = nvs_ptr[4];
3338 wl->mac_addr[5] = nvs_ptr[3];
3339 }
3340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3342
3343 ret = ieee80211_register_hw(wl->hw);
3344 if (ret < 0) {
3345 wl1271_error("unable to register mac80211 hw: %d", ret);
3346 return ret;
3347 }
3348
3349 wl->mac80211_registered = true;
3350
Eliad Pellerd60080a2010-11-24 12:53:16 +02003351 wl1271_debugfs_init(wl);
3352
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003353 register_netdevice_notifier(&wl1271_dev_notifier);
3354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003355 wl1271_notice("loaded");
3356
3357 return 0;
3358}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003359EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003360
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003361void wl1271_unregister_hw(struct wl1271 *wl)
3362{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003363 if (wl->state == WL1271_STATE_PLT)
3364 __wl1271_plt_stop(wl);
3365
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003366 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003367 ieee80211_unregister_hw(wl->hw);
3368 wl->mac80211_registered = false;
3369
3370}
3371EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3372
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003373int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003374{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003375 static const u32 cipher_suites[] = {
3376 WLAN_CIPHER_SUITE_WEP40,
3377 WLAN_CIPHER_SUITE_WEP104,
3378 WLAN_CIPHER_SUITE_TKIP,
3379 WLAN_CIPHER_SUITE_CCMP,
3380 WL1271_CIPHER_SUITE_GEM,
3381 };
3382
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003383 /* The tx descriptor buffer and the TKIP space. */
3384 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3385 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003386
3387 /* unit us */
3388 /* FIXME: find a proper value */
3389 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003390 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003391
3392 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003393 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003394 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003395 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003396 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003397 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003398 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003399 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3400 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003401
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003402 wl->hw->wiphy->cipher_suites = cipher_suites;
3403 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3404
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003405 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003406 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003407 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003408 /*
3409 * Maximum length of elements in scanning probe request templates
3410 * should be the maximum length possible for a template, without
3411 * the IEEE80211 header of the template
3412 */
3413 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3414 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003415
3416 /*
3417 * We keep local copies of the band structs because we need to
3418 * modify them on a per-device basis.
3419 */
3420 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3421 sizeof(wl1271_band_2ghz));
3422 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3423 sizeof(wl1271_band_5ghz));
3424
3425 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3426 &wl->bands[IEEE80211_BAND_2GHZ];
3427 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3428 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003429
Kalle Valo12bd8942010-03-18 12:26:33 +02003430 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003431 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003432
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003433 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3434
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003435 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003436
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003437 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3438
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003439 wl->hw->max_rx_aggregation_subframes = 8;
3440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003441 return 0;
3442}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003443EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003445#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003446
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003447struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003448{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003450 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003451 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003452 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003453 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003454
3455 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3456 if (!hw) {
3457 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003458 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003459 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003460 }
3461
Julia Lawall929ebd32010-05-15 23:16:39 +02003462 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003463 if (!plat_dev) {
3464 wl1271_error("could not allocate platform_device");
3465 ret = -ENOMEM;
3466 goto err_plat_alloc;
3467 }
3468
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003469 wl = hw->priv;
3470 memset(wl, 0, sizeof(*wl));
3471
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003472 INIT_LIST_HEAD(&wl->list);
3473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003474 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003475 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003476
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003477 for (i = 0; i < NUM_TX_QUEUES; i++)
3478 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003479
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003480 for (i = 0; i < NUM_TX_QUEUES; i++)
3481 for (j = 0; j < AP_MAX_LINKS; j++)
3482 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3483
Ido Yariva6208652011-03-01 15:14:41 +02003484 skb_queue_head_init(&wl->deferred_rx_queue);
3485 skb_queue_head_init(&wl->deferred_tx_queue);
3486
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003487 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003488 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003489 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003490 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3491 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3492 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003494 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003496 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003497 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3498 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003499 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003500 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003501 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003502 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003503 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003504 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003505 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003506 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003507 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003508 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003509 wl->bss_type = MAX_BSS_TYPE;
3510 wl->set_bss_type = MAX_BSS_TYPE;
3511 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003512 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003513 wl->ap_ps_map = 0;
3514 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003515 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003516 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003517
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003518 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003519 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003520 wl->tx_frames[i] = NULL;
3521
3522 spin_lock_init(&wl->wl_lock);
3523
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003524 wl->state = WL1271_STATE_OFF;
3525 mutex_init(&wl->mutex);
3526
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003527 /* Apply default driver configuration. */
3528 wl1271_conf_init(wl);
3529
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003530 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3531 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3532 if (!wl->aggr_buf) {
3533 ret = -ENOMEM;
3534 goto err_hw;
3535 }
3536
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003537 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003538 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003539 if (ret) {
3540 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003541 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003542 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003543 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003544
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003545 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003546 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003547 if (ret < 0) {
3548 wl1271_error("failed to create sysfs file bt_coex_state");
3549 goto err_platform;
3550 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003551
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003552 /* Create sysfs file to get HW PG version */
3553 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3554 if (ret < 0) {
3555 wl1271_error("failed to create sysfs file hw_pg_ver");
3556 goto err_bt_coex_state;
3557 }
3558
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003559 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003560
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003561err_bt_coex_state:
3562 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3563
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003564err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003565 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003566
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003567err_aggr:
3568 free_pages((unsigned long)wl->aggr_buf, order);
3569
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003570err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003571 wl1271_debugfs_exit(wl);
3572 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003573
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003574err_plat_alloc:
3575 ieee80211_free_hw(hw);
3576
3577err_hw_alloc:
3578
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003579 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003580}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003581EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003582
3583int wl1271_free_hw(struct wl1271 *wl)
3584{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003585 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003586 free_pages((unsigned long)wl->aggr_buf,
3587 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003588 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003589
3590 wl1271_debugfs_exit(wl);
3591
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003592 vfree(wl->fw);
3593 wl->fw = NULL;
3594 kfree(wl->nvs);
3595 wl->nvs = NULL;
3596
3597 kfree(wl->fw_status);
3598 kfree(wl->tx_res_if);
3599
3600 ieee80211_free_hw(wl->hw);
3601
3602 return 0;
3603}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003604EXPORT_SYMBOL_GPL(wl1271_free_hw);
3605
Guy Eilam491bbd62011-01-12 10:33:29 +01003606u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003607EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003608module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003609MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3610
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003611MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003612MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003613MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");