blob: 61dea73f5fdc3f7f0c6902df3b87868322224e55 [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 },
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .mem = {
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,
307 .min_req_tx_blocks = 104,
308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
310 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311};
312
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200313static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200314static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200315
316
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200317static void wl1271_device_release(struct device *dev)
318{
319
320}
321
322static struct platform_device wl1271_device = {
323 .name = "wl1271",
324 .id = -1,
325
326 /* device model insists to have a release function */
327 .dev = {
328 .release = wl1271_device_release,
329 },
330};
331
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300332static LIST_HEAD(wl_list);
333
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300334static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
335 void *arg)
336{
337 struct net_device *dev = arg;
338 struct wireless_dev *wdev;
339 struct wiphy *wiphy;
340 struct ieee80211_hw *hw;
341 struct wl1271 *wl;
342 struct wl1271 *wl_temp;
343 int ret = 0;
344
345 /* Check that this notification is for us. */
346 if (what != NETDEV_CHANGE)
347 return NOTIFY_DONE;
348
349 wdev = dev->ieee80211_ptr;
350 if (wdev == NULL)
351 return NOTIFY_DONE;
352
353 wiphy = wdev->wiphy;
354 if (wiphy == NULL)
355 return NOTIFY_DONE;
356
357 hw = wiphy_priv(wiphy);
358 if (hw == NULL)
359 return NOTIFY_DONE;
360
361 wl_temp = hw->priv;
362 list_for_each_entry(wl, &wl_list, list) {
363 if (wl == wl_temp)
364 break;
365 }
366 if (wl != wl_temp)
367 return NOTIFY_DONE;
368
369 mutex_lock(&wl->mutex);
370
371 if (wl->state == WL1271_STATE_OFF)
372 goto out;
373
374 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
375 goto out;
376
377 ret = wl1271_ps_elp_wakeup(wl, false);
378 if (ret < 0)
379 goto out;
380
381 if ((dev->operstate == IF_OPER_UP) &&
382 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
383 wl1271_cmd_set_sta_state(wl);
384 wl1271_info("Association completed.");
385 }
386
387 wl1271_ps_elp_sleep(wl);
388
389out:
390 mutex_unlock(&wl->mutex);
391
392 return NOTIFY_OK;
393}
394
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100395static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200396 struct regulatory_request *request)
397{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100398 struct ieee80211_supported_band *band;
399 struct ieee80211_channel *ch;
400 int i;
401
402 band = wiphy->bands[IEEE80211_BAND_5GHZ];
403 for (i = 0; i < band->n_channels; i++) {
404 ch = &band->channels[i];
405 if (ch->flags & IEEE80211_CHAN_DISABLED)
406 continue;
407
408 if (ch->flags & IEEE80211_CHAN_RADAR)
409 ch->flags |= IEEE80211_CHAN_NO_IBSS |
410 IEEE80211_CHAN_PASSIVE_SCAN;
411
412 }
413
414 return 0;
415}
416
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417static void wl1271_conf_init(struct wl1271 *wl)
418{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300419
420 /*
421 * This function applies the default configuration to the driver. This
422 * function is invoked upon driver load (spi probe.)
423 *
424 * The configuration is stored in a run-time structure in order to
425 * facilitate for run-time adjustment of any of the parameters. Making
426 * changes to the configuration structure will apply the new values on
427 * the next interface up (wl1271_op_start.)
428 */
429
430 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300431 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300432}
433
434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435static int wl1271_plt_init(struct wl1271 *wl)
436{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 struct conf_tx_ac_category *conf_ac;
438 struct conf_tx_tid *conf_tid;
439 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200441 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200442 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200443 return ret;
444
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200445 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200446 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200447 return ret;
448
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200449 ret = wl1271_cmd_ext_radio_parms(wl);
450 if (ret < 0)
451 return ret;
452
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200453 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200454 if (ret < 0)
455 return ret;
456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457 ret = wl1271_acx_init_mem_config(wl);
458 if (ret < 0)
459 return ret;
460
Luciano Coelho12419cc2010-02-18 13:25:44 +0200461 /* PHY layer config */
462 ret = wl1271_init_phy_config(wl);
463 if (ret < 0)
464 goto out_free_memmap;
465
466 ret = wl1271_acx_dco_itrim_params(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200471 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
475 /* Bluetooth WLAN coexistence */
476 ret = wl1271_init_pta(wl);
477 if (ret < 0)
478 goto out_free_memmap;
479
480 /* Energy detection */
481 ret = wl1271_init_energy_detection(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
485 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100486 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200487 if (ret < 0)
488 goto out_free_memmap;
489
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200490 /* Default TID/AC configuration */
491 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200492 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200493 conf_ac = &wl->conf.tx.ac_conf[i];
494 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
495 conf_ac->cw_max, conf_ac->aifsn,
496 conf_ac->tx_op_limit);
497 if (ret < 0)
498 goto out_free_memmap;
499
Luciano Coelho12419cc2010-02-18 13:25:44 +0200500 conf_tid = &wl->conf.tx.tid_conf[i];
501 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
502 conf_tid->channel_type,
503 conf_tid->tsid,
504 conf_tid->ps_scheme,
505 conf_tid->ack_policy,
506 conf_tid->apsd_conf[0],
507 conf_tid->apsd_conf[1]);
508 if (ret < 0)
509 goto out_free_memmap;
510 }
511
Luciano Coelho12419cc2010-02-18 13:25:44 +0200512 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200513 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200515 goto out_free_memmap;
516
517 /* Configure for CAM power saving (ie. always active) */
518 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
519 if (ret < 0)
520 goto out_free_memmap;
521
522 /* configure PM */
523 ret = wl1271_acx_pm_config(wl);
524 if (ret < 0)
525 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526
527 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200528
529 out_free_memmap:
530 kfree(wl->target_mem_map);
531 wl->target_mem_map = NULL;
532
533 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300534}
535
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300536static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200537 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200539 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200540 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300541 u32 total = 0;
542 int i;
543
Eliad Pellerc8bde242011-02-02 09:59:35 +0200544 if (wl->bss_type == BSS_TYPE_AP_BSS)
545 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
546 sizeof(struct wl1271_fw_ap_status), false);
547 else
548 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
549 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300550
551 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
552 "drv_rx_counter = %d, tx_results_counter = %d)",
553 status->intr,
554 status->fw_rx_counter,
555 status->drv_rx_counter,
556 status->tx_results_counter);
557
558 /* update number of available TX blocks */
559 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300560 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
561 wl->tx_blocks_freed[i];
562
563 wl->tx_blocks_freed[i] =
564 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565 wl->tx_blocks_available += cnt;
566 total += cnt;
567 }
568
Ido Yariva5225502010-10-12 14:49:10 +0200569 /* if more blocks are available now, tx work can be scheduled */
570 if (total)
571 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300572
573 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200574 getnstimeofday(&ts);
575 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
576 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577}
578
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200579#define WL1271_IRQ_MAX_LOOPS 10
580
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581static void wl1271_irq_work(struct work_struct *work)
582{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300584 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200585 int loopcount = WL1271_IRQ_MAX_LOOPS;
586 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 struct wl1271 *wl =
588 container_of(work, struct wl1271, irq_work);
589
590 mutex_lock(&wl->mutex);
591
592 wl1271_debug(DEBUG_IRQ, "IRQ work");
593
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200594 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl, true);
598 if (ret < 0)
599 goto out;
600
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200601 spin_lock_irqsave(&wl->wl_lock, flags);
602 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
603 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
604 spin_unlock_irqrestore(&wl->wl_lock, flags);
605 loopcount--;
606
607 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200608 intr = le32_to_cpu(wl->fw_status->common.intr);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200609 if (!intr) {
610 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200611 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200612 continue;
613 }
614
615 intr &= WL1271_INTR_MASK;
616
Eliad Pellerccc83b02010-10-27 14:09:57 +0200617 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
618 wl1271_error("watchdog interrupt received! "
619 "starting recovery.");
620 ieee80211_queue_work(wl->hw, &wl->recovery_work);
621
622 /* restarting the chip. ignore any other interrupt. */
623 goto out;
624 }
625
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200626 if (intr & WL1271_ACX_INTR_DATA) {
627 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
628
629 /* check for tx results */
Eliad Pellerc8bde242011-02-02 09:59:35 +0200630 if (wl->fw_status->common.tx_results_counter !=
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200631 (wl->tx_results_count & 0xff))
632 wl1271_tx_complete(wl);
633
Ido Yariva5225502010-10-12 14:49:10 +0200634 /* Check if any tx blocks were freed */
635 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200636 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200637 /*
638 * In order to avoid starvation of the TX path,
639 * call the work function directly.
640 */
641 wl1271_tx_work_locked(wl);
642 }
643
Eliad Pellerc8bde242011-02-02 09:59:35 +0200644 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200645 }
646
647 if (intr & WL1271_ACX_INTR_EVENT_A) {
648 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
649 wl1271_event_handle(wl, 0);
650 }
651
652 if (intr & WL1271_ACX_INTR_EVENT_B) {
653 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
654 wl1271_event_handle(wl, 1);
655 }
656
657 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
658 wl1271_debug(DEBUG_IRQ,
659 "WL1271_ACX_INTR_INIT_COMPLETE");
660
661 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
662 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
663
664 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 }
666
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200667 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
668 ieee80211_queue_work(wl->hw, &wl->irq_work);
669 else
670 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
671 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 wl1271_ps_elp_sleep(wl);
674
675out:
676 mutex_unlock(&wl->mutex);
677}
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679static int wl1271_fetch_firmware(struct wl1271 *wl)
680{
681 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200682 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 int ret;
684
Arik Nemtsov166d5042010-10-16 21:44:57 +0200685 switch (wl->bss_type) {
686 case BSS_TYPE_AP_BSS:
687 fw_name = WL1271_AP_FW_NAME;
688 break;
689 case BSS_TYPE_IBSS:
690 case BSS_TYPE_STA_BSS:
691 fw_name = WL1271_FW_NAME;
692 break;
693 default:
694 wl1271_error("no compatible firmware for bss_type %d",
695 wl->bss_type);
696 return -EINVAL;
697 }
698
699 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
700
701 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 if (ret < 0) {
704 wl1271_error("could not get firmware: %d", ret);
705 return ret;
706 }
707
708 if (fw->size % 4) {
709 wl1271_error("firmware size is not multiple of 32 bits: %zu",
710 fw->size);
711 ret = -EILSEQ;
712 goto out;
713 }
714
Arik Nemtsov166d5042010-10-16 21:44:57 +0200715 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300717 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718
719 if (!wl->fw) {
720 wl1271_error("could not allocate memory for the firmware");
721 ret = -ENOMEM;
722 goto out;
723 }
724
725 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200726 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727 ret = 0;
728
729out:
730 release_firmware(fw);
731
732 return ret;
733}
734
735static int wl1271_fetch_nvs(struct wl1271 *wl)
736{
737 const struct firmware *fw;
738 int ret;
739
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200740 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
742 if (ret < 0) {
743 wl1271_error("could not get nvs file: %d", ret);
744 return ret;
745 }
746
Julia Lawall929ebd32010-05-15 23:16:39 +0200747 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749 if (!wl->nvs) {
750 wl1271_error("could not allocate memory for the nvs file");
751 ret = -ENOMEM;
752 goto out;
753 }
754
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200755 wl->nvs_len = fw->size;
756
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757out:
758 release_firmware(fw);
759
760 return ret;
761}
762
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200763static void wl1271_recovery_work(struct work_struct *work)
764{
765 struct wl1271 *wl =
766 container_of(work, struct wl1271, recovery_work);
767
768 mutex_lock(&wl->mutex);
769
770 if (wl->state != WL1271_STATE_ON)
771 goto out;
772
773 wl1271_info("Hardware recovery in progress.");
774
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200775 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
776 ieee80211_connection_loss(wl->vif);
777
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200778 /* reboot the chipset */
779 __wl1271_op_remove_interface(wl);
780 ieee80211_restart_hw(wl->hw);
781
782out:
783 mutex_unlock(&wl->mutex);
784}
785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786static void wl1271_fw_wakeup(struct wl1271 *wl)
787{
788 u32 elp_reg;
789
790 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300791 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792}
793
794static int wl1271_setup(struct wl1271 *wl)
795{
796 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
797 if (!wl->fw_status)
798 return -ENOMEM;
799
800 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
801 if (!wl->tx_res_if) {
802 kfree(wl->fw_status);
803 return -ENOMEM;
804 }
805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806 return 0;
807}
808
809static int wl1271_chip_wakeup(struct wl1271 *wl)
810{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300811 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812 int ret = 0;
813
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200814 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200815 ret = wl1271_power_on(wl);
816 if (ret < 0)
817 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200819 wl1271_io_reset(wl);
820 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821
822 /* We don't need a real memory partition here, because we only want
823 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300824 memset(&partition, 0, sizeof(partition));
825 partition.reg.start = REGISTERS_BASE;
826 partition.reg.size = REGISTERS_DOWN_SIZE;
827 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
829 /* ELP module wake up */
830 wl1271_fw_wakeup(wl);
831
832 /* whal_FwCtrl_BootSm() */
833
834 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200835 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
837 /* 1. check if chip id is valid */
838
839 switch (wl->chip.id) {
840 case CHIP_ID_1271_PG10:
841 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
842 wl->chip.id);
843
844 ret = wl1271_setup(wl);
845 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200846 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847 break;
848 case CHIP_ID_1271_PG20:
849 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
850 wl->chip.id);
851
852 ret = wl1271_setup(wl);
853 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200854 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300855 break;
856 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200857 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300858 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200859 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860 }
861
Arik Nemtsov166d5042010-10-16 21:44:57 +0200862 /* Make sure the firmware type matches the BSS type */
863 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864 ret = wl1271_fetch_firmware(wl);
865 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200866 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 }
868
869 /* No NVS from netlink, try to get it from the filesystem */
870 if (wl->nvs == NULL) {
871 ret = wl1271_fetch_nvs(wl);
872 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200873 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 }
875
876out:
877 return ret;
878}
879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880int wl1271_plt_start(struct wl1271 *wl)
881{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200882 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883 int ret;
884
885 mutex_lock(&wl->mutex);
886
887 wl1271_notice("power up");
888
889 if (wl->state != WL1271_STATE_OFF) {
890 wl1271_error("cannot go into PLT state because not "
891 "in off state: %d", wl->state);
892 ret = -EBUSY;
893 goto out;
894 }
895
Arik Nemtsov166d5042010-10-16 21:44:57 +0200896 wl->bss_type = BSS_TYPE_STA_BSS;
897
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200898 while (retries) {
899 retries--;
900 ret = wl1271_chip_wakeup(wl);
901 if (ret < 0)
902 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200904 ret = wl1271_boot(wl);
905 if (ret < 0)
906 goto power_off;
907
908 ret = wl1271_plt_init(wl);
909 if (ret < 0)
910 goto irq_disable;
911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 wl->state = WL1271_STATE_PLT;
913 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100914 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915 goto out;
916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200917irq_disable:
918 wl1271_disable_interrupts(wl);
919 mutex_unlock(&wl->mutex);
920 /* Unlocking the mutex in the middle of handling is
921 inherently unsafe. In this case we deem it safe to do,
922 because we need to let any possibly pending IRQ out of
923 the system (and while we are WL1271_STATE_OFF the IRQ
924 work function will not do anything.) Also, any other
925 possible concurrent operations will fail due to the
926 current state, hence the wl1271 struct should be safe. */
927 cancel_work_sync(&wl->irq_work);
928 mutex_lock(&wl->mutex);
929power_off:
930 wl1271_power_off(wl);
931 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200933 wl1271_error("firmware boot in PLT mode failed despite %d retries",
934 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935out:
936 mutex_unlock(&wl->mutex);
937
938 return ret;
939}
940
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100941int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942{
943 int ret = 0;
944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 wl1271_notice("power down");
946
947 if (wl->state != WL1271_STATE_PLT) {
948 wl1271_error("cannot power down because not in PLT "
949 "state: %d", wl->state);
950 ret = -EBUSY;
951 goto out;
952 }
953
954 wl1271_disable_interrupts(wl);
955 wl1271_power_off(wl);
956
957 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300958 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200961 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200962 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100963 mutex_lock(&wl->mutex);
964out:
965 return ret;
966}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200967
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100968int wl1271_plt_stop(struct wl1271 *wl)
969{
970 int ret;
971
972 mutex_lock(&wl->mutex);
973 ret = __wl1271_plt_stop(wl);
974 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975 return ret;
976}
977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
979{
980 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200981 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200982 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200984 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200985 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200986 spin_unlock_irqrestore(&wl->wl_lock, flags);
987
988 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200989 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
990 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991
992 /*
993 * The chip specific setup must run before the first TX packet -
994 * before that, the tx_work will not be initialized!
995 */
996
Ido Yariva5225502010-10-12 14:49:10 +0200997 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
998 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
1000 /*
1001 * The workqueue is slow to process the tx_queue and we need stop
1002 * the queue here, otherwise the queue will get too long.
1003 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001004 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001005 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001007 spin_lock_irqsave(&wl->wl_lock, flags);
1008 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001009 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001010 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 }
1012
1013 return NETDEV_TX_OK;
1014}
1015
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001016static struct notifier_block wl1271_dev_notifier = {
1017 .notifier_call = wl1271_dev_notify,
1018};
1019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020static int wl1271_op_start(struct ieee80211_hw *hw)
1021{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001022 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1023
1024 /*
1025 * We have to delay the booting of the hardware because
1026 * we need to know the local MAC address before downloading and
1027 * initializing the firmware. The MAC address cannot be changed
1028 * after boot, and without the proper MAC address, the firmware
1029 * will not function properly.
1030 *
1031 * The MAC address is first known when the corresponding interface
1032 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001033 *
1034 * In addition, we currently have different firmwares for AP and managed
1035 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001036 */
1037
1038 return 0;
1039}
1040
1041static void wl1271_op_stop(struct ieee80211_hw *hw)
1042{
1043 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1044}
1045
1046static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1047 struct ieee80211_vif *vif)
1048{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001050 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001051 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001053 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001055 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1056 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
1058 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001059 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001060 wl1271_debug(DEBUG_MAC80211,
1061 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001062 ret = -EBUSY;
1063 goto out;
1064 }
1065
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001066 switch (vif->type) {
1067 case NL80211_IFTYPE_STATION:
1068 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001069 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001070 break;
1071 case NL80211_IFTYPE_ADHOC:
1072 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001073 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001074 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001075 case NL80211_IFTYPE_AP:
1076 wl->bss_type = BSS_TYPE_AP_BSS;
1077 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001078 default:
1079 ret = -EOPNOTSUPP;
1080 goto out;
1081 }
1082
1083 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084
1085 if (wl->state != WL1271_STATE_OFF) {
1086 wl1271_error("cannot start because not in off state: %d",
1087 wl->state);
1088 ret = -EBUSY;
1089 goto out;
1090 }
1091
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001092 while (retries) {
1093 retries--;
1094 ret = wl1271_chip_wakeup(wl);
1095 if (ret < 0)
1096 goto power_off;
1097
1098 ret = wl1271_boot(wl);
1099 if (ret < 0)
1100 goto power_off;
1101
1102 ret = wl1271_hw_init(wl);
1103 if (ret < 0)
1104 goto irq_disable;
1105
Eliad Peller71125ab2010-10-28 21:46:43 +02001106 booted = true;
1107 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001108
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001109irq_disable:
1110 wl1271_disable_interrupts(wl);
1111 mutex_unlock(&wl->mutex);
1112 /* Unlocking the mutex in the middle of handling is
1113 inherently unsafe. In this case we deem it safe to do,
1114 because we need to let any possibly pending IRQ out of
1115 the system (and while we are WL1271_STATE_OFF the IRQ
1116 work function will not do anything.) Also, any other
1117 possible concurrent operations will fail due to the
1118 current state, hence the wl1271 struct should be safe. */
1119 cancel_work_sync(&wl->irq_work);
1120 mutex_lock(&wl->mutex);
1121power_off:
1122 wl1271_power_off(wl);
1123 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124
Eliad Peller71125ab2010-10-28 21:46:43 +02001125 if (!booted) {
1126 wl1271_error("firmware boot failed despite %d retries",
1127 WL1271_BOOT_RETRIES);
1128 goto out;
1129 }
1130
1131 wl->vif = vif;
1132 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001133 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001134
1135 /* update hw/fw version info in wiphy struct */
1136 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001137 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001138 sizeof(wiphy->fw_version));
1139
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001140 /*
1141 * Now we know if 11a is supported (info from the NVS), so disable
1142 * 11a channels if not supported
1143 */
1144 if (!wl->enable_11a)
1145 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1146
1147 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1148 wl->enable_11a ? "" : "not ");
1149
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001150out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001151 mutex_unlock(&wl->mutex);
1152
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001153 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001154 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001155
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001156 return ret;
1157}
1158
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001159static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161 int i;
1162
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001163 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001165 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001167 list_del(&wl->list);
1168
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001169 WARN_ON(wl->state != WL1271_STATE_ON);
1170
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001171 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001172 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001173 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001174
Luciano Coelho08688d62010-07-08 17:50:07 +03001175 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001176 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1177 kfree(wl->scan.scanned_ch);
1178 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001179 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001180 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 }
1182
1183 wl->state = WL1271_STATE_OFF;
1184
1185 wl1271_disable_interrupts(wl);
1186
1187 mutex_unlock(&wl->mutex);
1188
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001189 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001190 cancel_work_sync(&wl->irq_work);
1191 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001192 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001193 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194
1195 mutex_lock(&wl->mutex);
1196
1197 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001198 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001199 wl1271_power_off(wl);
1200
1201 memset(wl->bssid, 0, ETH_ALEN);
1202 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1203 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001205 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001206 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207
1208 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001209 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1211 wl->tx_blocks_available = 0;
1212 wl->tx_results_count = 0;
1213 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001214 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001215 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216 wl->time_offset = 0;
1217 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001218 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001219 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001220 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001221 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001222 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001223 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001224
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225 for (i = 0; i < NUM_TX_QUEUES; i++)
1226 wl->tx_blocks_freed[i] = 0;
1227
1228 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001229
1230 kfree(wl->fw_status);
1231 wl->fw_status = NULL;
1232 kfree(wl->tx_res_if);
1233 wl->tx_res_if = NULL;
1234 kfree(wl->target_mem_map);
1235 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001236}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001237
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001238static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1239 struct ieee80211_vif *vif)
1240{
1241 struct wl1271 *wl = hw->priv;
1242
1243 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001244 /*
1245 * wl->vif can be null here if someone shuts down the interface
1246 * just when hardware recovery has been started.
1247 */
1248 if (wl->vif) {
1249 WARN_ON(wl->vif != vif);
1250 __wl1271_op_remove_interface(wl);
1251 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001252
Juuso Oikarinen67353292010-11-18 15:19:02 +02001253 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001254 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255}
1256
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001257static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1258{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001259 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001260
1261 /* combine requested filters with current filter config */
1262 filters = wl->filters | filters;
1263
1264 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1265
1266 if (filters & FIF_PROMISC_IN_BSS) {
1267 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1268 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1269 wl->rx_config |= CFG_BSSID_FILTER_EN;
1270 }
1271 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1272 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1273 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1274 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1275 }
1276 if (filters & FIF_OTHER_BSS) {
1277 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1278 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1279 }
1280 if (filters & FIF_CONTROL) {
1281 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1282 wl->rx_filter |= CFG_RX_CTL_EN;
1283 }
1284 if (filters & FIF_FCSFAIL) {
1285 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1286 wl->rx_filter |= CFG_RX_FCS_ERROR;
1287 }
1288}
1289
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001290static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001291{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001292 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001293 /* we need to use a dummy BSSID for now */
1294 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1295 0xad, 0xbe, 0xef };
1296
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001297 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1298
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001299 /* pass through frames from all BSS */
1300 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1301
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001302 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001303 if (ret < 0)
1304 goto out;
1305
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001306 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001307
1308out:
1309 return ret;
1310}
1311
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001312static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001313{
1314 int ret;
1315
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001316 /*
1317 * One of the side effects of the JOIN command is that is clears
1318 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1319 * to a WPA/WPA2 access point will therefore kill the data-path.
1320 * Currently there is no supported scenario for JOIN during
1321 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1322 * must be handled somehow.
1323 *
1324 */
1325 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1326 wl1271_info("JOIN while associated.");
1327
1328 if (set_assoc)
1329 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1330
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001331 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1332 if (ret < 0)
1333 goto out;
1334
1335 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1336
1337 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1338 goto out;
1339
1340 /*
1341 * The join command disable the keep-alive mode, shut down its process,
1342 * and also clear the template config, so we need to reset it all after
1343 * the join. The acx_aid starts the keep-alive process, and the order
1344 * of the commands below is relevant.
1345 */
1346 ret = wl1271_acx_keep_alive_mode(wl, true);
1347 if (ret < 0)
1348 goto out;
1349
1350 ret = wl1271_acx_aid(wl, wl->aid);
1351 if (ret < 0)
1352 goto out;
1353
1354 ret = wl1271_cmd_build_klv_null_data(wl);
1355 if (ret < 0)
1356 goto out;
1357
1358 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1359 ACX_KEEP_ALIVE_TPL_VALID);
1360 if (ret < 0)
1361 goto out;
1362
1363out:
1364 return ret;
1365}
1366
1367static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001368{
1369 int ret;
1370
1371 /* to stop listening to a channel, we disconnect */
1372 ret = wl1271_cmd_disconnect(wl);
1373 if (ret < 0)
1374 goto out;
1375
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001376 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001377 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001378
1379 /* stop filterting packets based on bssid */
1380 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001381
1382out:
1383 return ret;
1384}
1385
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001386static void wl1271_set_band_rate(struct wl1271 *wl)
1387{
1388 if (wl->band == IEEE80211_BAND_2GHZ)
1389 wl->basic_rate_set = wl->conf.tx.basic_rate;
1390 else
1391 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1392}
1393
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001394static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001395{
1396 int ret;
1397
1398 if (idle) {
1399 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1400 ret = wl1271_unjoin(wl);
1401 if (ret < 0)
1402 goto out;
1403 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001404 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001405 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001406 if (ret < 0)
1407 goto out;
1408 ret = wl1271_acx_keep_alive_config(
1409 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1410 ACX_KEEP_ALIVE_TPL_INVALID);
1411 if (ret < 0)
1412 goto out;
1413 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1414 } else {
1415 /* increment the session counter */
1416 wl->session_counter++;
1417 if (wl->session_counter >= SESSION_COUNTER_MAX)
1418 wl->session_counter = 0;
1419 ret = wl1271_dummy_join(wl);
1420 if (ret < 0)
1421 goto out;
1422 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1423 }
1424
1425out:
1426 return ret;
1427}
1428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1430{
1431 struct wl1271 *wl = hw->priv;
1432 struct ieee80211_conf *conf = &hw->conf;
1433 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001434 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435
1436 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1437
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001438 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1439 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 channel,
1441 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001442 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001443 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1444 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001446 /*
1447 * mac80211 will go to idle nearly immediately after transmitting some
1448 * frames, such as the deauth. To make sure those frames reach the air,
1449 * wait here until the TX queue is fully flushed.
1450 */
1451 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1452 (conf->flags & IEEE80211_CONF_IDLE))
1453 wl1271_tx_flush(wl);
1454
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 mutex_lock(&wl->mutex);
1456
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001457 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1458 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001459 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001460 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001461
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001462 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1463
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 ret = wl1271_ps_elp_wakeup(wl, false);
1465 if (ret < 0)
1466 goto out;
1467
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001468 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001469 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1470 ((wl->band != conf->channel->band) ||
1471 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001472 wl->band = conf->channel->band;
1473 wl->channel = channel;
1474
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001475 if (!is_ap) {
1476 /*
1477 * FIXME: the mac80211 should really provide a fixed
1478 * rate to use here. for now, just use the smallest
1479 * possible rate for the band as a fixed rate for
1480 * association frames and other control messages.
1481 */
1482 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1483 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001484
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001485 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1486 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001487 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001488 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001489 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001490
1491 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1492 ret = wl1271_join(wl, false);
1493 if (ret < 0)
1494 wl1271_warning("cmd join on channel "
1495 "failed %d", ret);
1496 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001497 }
1498 }
1499
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001500 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1501 ret = wl1271_sta_handle_idle(wl,
1502 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001503 if (ret < 0)
1504 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505 }
1506
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001507 /*
1508 * if mac80211 changes the PSM mode, make sure the mode is not
1509 * incorrectly changed after the pspoll failure active window.
1510 */
1511 if (changed & IEEE80211_CONF_CHANGE_PS)
1512 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1513
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001514 if (conf->flags & IEEE80211_CONF_PS &&
1515 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1516 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
1518 /*
1519 * We enter PSM only if we're already associated.
1520 * If we're not, we'll enter it when joining an SSID,
1521 * through the bss_info_changed() hook.
1522 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001523 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001524 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001525 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001526 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001527 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001529 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001530 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001532 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001534 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001535 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001536 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537 }
1538
1539 if (conf->power_level != wl->power_level) {
1540 ret = wl1271_acx_tx_power(wl, conf->power_level);
1541 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001542 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543
1544 wl->power_level = conf->power_level;
1545 }
1546
1547out_sleep:
1548 wl1271_ps_elp_sleep(wl);
1549
1550out:
1551 mutex_unlock(&wl->mutex);
1552
1553 return ret;
1554}
1555
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001556struct wl1271_filter_params {
1557 bool enabled;
1558 int mc_list_length;
1559 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1560};
1561
Jiri Pirko22bedad2010-04-01 21:22:57 +00001562static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1563 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001564{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001565 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001566 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001567 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001569 if (unlikely(wl->state == WL1271_STATE_OFF))
1570 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001571
Juuso Oikarinen74441132009-10-13 12:47:53 +03001572 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001573 if (!fp) {
1574 wl1271_error("Out of memory setting filters.");
1575 return 0;
1576 }
1577
1578 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001579 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001580 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1581 fp->enabled = false;
1582 } else {
1583 fp->enabled = true;
1584 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001585 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001586 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001587 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001588 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001589 }
1590
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001591 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001592}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001593
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001594#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1595 FIF_ALLMULTI | \
1596 FIF_FCSFAIL | \
1597 FIF_BCN_PRBRESP_PROMISC | \
1598 FIF_CONTROL | \
1599 FIF_OTHER_BSS)
1600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1602 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001603 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001604{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001605 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001607 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608
Arik Nemtsov7d057862010-10-16 19:25:35 +02001609 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1610 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001612 mutex_lock(&wl->mutex);
1613
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001614 *total &= WL1271_SUPPORTED_FILTERS;
1615 changed &= WL1271_SUPPORTED_FILTERS;
1616
1617 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001618 goto out;
1619
1620 ret = wl1271_ps_elp_wakeup(wl, false);
1621 if (ret < 0)
1622 goto out;
1623
Arik Nemtsov7d057862010-10-16 19:25:35 +02001624 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1625 if (*total & FIF_ALLMULTI)
1626 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1627 else if (fp)
1628 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1629 fp->mc_list,
1630 fp->mc_list_length);
1631 if (ret < 0)
1632 goto out_sleep;
1633 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001634
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001635 /* determine, whether supported filter values have changed */
1636 if (changed == 0)
1637 goto out_sleep;
1638
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001639 /* configure filters */
1640 wl->filters = *total;
1641 wl1271_configure_filters(wl, 0);
1642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001643 /* apply configured filters */
1644 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1645 if (ret < 0)
1646 goto out_sleep;
1647
1648out_sleep:
1649 wl1271_ps_elp_sleep(wl);
1650
1651out:
1652 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001653 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654}
1655
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001656static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1657 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1658 u16 tx_seq_16)
1659{
1660 struct wl1271_ap_key *ap_key;
1661 int i;
1662
1663 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1664
1665 if (key_size > MAX_KEY_SIZE)
1666 return -EINVAL;
1667
1668 /*
1669 * Find next free entry in ap_keys. Also check we are not replacing
1670 * an existing key.
1671 */
1672 for (i = 0; i < MAX_NUM_KEYS; i++) {
1673 if (wl->recorded_ap_keys[i] == NULL)
1674 break;
1675
1676 if (wl->recorded_ap_keys[i]->id == id) {
1677 wl1271_warning("trying to record key replacement");
1678 return -EINVAL;
1679 }
1680 }
1681
1682 if (i == MAX_NUM_KEYS)
1683 return -EBUSY;
1684
1685 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1686 if (!ap_key)
1687 return -ENOMEM;
1688
1689 ap_key->id = id;
1690 ap_key->key_type = key_type;
1691 ap_key->key_size = key_size;
1692 memcpy(ap_key->key, key, key_size);
1693 ap_key->hlid = hlid;
1694 ap_key->tx_seq_32 = tx_seq_32;
1695 ap_key->tx_seq_16 = tx_seq_16;
1696
1697 wl->recorded_ap_keys[i] = ap_key;
1698 return 0;
1699}
1700
1701static void wl1271_free_ap_keys(struct wl1271 *wl)
1702{
1703 int i;
1704
1705 for (i = 0; i < MAX_NUM_KEYS; i++) {
1706 kfree(wl->recorded_ap_keys[i]);
1707 wl->recorded_ap_keys[i] = NULL;
1708 }
1709}
1710
1711static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1712{
1713 int i, ret = 0;
1714 struct wl1271_ap_key *key;
1715 bool wep_key_added = false;
1716
1717 for (i = 0; i < MAX_NUM_KEYS; i++) {
1718 if (wl->recorded_ap_keys[i] == NULL)
1719 break;
1720
1721 key = wl->recorded_ap_keys[i];
1722 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1723 key->id, key->key_type,
1724 key->key_size, key->key,
1725 key->hlid, key->tx_seq_32,
1726 key->tx_seq_16);
1727 if (ret < 0)
1728 goto out;
1729
1730 if (key->key_type == KEY_WEP)
1731 wep_key_added = true;
1732 }
1733
1734 if (wep_key_added) {
1735 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1736 if (ret < 0)
1737 goto out;
1738 }
1739
1740out:
1741 wl1271_free_ap_keys(wl);
1742 return ret;
1743}
1744
1745static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1746 u8 key_size, const u8 *key, u32 tx_seq_32,
1747 u16 tx_seq_16, struct ieee80211_sta *sta)
1748{
1749 int ret;
1750 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1751
1752 if (is_ap) {
1753 struct wl1271_station *wl_sta;
1754 u8 hlid;
1755
1756 if (sta) {
1757 wl_sta = (struct wl1271_station *)sta->drv_priv;
1758 hlid = wl_sta->hlid;
1759 } else {
1760 hlid = WL1271_AP_BROADCAST_HLID;
1761 }
1762
1763 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1764 /*
1765 * We do not support removing keys after AP shutdown.
1766 * Pretend we do to make mac80211 happy.
1767 */
1768 if (action != KEY_ADD_OR_REPLACE)
1769 return 0;
1770
1771 ret = wl1271_record_ap_key(wl, id,
1772 key_type, key_size,
1773 key, hlid, tx_seq_32,
1774 tx_seq_16);
1775 } else {
1776 ret = wl1271_cmd_set_ap_key(wl, action,
1777 id, key_type, key_size,
1778 key, hlid, tx_seq_32,
1779 tx_seq_16);
1780 }
1781
1782 if (ret < 0)
1783 return ret;
1784 } else {
1785 const u8 *addr;
1786 static const u8 bcast_addr[ETH_ALEN] = {
1787 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1788 };
1789
1790 addr = sta ? sta->addr : bcast_addr;
1791
1792 if (is_zero_ether_addr(addr)) {
1793 /* We dont support TX only encryption */
1794 return -EOPNOTSUPP;
1795 }
1796
1797 /* The wl1271 does not allow to remove unicast keys - they
1798 will be cleared automatically on next CMD_JOIN. Ignore the
1799 request silently, as we dont want the mac80211 to emit
1800 an error message. */
1801 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1802 return 0;
1803
1804 ret = wl1271_cmd_set_sta_key(wl, action,
1805 id, key_type, key_size,
1806 key, addr, tx_seq_32,
1807 tx_seq_16);
1808 if (ret < 0)
1809 return ret;
1810
1811 /* the default WEP key needs to be configured at least once */
1812 if (key_type == KEY_WEP) {
1813 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1814 wl->default_key);
1815 if (ret < 0)
1816 return ret;
1817 }
1818 }
1819
1820 return 0;
1821}
1822
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1824 struct ieee80211_vif *vif,
1825 struct ieee80211_sta *sta,
1826 struct ieee80211_key_conf *key_conf)
1827{
1828 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001830 u32 tx_seq_32 = 0;
1831 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 u8 key_type;
1833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1835
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001836 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001838 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 key_conf->keylen, key_conf->flags);
1840 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 mutex_lock(&wl->mutex);
1843
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001844 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1845 ret = -EAGAIN;
1846 goto out_unlock;
1847 }
1848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 ret = wl1271_ps_elp_wakeup(wl, false);
1850 if (ret < 0)
1851 goto out_unlock;
1852
Johannes Berg97359d12010-08-10 09:46:38 +02001853 switch (key_conf->cipher) {
1854 case WLAN_CIPHER_SUITE_WEP40:
1855 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 key_type = KEY_WEP;
1857
1858 key_conf->hw_key_idx = key_conf->keyidx;
1859 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001860 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 key_type = KEY_TKIP;
1862
1863 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001864 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1865 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001867 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 key_type = KEY_AES;
1869
1870 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001871 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1872 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001874 case WL1271_CIPHER_SUITE_GEM:
1875 key_type = KEY_GEM;
1876 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1877 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1878 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001879 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001880 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881
1882 ret = -EOPNOTSUPP;
1883 goto out_sleep;
1884 }
1885
1886 switch (cmd) {
1887 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001888 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1889 key_conf->keyidx, key_type,
1890 key_conf->keylen, key_conf->key,
1891 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001892 if (ret < 0) {
1893 wl1271_error("Could not add or replace key");
1894 goto out_sleep;
1895 }
1896 break;
1897
1898 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001899 ret = wl1271_set_key(wl, KEY_REMOVE,
1900 key_conf->keyidx, key_type,
1901 key_conf->keylen, key_conf->key,
1902 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 if (ret < 0) {
1904 wl1271_error("Could not remove key");
1905 goto out_sleep;
1906 }
1907 break;
1908
1909 default:
1910 wl1271_error("Unsupported key cmd 0x%x", cmd);
1911 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912 break;
1913 }
1914
1915out_sleep:
1916 wl1271_ps_elp_sleep(wl);
1917
1918out_unlock:
1919 mutex_unlock(&wl->mutex);
1920
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 return ret;
1922}
1923
1924static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001925 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 struct cfg80211_scan_request *req)
1927{
1928 struct wl1271 *wl = hw->priv;
1929 int ret;
1930 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001931 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932
1933 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1934
1935 if (req->n_ssids) {
1936 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001937 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938 }
1939
1940 mutex_lock(&wl->mutex);
1941
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001942 if (wl->state == WL1271_STATE_OFF) {
1943 /*
1944 * We cannot return -EBUSY here because cfg80211 will expect
1945 * a call to ieee80211_scan_completed if we do - in this case
1946 * there won't be any call.
1947 */
1948 ret = -EAGAIN;
1949 goto out;
1950 }
1951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 ret = wl1271_ps_elp_wakeup(wl, false);
1953 if (ret < 0)
1954 goto out;
1955
Luciano Coelho5924f892010-08-04 03:46:22 +03001956 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957
1958 wl1271_ps_elp_sleep(wl);
1959
1960out:
1961 mutex_unlock(&wl->mutex);
1962
1963 return ret;
1964}
1965
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001966static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1967{
1968 struct wl1271 *wl = hw->priv;
1969 int ret = 0;
1970
1971 mutex_lock(&wl->mutex);
1972
1973 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1974 ret = -EAGAIN;
1975 goto out;
1976 }
1977
1978 ret = wl1271_ps_elp_wakeup(wl, false);
1979 if (ret < 0)
1980 goto out;
1981
1982 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1983 if (ret < 0)
1984 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1985
1986 wl1271_ps_elp_sleep(wl);
1987
1988out:
1989 mutex_unlock(&wl->mutex);
1990
1991 return ret;
1992}
1993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1995{
1996 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001997 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998
1999 mutex_lock(&wl->mutex);
2000
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002001 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2002 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002003 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002004 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 ret = wl1271_ps_elp_wakeup(wl, false);
2007 if (ret < 0)
2008 goto out;
2009
2010 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2011 if (ret < 0)
2012 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2013
2014 wl1271_ps_elp_sleep(wl);
2015
2016out:
2017 mutex_unlock(&wl->mutex);
2018
2019 return ret;
2020}
2021
Arik Nemtsove78a2872010-10-16 19:07:21 +02002022static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002023 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002024{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002025 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002026
2027 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002028 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002029 if (ptr[0] == WLAN_EID_SSID) {
2030 wl->ssid_len = ptr[1];
2031 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002032 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002033 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002034 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002035 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002036
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002037 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002038 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002039}
2040
Arik Nemtsove78a2872010-10-16 19:07:21 +02002041static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2042 struct ieee80211_bss_conf *bss_conf,
2043 u32 changed)
2044{
2045 int ret = 0;
2046
2047 if (changed & BSS_CHANGED_ERP_SLOT) {
2048 if (bss_conf->use_short_slot)
2049 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2050 else
2051 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2052 if (ret < 0) {
2053 wl1271_warning("Set slot time failed %d", ret);
2054 goto out;
2055 }
2056 }
2057
2058 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2059 if (bss_conf->use_short_preamble)
2060 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2061 else
2062 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2063 }
2064
2065 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2066 if (bss_conf->use_cts_prot)
2067 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2068 else
2069 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2070 if (ret < 0) {
2071 wl1271_warning("Set ctsprotect failed %d", ret);
2072 goto out;
2073 }
2074 }
2075
2076out:
2077 return ret;
2078}
2079
2080static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2081 struct ieee80211_vif *vif,
2082 struct ieee80211_bss_conf *bss_conf,
2083 u32 changed)
2084{
2085 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2086 int ret = 0;
2087
2088 if ((changed & BSS_CHANGED_BEACON_INT)) {
2089 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2090 bss_conf->beacon_int);
2091
2092 wl->beacon_int = bss_conf->beacon_int;
2093 }
2094
2095 if ((changed & BSS_CHANGED_BEACON)) {
2096 struct ieee80211_hdr *hdr;
2097 int ieoffset = offsetof(struct ieee80211_mgmt,
2098 u.beacon.variable);
2099 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2100 u16 tmpl_id;
2101
2102 if (!beacon)
2103 goto out;
2104
2105 wl1271_debug(DEBUG_MASTER, "beacon updated");
2106
2107 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2108 if (ret < 0) {
2109 dev_kfree_skb(beacon);
2110 goto out;
2111 }
2112 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2113 CMD_TEMPL_BEACON;
2114 ret = wl1271_cmd_template_set(wl, tmpl_id,
2115 beacon->data,
2116 beacon->len, 0,
2117 wl1271_tx_min_rate_get(wl));
2118 if (ret < 0) {
2119 dev_kfree_skb(beacon);
2120 goto out;
2121 }
2122
2123 hdr = (struct ieee80211_hdr *) beacon->data;
2124 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2125 IEEE80211_STYPE_PROBE_RESP);
2126
2127 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2128 CMD_TEMPL_PROBE_RESPONSE;
2129 ret = wl1271_cmd_template_set(wl,
2130 tmpl_id,
2131 beacon->data,
2132 beacon->len, 0,
2133 wl1271_tx_min_rate_get(wl));
2134 dev_kfree_skb(beacon);
2135 if (ret < 0)
2136 goto out;
2137 }
2138
2139out:
2140 return ret;
2141}
2142
2143/* AP mode changes */
2144static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 struct ieee80211_vif *vif,
2146 struct ieee80211_bss_conf *bss_conf,
2147 u32 changed)
2148{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002149 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150
Arik Nemtsove78a2872010-10-16 19:07:21 +02002151 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2152 u32 rates = bss_conf->basic_rates;
2153 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2156 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2157 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2158 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159
Arik Nemtsove78a2872010-10-16 19:07:21 +02002160 /* update the AP management rate policy with the new rates */
2161 mgmt_rc.enabled_rates = wl->basic_rate_set;
2162 mgmt_rc.long_retry_limit = 10;
2163 mgmt_rc.short_retry_limit = 10;
2164 mgmt_rc.aflags = 0;
2165 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2166 ACX_TX_AP_MODE_MGMT_RATE);
2167 if (ret < 0) {
2168 wl1271_error("AP mgmt policy change failed %d", ret);
2169 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002170 }
2171 }
2172
Arik Nemtsove78a2872010-10-16 19:07:21 +02002173 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2174 if (ret < 0)
2175 goto out;
2176
2177 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2178 if (bss_conf->enable_beacon) {
2179 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2180 ret = wl1271_cmd_start_bss(wl);
2181 if (ret < 0)
2182 goto out;
2183
2184 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2185 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002186
2187 ret = wl1271_ap_init_hwenc(wl);
2188 if (ret < 0)
2189 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002190 }
2191 } else {
2192 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2193 ret = wl1271_cmd_stop_bss(wl);
2194 if (ret < 0)
2195 goto out;
2196
2197 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2198 wl1271_debug(DEBUG_AP, "stopped AP");
2199 }
2200 }
2201 }
2202
2203 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2204 if (ret < 0)
2205 goto out;
2206out:
2207 return;
2208}
2209
2210/* STA/IBSS mode changes */
2211static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2212 struct ieee80211_vif *vif,
2213 struct ieee80211_bss_conf *bss_conf,
2214 u32 changed)
2215{
2216 bool do_join = false, set_assoc = false;
2217 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002218 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002219 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002220 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002221
2222 if (is_ibss) {
2223 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2224 changed);
2225 if (ret < 0)
2226 goto out;
2227 }
2228
2229 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2230 do_join = true;
2231
2232 /* Need to update the SSID (for filtering etc) */
2233 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2234 do_join = true;
2235
2236 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002237 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2238 bss_conf->enable_beacon ? "enabled" : "disabled");
2239
2240 if (bss_conf->enable_beacon)
2241 wl->set_bss_type = BSS_TYPE_IBSS;
2242 else
2243 wl->set_bss_type = BSS_TYPE_STA_BSS;
2244 do_join = true;
2245 }
2246
Arik Nemtsove78a2872010-10-16 19:07:21 +02002247 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002248 bool enable = false;
2249 if (bss_conf->cqm_rssi_thold)
2250 enable = true;
2251 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2252 bss_conf->cqm_rssi_thold,
2253 bss_conf->cqm_rssi_hyst);
2254 if (ret < 0)
2255 goto out;
2256 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2257 }
2258
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002259 if ((changed & BSS_CHANGED_BSSID) &&
2260 /*
2261 * Now we know the correct bssid, so we send a new join command
2262 * and enable the BSSID filter
2263 */
2264 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002265 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002266
Eliad Pellerfa287b82010-12-26 09:27:50 +01002267 if (!is_zero_ether_addr(wl->bssid)) {
2268 ret = wl1271_cmd_build_null_data(wl);
2269 if (ret < 0)
2270 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002271
Eliad Pellerfa287b82010-12-26 09:27:50 +01002272 ret = wl1271_build_qos_null_data(wl);
2273 if (ret < 0)
2274 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002275
Eliad Pellerfa287b82010-12-26 09:27:50 +01002276 /* filter out all packets not from this BSSID */
2277 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002278
Eliad Pellerfa287b82010-12-26 09:27:50 +01002279 /* Need to update the BSSID (for filtering etc) */
2280 do_join = true;
2281 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002282 }
2283
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002284 rcu_read_lock();
2285 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2286 if (sta) {
2287 /* save the supp_rates of the ap */
2288 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2289 if (sta->ht_cap.ht_supported)
2290 sta_rate_set |=
2291 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
2292
2293 /* handle new association with HT and HT information change */
2294 if ((changed & BSS_CHANGED_HT) &&
2295 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2296 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2297 true);
2298 if (ret < 0) {
2299 wl1271_warning("Set ht cap true failed %d",
2300 ret);
2301 rcu_read_unlock();
2302 goto out;
2303 }
2304 ret = wl1271_acx_set_ht_information(wl,
2305 bss_conf->ht_operation_mode);
2306 if (ret < 0) {
2307 wl1271_warning("Set ht information failed %d",
2308 ret);
2309 rcu_read_unlock();
2310 goto out;
2311 }
2312 }
2313 /* handle new association without HT and disassociation */
2314 else if (changed & BSS_CHANGED_ASSOC) {
2315 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2316 false);
2317 if (ret < 0) {
2318 wl1271_warning("Set ht cap false failed %d",
2319 ret);
2320 rcu_read_unlock();
2321 goto out;
2322 }
2323 }
2324 }
2325 rcu_read_unlock();
2326
Arik Nemtsove78a2872010-10-16 19:07:21 +02002327 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002329 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002330 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002332 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002334 wl->ps_poll_failures = 0;
2335
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002336 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002337 * use basic rates from AP, and determine lowest rate
2338 * to use with control frames.
2339 */
2340 rates = bss_conf->basic_rates;
2341 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2342 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002343 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002344 if (sta_rate_set)
2345 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2346 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002347 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002348 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002349 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002350
2351 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002352 * with wl1271, we don't need to update the
2353 * beacon_int and dtim_period, because the firmware
2354 * updates it by itself when the first beacon is
2355 * received after a join.
2356 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002357 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2358 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002359 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002361 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002362 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002363 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002364 dev_kfree_skb(wl->probereq);
2365 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2366 ieoffset = offsetof(struct ieee80211_mgmt,
2367 u.probe_req.variable);
2368 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002369
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002370 /* enable the connection monitoring feature */
2371 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002373 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374
2375 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002376 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2377 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002378 enum wl1271_cmd_ps_mode mode;
2379
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002381 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002382 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002383 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002385 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002387 } else {
2388 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002389 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002390 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002391 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002392
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002393 /* free probe-request template */
2394 dev_kfree_skb(wl->probereq);
2395 wl->probereq = NULL;
2396
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002397 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002398 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002399
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002400 /* revert back to minimum rates for the current band */
2401 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002402 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002403 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002405 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002406
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002407 /* disable connection monitor features */
2408 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002409
2410 /* Disable the keep-alive feature */
2411 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002412 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002413 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002414
2415 /* restore the bssid filter and go to dummy bssid */
2416 wl1271_unjoin(wl);
2417 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418 }
2419 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002420
Arik Nemtsove78a2872010-10-16 19:07:21 +02002421 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2422 if (ret < 0)
2423 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002424
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002425 if (changed & BSS_CHANGED_ARP_FILTER) {
2426 __be32 addr = bss_conf->arp_addr_list[0];
2427 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2428
Eliad Pellerc5312772010-12-09 11:31:27 +02002429 if (bss_conf->arp_addr_cnt == 1 &&
2430 bss_conf->arp_filter_enabled) {
2431 /*
2432 * The template should have been configured only upon
2433 * association. however, it seems that the correct ip
2434 * isn't being set (when sending), so we have to
2435 * reconfigure the template upon every ip change.
2436 */
2437 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2438 if (ret < 0) {
2439 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002440 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002441 }
2442
2443 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002444 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002445 addr);
2446 } else
2447 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002448
2449 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002450 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002451 }
2452
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002453 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002454 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002455 if (ret < 0) {
2456 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002457 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002458 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002459 }
2460
Arik Nemtsove78a2872010-10-16 19:07:21 +02002461out:
2462 return;
2463}
2464
2465static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2466 struct ieee80211_vif *vif,
2467 struct ieee80211_bss_conf *bss_conf,
2468 u32 changed)
2469{
2470 struct wl1271 *wl = hw->priv;
2471 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2472 int ret;
2473
2474 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2475 (int)changed);
2476
2477 mutex_lock(&wl->mutex);
2478
2479 if (unlikely(wl->state == WL1271_STATE_OFF))
2480 goto out;
2481
2482 ret = wl1271_ps_elp_wakeup(wl, false);
2483 if (ret < 0)
2484 goto out;
2485
2486 if (is_ap)
2487 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2488 else
2489 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491 wl1271_ps_elp_sleep(wl);
2492
2493out:
2494 mutex_unlock(&wl->mutex);
2495}
2496
Kalle Valoc6999d82010-02-18 13:25:41 +02002497static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2498 const struct ieee80211_tx_queue_params *params)
2499{
2500 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002501 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002502 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002503
2504 mutex_lock(&wl->mutex);
2505
2506 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2507
Kalle Valo4695dc92010-03-18 12:26:38 +02002508 if (params->uapsd)
2509 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2510 else
2511 ps_scheme = CONF_PS_SCHEME_LEGACY;
2512
Arik Nemtsov488fc542010-10-16 20:33:45 +02002513 if (wl->state == WL1271_STATE_OFF) {
2514 /*
2515 * If the state is off, the parameters will be recorded and
2516 * configured on init. This happens in AP-mode.
2517 */
2518 struct conf_tx_ac_category *conf_ac =
2519 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2520 struct conf_tx_tid *conf_tid =
2521 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2522
2523 conf_ac->ac = wl1271_tx_get_queue(queue);
2524 conf_ac->cw_min = (u8)params->cw_min;
2525 conf_ac->cw_max = params->cw_max;
2526 conf_ac->aifsn = params->aifs;
2527 conf_ac->tx_op_limit = params->txop << 5;
2528
2529 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2530 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2531 conf_tid->tsid = wl1271_tx_get_queue(queue);
2532 conf_tid->ps_scheme = ps_scheme;
2533 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2534 conf_tid->apsd_conf[0] = 0;
2535 conf_tid->apsd_conf[1] = 0;
2536 } else {
2537 ret = wl1271_ps_elp_wakeup(wl, false);
2538 if (ret < 0)
2539 goto out;
2540
2541 /*
2542 * the txop is confed in units of 32us by the mac80211,
2543 * we need us
2544 */
2545 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2546 params->cw_min, params->cw_max,
2547 params->aifs, params->txop << 5);
2548 if (ret < 0)
2549 goto out_sleep;
2550
2551 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2552 CONF_CHANNEL_TYPE_EDCF,
2553 wl1271_tx_get_queue(queue),
2554 ps_scheme, CONF_ACK_POLICY_LEGACY,
2555 0, 0);
2556 if (ret < 0)
2557 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002558
2559out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002560 wl1271_ps_elp_sleep(wl);
2561 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002562
2563out:
2564 mutex_unlock(&wl->mutex);
2565
2566 return ret;
2567}
2568
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002569static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2570{
2571
2572 struct wl1271 *wl = hw->priv;
2573 u64 mactime = ULLONG_MAX;
2574 int ret;
2575
2576 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2577
2578 mutex_lock(&wl->mutex);
2579
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002580 if (unlikely(wl->state == WL1271_STATE_OFF))
2581 goto out;
2582
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002583 ret = wl1271_ps_elp_wakeup(wl, false);
2584 if (ret < 0)
2585 goto out;
2586
2587 ret = wl1271_acx_tsf_info(wl, &mactime);
2588 if (ret < 0)
2589 goto out_sleep;
2590
2591out_sleep:
2592 wl1271_ps_elp_sleep(wl);
2593
2594out:
2595 mutex_unlock(&wl->mutex);
2596 return mactime;
2597}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002598
John W. Linvilleece550d2010-07-28 16:41:06 -04002599static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2600 struct survey_info *survey)
2601{
2602 struct wl1271 *wl = hw->priv;
2603 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002604
John W. Linvilleece550d2010-07-28 16:41:06 -04002605 if (idx != 0)
2606 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002607
John W. Linvilleece550d2010-07-28 16:41:06 -04002608 survey->channel = conf->channel;
2609 survey->filled = SURVEY_INFO_NOISE_DBM;
2610 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002611
John W. Linvilleece550d2010-07-28 16:41:06 -04002612 return 0;
2613}
2614
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002615static int wl1271_allocate_hlid(struct wl1271 *wl,
2616 struct ieee80211_sta *sta,
2617 u8 *hlid)
2618{
2619 struct wl1271_station *wl_sta;
2620 int id;
2621
2622 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2623 if (id >= AP_MAX_STATIONS) {
2624 wl1271_warning("could not allocate HLID - too much stations");
2625 return -EBUSY;
2626 }
2627
2628 wl_sta = (struct wl1271_station *)sta->drv_priv;
2629
2630 __set_bit(id, wl->ap_hlid_map);
2631 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2632 *hlid = wl_sta->hlid;
2633 return 0;
2634}
2635
2636static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2637{
2638 int id = hlid - WL1271_AP_STA_HLID_START;
2639
2640 __clear_bit(id, wl->ap_hlid_map);
2641}
2642
2643static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2644 struct ieee80211_vif *vif,
2645 struct ieee80211_sta *sta)
2646{
2647 struct wl1271 *wl = hw->priv;
2648 int ret = 0;
2649 u8 hlid;
2650
2651 mutex_lock(&wl->mutex);
2652
2653 if (unlikely(wl->state == WL1271_STATE_OFF))
2654 goto out;
2655
2656 if (wl->bss_type != BSS_TYPE_AP_BSS)
2657 goto out;
2658
2659 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2660
2661 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2662 if (ret < 0)
2663 goto out;
2664
2665 ret = wl1271_ps_elp_wakeup(wl, false);
2666 if (ret < 0)
2667 goto out;
2668
2669 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2670 if (ret < 0)
2671 goto out_sleep;
2672
2673out_sleep:
2674 wl1271_ps_elp_sleep(wl);
2675
2676out:
2677 mutex_unlock(&wl->mutex);
2678 return ret;
2679}
2680
2681static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2682 struct ieee80211_vif *vif,
2683 struct ieee80211_sta *sta)
2684{
2685 struct wl1271 *wl = hw->priv;
2686 struct wl1271_station *wl_sta;
2687 int ret = 0, id;
2688
2689 mutex_lock(&wl->mutex);
2690
2691 if (unlikely(wl->state == WL1271_STATE_OFF))
2692 goto out;
2693
2694 if (wl->bss_type != BSS_TYPE_AP_BSS)
2695 goto out;
2696
2697 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2698
2699 wl_sta = (struct wl1271_station *)sta->drv_priv;
2700 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2701 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2702 goto out;
2703
2704 ret = wl1271_ps_elp_wakeup(wl, false);
2705 if (ret < 0)
2706 goto out;
2707
2708 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2709 if (ret < 0)
2710 goto out_sleep;
2711
2712 wl1271_free_hlid(wl, wl_sta->hlid);
2713
2714out_sleep:
2715 wl1271_ps_elp_sleep(wl);
2716
2717out:
2718 mutex_unlock(&wl->mutex);
2719 return ret;
2720}
2721
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002722int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002723 enum ieee80211_ampdu_mlme_action action,
2724 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2725 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002726{
2727 struct wl1271 *wl = hw->priv;
2728 int ret;
2729
2730 mutex_lock(&wl->mutex);
2731
2732 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2733 ret = -EAGAIN;
2734 goto out;
2735 }
2736
2737 ret = wl1271_ps_elp_wakeup(wl, false);
2738 if (ret < 0)
2739 goto out;
2740
2741 switch (action) {
2742 case IEEE80211_AMPDU_RX_START:
2743 if (wl->ba_support) {
2744 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2745 true);
2746 if (!ret)
2747 wl->ba_rx_bitmap |= BIT(tid);
2748 } else {
2749 ret = -ENOTSUPP;
2750 }
2751 break;
2752
2753 case IEEE80211_AMPDU_RX_STOP:
2754 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2755 if (!ret)
2756 wl->ba_rx_bitmap &= ~BIT(tid);
2757 break;
2758
2759 /*
2760 * The BA initiator session management in FW independently.
2761 * Falling break here on purpose for all TX APDU commands.
2762 */
2763 case IEEE80211_AMPDU_TX_START:
2764 case IEEE80211_AMPDU_TX_STOP:
2765 case IEEE80211_AMPDU_TX_OPERATIONAL:
2766 ret = -EINVAL;
2767 break;
2768
2769 default:
2770 wl1271_error("Incorrect ampdu action id=%x\n", action);
2771 ret = -EINVAL;
2772 }
2773
2774 wl1271_ps_elp_sleep(wl);
2775
2776out:
2777 mutex_unlock(&wl->mutex);
2778
2779 return ret;
2780}
2781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782/* can't be const, mac80211 writes to this */
2783static struct ieee80211_rate wl1271_rates[] = {
2784 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002785 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2786 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002788 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2789 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2791 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002792 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2793 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002794 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2795 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002796 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2797 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2799 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002800 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2801 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002803 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2804 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002805 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002806 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2807 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002809 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2810 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002812 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2813 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002814 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002815 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2816 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002817 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002818 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2819 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002820 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002821 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2822 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002823};
2824
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002825/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002827 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002828 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002829 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2830 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2831 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002832 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002833 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2834 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2835 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002836 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002837 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2838 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2839 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002840 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841};
2842
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002843/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002844static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002845 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002846 7, /* CONF_HW_RXTX_RATE_MCS7 */
2847 6, /* CONF_HW_RXTX_RATE_MCS6 */
2848 5, /* CONF_HW_RXTX_RATE_MCS5 */
2849 4, /* CONF_HW_RXTX_RATE_MCS4 */
2850 3, /* CONF_HW_RXTX_RATE_MCS3 */
2851 2, /* CONF_HW_RXTX_RATE_MCS2 */
2852 1, /* CONF_HW_RXTX_RATE_MCS1 */
2853 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002854
2855 11, /* CONF_HW_RXTX_RATE_54 */
2856 10, /* CONF_HW_RXTX_RATE_48 */
2857 9, /* CONF_HW_RXTX_RATE_36 */
2858 8, /* CONF_HW_RXTX_RATE_24 */
2859
2860 /* TI-specific rate */
2861 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2862
2863 7, /* CONF_HW_RXTX_RATE_18 */
2864 6, /* CONF_HW_RXTX_RATE_12 */
2865 3, /* CONF_HW_RXTX_RATE_11 */
2866 5, /* CONF_HW_RXTX_RATE_9 */
2867 4, /* CONF_HW_RXTX_RATE_6 */
2868 2, /* CONF_HW_RXTX_RATE_5_5 */
2869 1, /* CONF_HW_RXTX_RATE_2 */
2870 0 /* CONF_HW_RXTX_RATE_1 */
2871};
2872
Shahar Levie8b03a22010-10-13 16:09:39 +02002873/* 11n STA capabilities */
2874#define HW_RX_HIGHEST_RATE 72
2875
Shahar Levi00d20102010-11-08 11:20:10 +00002876#ifdef CONFIG_WL12XX_HT
2877#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002878 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2879 .ht_supported = true, \
2880 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2881 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2882 .mcs = { \
2883 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2884 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2885 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2886 }, \
2887}
Shahar Levi18357852010-10-13 16:09:41 +02002888#else
Shahar Levi00d20102010-11-08 11:20:10 +00002889#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002890 .ht_supported = false, \
2891}
2892#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002894/* can't be const, mac80211 writes to this */
2895static struct ieee80211_supported_band wl1271_band_2ghz = {
2896 .channels = wl1271_channels,
2897 .n_channels = ARRAY_SIZE(wl1271_channels),
2898 .bitrates = wl1271_rates,
2899 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002900 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002901};
2902
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002903/* 5 GHz data rates for WL1273 */
2904static struct ieee80211_rate wl1271_rates_5ghz[] = {
2905 { .bitrate = 60,
2906 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2907 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2908 { .bitrate = 90,
2909 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2910 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2911 { .bitrate = 120,
2912 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2913 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2914 { .bitrate = 180,
2915 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2916 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2917 { .bitrate = 240,
2918 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2919 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2920 { .bitrate = 360,
2921 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2922 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2923 { .bitrate = 480,
2924 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2925 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2926 { .bitrate = 540,
2927 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2928 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2929};
2930
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002931/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002932static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002933 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002934 { .hw_value = 8, .center_freq = 5040},
2935 { .hw_value = 9, .center_freq = 5045},
2936 { .hw_value = 11, .center_freq = 5055},
2937 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002938 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002939 { .hw_value = 34, .center_freq = 5170},
2940 { .hw_value = 36, .center_freq = 5180},
2941 { .hw_value = 38, .center_freq = 5190},
2942 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002943 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002944 { .hw_value = 44, .center_freq = 5220},
2945 { .hw_value = 46, .center_freq = 5230},
2946 { .hw_value = 48, .center_freq = 5240},
2947 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002948 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002949 { .hw_value = 60, .center_freq = 5300},
2950 { .hw_value = 64, .center_freq = 5320},
2951 { .hw_value = 100, .center_freq = 5500},
2952 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002953 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002954 { .hw_value = 112, .center_freq = 5560},
2955 { .hw_value = 116, .center_freq = 5580},
2956 { .hw_value = 120, .center_freq = 5600},
2957 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002958 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002959 { .hw_value = 132, .center_freq = 5660},
2960 { .hw_value = 136, .center_freq = 5680},
2961 { .hw_value = 140, .center_freq = 5700},
2962 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002963 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002964 { .hw_value = 157, .center_freq = 5785},
2965 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002966 { .hw_value = 165, .center_freq = 5825},
2967};
2968
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002969/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002970static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002971 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002972 7, /* CONF_HW_RXTX_RATE_MCS7 */
2973 6, /* CONF_HW_RXTX_RATE_MCS6 */
2974 5, /* CONF_HW_RXTX_RATE_MCS5 */
2975 4, /* CONF_HW_RXTX_RATE_MCS4 */
2976 3, /* CONF_HW_RXTX_RATE_MCS3 */
2977 2, /* CONF_HW_RXTX_RATE_MCS2 */
2978 1, /* CONF_HW_RXTX_RATE_MCS1 */
2979 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002980
2981 7, /* CONF_HW_RXTX_RATE_54 */
2982 6, /* CONF_HW_RXTX_RATE_48 */
2983 5, /* CONF_HW_RXTX_RATE_36 */
2984 4, /* CONF_HW_RXTX_RATE_24 */
2985
2986 /* TI-specific rate */
2987 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2988
2989 3, /* CONF_HW_RXTX_RATE_18 */
2990 2, /* CONF_HW_RXTX_RATE_12 */
2991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2992 1, /* CONF_HW_RXTX_RATE_9 */
2993 0, /* CONF_HW_RXTX_RATE_6 */
2994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2996 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2997};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002998
2999static struct ieee80211_supported_band wl1271_band_5ghz = {
3000 .channels = wl1271_channels_5ghz,
3001 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3002 .bitrates = wl1271_rates_5ghz,
3003 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003004 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003005};
3006
Tobias Klausera0ea9492010-05-20 10:38:11 +02003007static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003008 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3009 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3010};
3011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003012static const struct ieee80211_ops wl1271_ops = {
3013 .start = wl1271_op_start,
3014 .stop = wl1271_op_stop,
3015 .add_interface = wl1271_op_add_interface,
3016 .remove_interface = wl1271_op_remove_interface,
3017 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003018 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 .configure_filter = wl1271_op_configure_filter,
3020 .tx = wl1271_op_tx,
3021 .set_key = wl1271_op_set_key,
3022 .hw_scan = wl1271_op_hw_scan,
3023 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003024 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003025 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003026 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003027 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003028 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003029 .sta_add = wl1271_op_sta_add,
3030 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003031 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003032 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033};
3034
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003035
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003036u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003037{
3038 u8 idx;
3039
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003040 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003041
3042 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3043 wl1271_error("Illegal RX rate from HW: %d", rate);
3044 return 0;
3045 }
3046
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003047 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003048 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3049 wl1271_error("Unsupported RX rate from HW: %d", rate);
3050 return 0;
3051 }
3052
3053 return idx;
3054}
3055
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003056static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3057 struct device_attribute *attr,
3058 char *buf)
3059{
3060 struct wl1271 *wl = dev_get_drvdata(dev);
3061 ssize_t len;
3062
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003063 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003064
3065 mutex_lock(&wl->mutex);
3066 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3067 wl->sg_enabled);
3068 mutex_unlock(&wl->mutex);
3069
3070 return len;
3071
3072}
3073
3074static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3075 struct device_attribute *attr,
3076 const char *buf, size_t count)
3077{
3078 struct wl1271 *wl = dev_get_drvdata(dev);
3079 unsigned long res;
3080 int ret;
3081
3082 ret = strict_strtoul(buf, 10, &res);
3083
3084 if (ret < 0) {
3085 wl1271_warning("incorrect value written to bt_coex_mode");
3086 return count;
3087 }
3088
3089 mutex_lock(&wl->mutex);
3090
3091 res = !!res;
3092
3093 if (res == wl->sg_enabled)
3094 goto out;
3095
3096 wl->sg_enabled = res;
3097
3098 if (wl->state == WL1271_STATE_OFF)
3099 goto out;
3100
3101 ret = wl1271_ps_elp_wakeup(wl, false);
3102 if (ret < 0)
3103 goto out;
3104
3105 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3106 wl1271_ps_elp_sleep(wl);
3107
3108 out:
3109 mutex_unlock(&wl->mutex);
3110 return count;
3111}
3112
3113static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3114 wl1271_sysfs_show_bt_coex_state,
3115 wl1271_sysfs_store_bt_coex_state);
3116
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003117static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3118 struct device_attribute *attr,
3119 char *buf)
3120{
3121 struct wl1271 *wl = dev_get_drvdata(dev);
3122 ssize_t len;
3123
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003124 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003125
3126 mutex_lock(&wl->mutex);
3127 if (wl->hw_pg_ver >= 0)
3128 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3129 else
3130 len = snprintf(buf, len, "n/a\n");
3131 mutex_unlock(&wl->mutex);
3132
3133 return len;
3134}
3135
3136static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3137 wl1271_sysfs_show_hw_pg_ver, NULL);
3138
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003139int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003140{
3141 int ret;
3142
3143 if (wl->mac80211_registered)
3144 return 0;
3145
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003146 ret = wl1271_fetch_nvs(wl);
3147 if (ret == 0) {
3148 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3149
3150 wl->mac_addr[0] = nvs_ptr[11];
3151 wl->mac_addr[1] = nvs_ptr[10];
3152 wl->mac_addr[2] = nvs_ptr[6];
3153 wl->mac_addr[3] = nvs_ptr[5];
3154 wl->mac_addr[4] = nvs_ptr[4];
3155 wl->mac_addr[5] = nvs_ptr[3];
3156 }
3157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003158 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3159
3160 ret = ieee80211_register_hw(wl->hw);
3161 if (ret < 0) {
3162 wl1271_error("unable to register mac80211 hw: %d", ret);
3163 return ret;
3164 }
3165
3166 wl->mac80211_registered = true;
3167
Eliad Pellerd60080a2010-11-24 12:53:16 +02003168 wl1271_debugfs_init(wl);
3169
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003170 register_netdevice_notifier(&wl1271_dev_notifier);
3171
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003172 wl1271_notice("loaded");
3173
3174 return 0;
3175}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003176EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003178void wl1271_unregister_hw(struct wl1271 *wl)
3179{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003180 if (wl->state == WL1271_STATE_PLT)
3181 __wl1271_plt_stop(wl);
3182
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003183 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003184 ieee80211_unregister_hw(wl->hw);
3185 wl->mac80211_registered = false;
3186
3187}
3188EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3189
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003190int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003191{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003192 static const u32 cipher_suites[] = {
3193 WLAN_CIPHER_SUITE_WEP40,
3194 WLAN_CIPHER_SUITE_WEP104,
3195 WLAN_CIPHER_SUITE_TKIP,
3196 WLAN_CIPHER_SUITE_CCMP,
3197 WL1271_CIPHER_SUITE_GEM,
3198 };
3199
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003200 /* The tx descriptor buffer and the TKIP space. */
3201 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3202 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003203
3204 /* unit us */
3205 /* FIXME: find a proper value */
3206 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003207 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208
3209 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003210 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003211 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003212 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003213 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003214 IEEE80211_HW_CONNECTION_MONITOR |
3215 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003217 wl->hw->wiphy->cipher_suites = cipher_suites;
3218 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3219
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003220 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003221 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003223 /*
3224 * Maximum length of elements in scanning probe request templates
3225 * should be the maximum length possible for a template, without
3226 * the IEEE80211 header of the template
3227 */
3228 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3229 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003230
3231 /*
3232 * We keep local copies of the band structs because we need to
3233 * modify them on a per-device basis.
3234 */
3235 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3236 sizeof(wl1271_band_2ghz));
3237 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3238 sizeof(wl1271_band_5ghz));
3239
3240 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3241 &wl->bands[IEEE80211_BAND_2GHZ];
3242 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3243 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003244
Kalle Valo12bd8942010-03-18 12:26:33 +02003245 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003246 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003247
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003248 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3249
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003250 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003251
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003252 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3253
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003254 wl->hw->max_rx_aggregation_subframes = 8;
3255
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003256 return 0;
3257}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003258EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003259
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003260#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003261
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003262struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003263{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003265 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003266 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003267 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003268 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003269
3270 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3271 if (!hw) {
3272 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003273 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003274 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003275 }
3276
Julia Lawall929ebd32010-05-15 23:16:39 +02003277 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003278 if (!plat_dev) {
3279 wl1271_error("could not allocate platform_device");
3280 ret = -ENOMEM;
3281 goto err_plat_alloc;
3282 }
3283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003284 wl = hw->priv;
3285 memset(wl, 0, sizeof(*wl));
3286
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003287 INIT_LIST_HEAD(&wl->list);
3288
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003289 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003290 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003291
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003292 for (i = 0; i < NUM_TX_QUEUES; i++)
3293 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003295 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003296 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003297 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3298 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3299 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3300 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003301 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003302 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003303 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003304 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003305 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3306 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003307 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003309 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003310 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003311 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003312 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003313 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003314 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003315 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003316 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003317 wl->bss_type = MAX_BSS_TYPE;
3318 wl->set_bss_type = MAX_BSS_TYPE;
3319 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003320
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003321 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003322 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003323 wl->tx_frames[i] = NULL;
3324
3325 spin_lock_init(&wl->wl_lock);
3326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003327 wl->state = WL1271_STATE_OFF;
3328 mutex_init(&wl->mutex);
3329
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003330 /* Apply default driver configuration. */
3331 wl1271_conf_init(wl);
3332
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003333 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3334 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3335 if (!wl->aggr_buf) {
3336 ret = -ENOMEM;
3337 goto err_hw;
3338 }
3339
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003340 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003341 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003342 if (ret) {
3343 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003344 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003345 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003346 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003347
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003348 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003349 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003350 if (ret < 0) {
3351 wl1271_error("failed to create sysfs file bt_coex_state");
3352 goto err_platform;
3353 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003354
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003355 /* Create sysfs file to get HW PG version */
3356 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3357 if (ret < 0) {
3358 wl1271_error("failed to create sysfs file hw_pg_ver");
3359 goto err_bt_coex_state;
3360 }
3361
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003362 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003363
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003364err_bt_coex_state:
3365 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3366
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003367err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003368 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003369
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003370err_aggr:
3371 free_pages((unsigned long)wl->aggr_buf, order);
3372
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003373err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003374 wl1271_debugfs_exit(wl);
3375 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003376
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003377err_plat_alloc:
3378 ieee80211_free_hw(hw);
3379
3380err_hw_alloc:
3381
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003382 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003383}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003384EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003385
3386int wl1271_free_hw(struct wl1271 *wl)
3387{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003388 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003389 free_pages((unsigned long)wl->aggr_buf,
3390 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003391 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003392
3393 wl1271_debugfs_exit(wl);
3394
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003395 vfree(wl->fw);
3396 wl->fw = NULL;
3397 kfree(wl->nvs);
3398 wl->nvs = NULL;
3399
3400 kfree(wl->fw_status);
3401 kfree(wl->tx_res_if);
3402
3403 ieee80211_free_hw(wl->hw);
3404
3405 return 0;
3406}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003407EXPORT_SYMBOL_GPL(wl1271_free_hw);
3408
Guy Eilam491bbd62011-01-12 10:33:29 +01003409u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003410EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003411module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003412MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3413
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003414MODULE_LICENSE("GPL");
3415MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3416MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");