blob: 9bb9ad31c2f5e591e836a9bedd0f95cd6f400fc7 [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
Gery Kahn1ec610e2011-02-01 03:03:08 -0600485 ret = wl1271_acx_sta_mem_cfg(wl);
486 if (ret < 0)
487 goto out_free_memmap;
488
Luciano Coelho12419cc2010-02-18 13:25:44 +0200489 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100490 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200491 if (ret < 0)
492 goto out_free_memmap;
493
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200494 /* Default TID/AC configuration */
495 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200497 conf_ac = &wl->conf.tx.ac_conf[i];
498 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
499 conf_ac->cw_max, conf_ac->aifsn,
500 conf_ac->tx_op_limit);
501 if (ret < 0)
502 goto out_free_memmap;
503
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 conf_tid = &wl->conf.tx.tid_conf[i];
505 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
506 conf_tid->channel_type,
507 conf_tid->tsid,
508 conf_tid->ps_scheme,
509 conf_tid->ack_policy,
510 conf_tid->apsd_conf[0],
511 conf_tid->apsd_conf[1]);
512 if (ret < 0)
513 goto out_free_memmap;
514 }
515
Luciano Coelho12419cc2010-02-18 13:25:44 +0200516 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200517 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200519 goto out_free_memmap;
520
521 /* Configure for CAM power saving (ie. always active) */
522 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
523 if (ret < 0)
524 goto out_free_memmap;
525
526 /* configure PM */
527 ret = wl1271_acx_pm_config(wl);
528 if (ret < 0)
529 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530
531 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200532
533 out_free_memmap:
534 kfree(wl->target_mem_map);
535 wl->target_mem_map = NULL;
536
537 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538}
539
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300540static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200541 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200543 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200544 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300545 u32 total = 0;
546 int i;
547
Eliad Pellerc8bde242011-02-02 09:59:35 +0200548 if (wl->bss_type == BSS_TYPE_AP_BSS)
549 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
550 sizeof(struct wl1271_fw_ap_status), false);
551 else
552 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
553 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300554
555 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
556 "drv_rx_counter = %d, tx_results_counter = %d)",
557 status->intr,
558 status->fw_rx_counter,
559 status->drv_rx_counter,
560 status->tx_results_counter);
561
562 /* update number of available TX blocks */
563 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300564 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
565 wl->tx_blocks_freed[i];
566
567 wl->tx_blocks_freed[i] =
568 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569 wl->tx_blocks_available += cnt;
570 total += cnt;
571 }
572
Ido Yariva5225502010-10-12 14:49:10 +0200573 /* if more blocks are available now, tx work can be scheduled */
574 if (total)
575 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300576
577 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200578 getnstimeofday(&ts);
579 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
580 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581}
582
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200583#define WL1271_IRQ_MAX_LOOPS 10
584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585static void wl1271_irq_work(struct work_struct *work)
586{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300588 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200589 int loopcount = WL1271_IRQ_MAX_LOOPS;
590 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591 struct wl1271 *wl =
592 container_of(work, struct wl1271, irq_work);
593
594 mutex_lock(&wl->mutex);
595
596 wl1271_debug(DEBUG_IRQ, "IRQ work");
597
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200598 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300599 goto out;
600
601 ret = wl1271_ps_elp_wakeup(wl, true);
602 if (ret < 0)
603 goto out;
604
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 spin_lock_irqsave(&wl->wl_lock, flags);
606 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
607 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
608 spin_unlock_irqrestore(&wl->wl_lock, flags);
609 loopcount--;
610
611 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200612 intr = le32_to_cpu(wl->fw_status->common.intr);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200613 if (!intr) {
614 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200615 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200616 continue;
617 }
618
619 intr &= WL1271_INTR_MASK;
620
Eliad Pellerccc83b02010-10-27 14:09:57 +0200621 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
622 wl1271_error("watchdog interrupt received! "
623 "starting recovery.");
624 ieee80211_queue_work(wl->hw, &wl->recovery_work);
625
626 /* restarting the chip. ignore any other interrupt. */
627 goto out;
628 }
629
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200630 if (intr & WL1271_ACX_INTR_DATA) {
631 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
632
633 /* check for tx results */
Eliad Pellerc8bde242011-02-02 09:59:35 +0200634 if (wl->fw_status->common.tx_results_counter !=
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200635 (wl->tx_results_count & 0xff))
636 wl1271_tx_complete(wl);
637
Ido Yariva5225502010-10-12 14:49:10 +0200638 /* Check if any tx blocks were freed */
639 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200640 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200641 /*
642 * In order to avoid starvation of the TX path,
643 * call the work function directly.
644 */
645 wl1271_tx_work_locked(wl);
646 }
647
Eliad Pellerc8bde242011-02-02 09:59:35 +0200648 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200649 }
650
651 if (intr & WL1271_ACX_INTR_EVENT_A) {
652 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
653 wl1271_event_handle(wl, 0);
654 }
655
656 if (intr & WL1271_ACX_INTR_EVENT_B) {
657 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
658 wl1271_event_handle(wl, 1);
659 }
660
661 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
662 wl1271_debug(DEBUG_IRQ,
663 "WL1271_ACX_INTR_INIT_COMPLETE");
664
665 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
666 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
667
668 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 }
670
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200671 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
672 ieee80211_queue_work(wl->hw, &wl->irq_work);
673 else
674 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
675 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 wl1271_ps_elp_sleep(wl);
678
679out:
680 mutex_unlock(&wl->mutex);
681}
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683static int wl1271_fetch_firmware(struct wl1271 *wl)
684{
685 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200686 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 int ret;
688
Arik Nemtsov166d5042010-10-16 21:44:57 +0200689 switch (wl->bss_type) {
690 case BSS_TYPE_AP_BSS:
691 fw_name = WL1271_AP_FW_NAME;
692 break;
693 case BSS_TYPE_IBSS:
694 case BSS_TYPE_STA_BSS:
695 fw_name = WL1271_FW_NAME;
696 break;
697 default:
698 wl1271_error("no compatible firmware for bss_type %d",
699 wl->bss_type);
700 return -EINVAL;
701 }
702
703 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
704
705 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706
707 if (ret < 0) {
708 wl1271_error("could not get firmware: %d", ret);
709 return ret;
710 }
711
712 if (fw->size % 4) {
713 wl1271_error("firmware size is not multiple of 32 bits: %zu",
714 fw->size);
715 ret = -EILSEQ;
716 goto out;
717 }
718
Arik Nemtsov166d5042010-10-16 21:44:57 +0200719 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300721 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722
723 if (!wl->fw) {
724 wl1271_error("could not allocate memory for the firmware");
725 ret = -ENOMEM;
726 goto out;
727 }
728
729 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200730 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731 ret = 0;
732
733out:
734 release_firmware(fw);
735
736 return ret;
737}
738
739static int wl1271_fetch_nvs(struct wl1271 *wl)
740{
741 const struct firmware *fw;
742 int ret;
743
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200744 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745
746 if (ret < 0) {
747 wl1271_error("could not get nvs file: %d", ret);
748 return ret;
749 }
750
Julia Lawall929ebd32010-05-15 23:16:39 +0200751 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752
753 if (!wl->nvs) {
754 wl1271_error("could not allocate memory for the nvs file");
755 ret = -ENOMEM;
756 goto out;
757 }
758
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200759 wl->nvs_len = fw->size;
760
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761out:
762 release_firmware(fw);
763
764 return ret;
765}
766
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200767static void wl1271_recovery_work(struct work_struct *work)
768{
769 struct wl1271 *wl =
770 container_of(work, struct wl1271, recovery_work);
771
772 mutex_lock(&wl->mutex);
773
774 if (wl->state != WL1271_STATE_ON)
775 goto out;
776
777 wl1271_info("Hardware recovery in progress.");
778
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200779 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
780 ieee80211_connection_loss(wl->vif);
781
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200782 /* reboot the chipset */
783 __wl1271_op_remove_interface(wl);
784 ieee80211_restart_hw(wl->hw);
785
786out:
787 mutex_unlock(&wl->mutex);
788}
789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790static void wl1271_fw_wakeup(struct wl1271 *wl)
791{
792 u32 elp_reg;
793
794 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300795 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796}
797
798static int wl1271_setup(struct wl1271 *wl)
799{
800 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
801 if (!wl->fw_status)
802 return -ENOMEM;
803
804 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
805 if (!wl->tx_res_if) {
806 kfree(wl->fw_status);
807 return -ENOMEM;
808 }
809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810 return 0;
811}
812
813static int wl1271_chip_wakeup(struct wl1271 *wl)
814{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300815 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 int ret = 0;
817
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200818 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200819 ret = wl1271_power_on(wl);
820 if (ret < 0)
821 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200823 wl1271_io_reset(wl);
824 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300825
826 /* We don't need a real memory partition here, because we only want
827 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300828 memset(&partition, 0, sizeof(partition));
829 partition.reg.start = REGISTERS_BASE;
830 partition.reg.size = REGISTERS_DOWN_SIZE;
831 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
833 /* ELP module wake up */
834 wl1271_fw_wakeup(wl);
835
836 /* whal_FwCtrl_BootSm() */
837
838 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200839 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840
841 /* 1. check if chip id is valid */
842
843 switch (wl->chip.id) {
844 case CHIP_ID_1271_PG10:
845 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
846 wl->chip.id);
847
848 ret = wl1271_setup(wl);
849 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200850 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851 break;
852 case CHIP_ID_1271_PG20:
853 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
854 wl->chip.id);
855
856 ret = wl1271_setup(wl);
857 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200858 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859 break;
860 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200861 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200863 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864 }
865
Arik Nemtsov166d5042010-10-16 21:44:57 +0200866 /* Make sure the firmware type matches the BSS type */
867 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300868 ret = wl1271_fetch_firmware(wl);
869 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200870 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871 }
872
873 /* No NVS from netlink, try to get it from the filesystem */
874 if (wl->nvs == NULL) {
875 ret = wl1271_fetch_nvs(wl);
876 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200877 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 }
879
880out:
881 return ret;
882}
883
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884int wl1271_plt_start(struct wl1271 *wl)
885{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200886 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 int ret;
888
889 mutex_lock(&wl->mutex);
890
891 wl1271_notice("power up");
892
893 if (wl->state != WL1271_STATE_OFF) {
894 wl1271_error("cannot go into PLT state because not "
895 "in off state: %d", wl->state);
896 ret = -EBUSY;
897 goto out;
898 }
899
Arik Nemtsov166d5042010-10-16 21:44:57 +0200900 wl->bss_type = BSS_TYPE_STA_BSS;
901
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200902 while (retries) {
903 retries--;
904 ret = wl1271_chip_wakeup(wl);
905 if (ret < 0)
906 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200908 ret = wl1271_boot(wl);
909 if (ret < 0)
910 goto power_off;
911
912 ret = wl1271_plt_init(wl);
913 if (ret < 0)
914 goto irq_disable;
915
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200916 wl->state = WL1271_STATE_PLT;
917 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100918 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 goto out;
920
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200921irq_disable:
922 wl1271_disable_interrupts(wl);
923 mutex_unlock(&wl->mutex);
924 /* Unlocking the mutex in the middle of handling is
925 inherently unsafe. In this case we deem it safe to do,
926 because we need to let any possibly pending IRQ out of
927 the system (and while we are WL1271_STATE_OFF the IRQ
928 work function will not do anything.) Also, any other
929 possible concurrent operations will fail due to the
930 current state, hence the wl1271 struct should be safe. */
931 cancel_work_sync(&wl->irq_work);
932 mutex_lock(&wl->mutex);
933power_off:
934 wl1271_power_off(wl);
935 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200937 wl1271_error("firmware boot in PLT mode failed despite %d retries",
938 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939out:
940 mutex_unlock(&wl->mutex);
941
942 return ret;
943}
944
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100945int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946{
947 int ret = 0;
948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 wl1271_notice("power down");
950
951 if (wl->state != WL1271_STATE_PLT) {
952 wl1271_error("cannot power down because not in PLT "
953 "state: %d", wl->state);
954 ret = -EBUSY;
955 goto out;
956 }
957
958 wl1271_disable_interrupts(wl);
959 wl1271_power_off(wl);
960
961 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300962 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200965 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200966 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100967 mutex_lock(&wl->mutex);
968out:
969 return ret;
970}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200971
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100972int wl1271_plt_stop(struct wl1271 *wl)
973{
974 int ret;
975
976 mutex_lock(&wl->mutex);
977 ret = __wl1271_plt_stop(wl);
978 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 return ret;
980}
981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
983{
984 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200985 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200986 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200988 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200989 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +0200990
991 /*
992 * The workqueue is slow to process the tx_queue and we need stop
993 * the queue here, otherwise the queue will get too long.
994 */
995 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
996 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
997 ieee80211_stop_queues(wl->hw);
998 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
999 }
1000
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001001 spin_unlock_irqrestore(&wl->wl_lock, flags);
1002
1003 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001004 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1005 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006
1007 /*
1008 * The chip specific setup must run before the first TX packet -
1009 * before that, the tx_work will not be initialized!
1010 */
1011
Ido Yariva5225502010-10-12 14:49:10 +02001012 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1013 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 return NETDEV_TX_OK;
1016}
1017
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001018static struct notifier_block wl1271_dev_notifier = {
1019 .notifier_call = wl1271_dev_notify,
1020};
1021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022static int wl1271_op_start(struct ieee80211_hw *hw)
1023{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001024 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1025
1026 /*
1027 * We have to delay the booting of the hardware because
1028 * we need to know the local MAC address before downloading and
1029 * initializing the firmware. The MAC address cannot be changed
1030 * after boot, and without the proper MAC address, the firmware
1031 * will not function properly.
1032 *
1033 * The MAC address is first known when the corresponding interface
1034 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001035 *
1036 * In addition, we currently have different firmwares for AP and managed
1037 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001038 */
1039
1040 return 0;
1041}
1042
1043static void wl1271_op_stop(struct ieee80211_hw *hw)
1044{
1045 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1046}
1047
1048static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1049 struct ieee80211_vif *vif)
1050{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001052 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001053 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001055 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001057 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1058 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059
1060 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001061 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001062 wl1271_debug(DEBUG_MAC80211,
1063 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001064 ret = -EBUSY;
1065 goto out;
1066 }
1067
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001068 switch (vif->type) {
1069 case NL80211_IFTYPE_STATION:
1070 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001071 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001072 break;
1073 case NL80211_IFTYPE_ADHOC:
1074 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001075 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001076 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001077 case NL80211_IFTYPE_AP:
1078 wl->bss_type = BSS_TYPE_AP_BSS;
1079 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001080 default:
1081 ret = -EOPNOTSUPP;
1082 goto out;
1083 }
1084
1085 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086
1087 if (wl->state != WL1271_STATE_OFF) {
1088 wl1271_error("cannot start because not in off state: %d",
1089 wl->state);
1090 ret = -EBUSY;
1091 goto out;
1092 }
1093
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001094 while (retries) {
1095 retries--;
1096 ret = wl1271_chip_wakeup(wl);
1097 if (ret < 0)
1098 goto power_off;
1099
1100 ret = wl1271_boot(wl);
1101 if (ret < 0)
1102 goto power_off;
1103
1104 ret = wl1271_hw_init(wl);
1105 if (ret < 0)
1106 goto irq_disable;
1107
Eliad Peller71125ab2010-10-28 21:46:43 +02001108 booted = true;
1109 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001111irq_disable:
1112 wl1271_disable_interrupts(wl);
1113 mutex_unlock(&wl->mutex);
1114 /* Unlocking the mutex in the middle of handling is
1115 inherently unsafe. In this case we deem it safe to do,
1116 because we need to let any possibly pending IRQ out of
1117 the system (and while we are WL1271_STATE_OFF the IRQ
1118 work function will not do anything.) Also, any other
1119 possible concurrent operations will fail due to the
1120 current state, hence the wl1271 struct should be safe. */
1121 cancel_work_sync(&wl->irq_work);
1122 mutex_lock(&wl->mutex);
1123power_off:
1124 wl1271_power_off(wl);
1125 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126
Eliad Peller71125ab2010-10-28 21:46:43 +02001127 if (!booted) {
1128 wl1271_error("firmware boot failed despite %d retries",
1129 WL1271_BOOT_RETRIES);
1130 goto out;
1131 }
1132
1133 wl->vif = vif;
1134 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001135 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001136
1137 /* update hw/fw version info in wiphy struct */
1138 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001139 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001140 sizeof(wiphy->fw_version));
1141
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001142 /*
1143 * Now we know if 11a is supported (info from the NVS), so disable
1144 * 11a channels if not supported
1145 */
1146 if (!wl->enable_11a)
1147 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1148
1149 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1150 wl->enable_11a ? "" : "not ");
1151
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001152out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 mutex_unlock(&wl->mutex);
1154
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001155 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001156 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158 return ret;
1159}
1160
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001161static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001162{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163 int i;
1164
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001165 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001167 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001169 list_del(&wl->list);
1170
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001171 WARN_ON(wl->state != WL1271_STATE_ON);
1172
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001173 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001174 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001175 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001176
Luciano Coelho08688d62010-07-08 17:50:07 +03001177 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001178 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1179 kfree(wl->scan.scanned_ch);
1180 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001181 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001182 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 }
1184
1185 wl->state = WL1271_STATE_OFF;
1186
1187 wl1271_disable_interrupts(wl);
1188
1189 mutex_unlock(&wl->mutex);
1190
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001191 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 cancel_work_sync(&wl->irq_work);
1193 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001194 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001195 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196
1197 mutex_lock(&wl->mutex);
1198
1199 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001200 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 wl1271_power_off(wl);
1202
1203 memset(wl->bssid, 0, ETH_ALEN);
1204 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1205 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001207 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001208 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209
1210 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001211 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1213 wl->tx_blocks_available = 0;
1214 wl->tx_results_count = 0;
1215 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001216 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001217 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 wl->time_offset = 0;
1219 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001220 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001221 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001222 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001223 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001224 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001225 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001226
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227 for (i = 0; i < NUM_TX_QUEUES; i++)
1228 wl->tx_blocks_freed[i] = 0;
1229
1230 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001231
1232 kfree(wl->fw_status);
1233 wl->fw_status = NULL;
1234 kfree(wl->tx_res_if);
1235 wl->tx_res_if = NULL;
1236 kfree(wl->target_mem_map);
1237 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001238}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001239
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001240static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1241 struct ieee80211_vif *vif)
1242{
1243 struct wl1271 *wl = hw->priv;
1244
1245 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001246 /*
1247 * wl->vif can be null here if someone shuts down the interface
1248 * just when hardware recovery has been started.
1249 */
1250 if (wl->vif) {
1251 WARN_ON(wl->vif != vif);
1252 __wl1271_op_remove_interface(wl);
1253 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001254
Juuso Oikarinen67353292010-11-18 15:19:02 +02001255 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257}
1258
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001259static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1260{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001261 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001262
1263 /* combine requested filters with current filter config */
1264 filters = wl->filters | filters;
1265
1266 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1267
1268 if (filters & FIF_PROMISC_IN_BSS) {
1269 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1270 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1271 wl->rx_config |= CFG_BSSID_FILTER_EN;
1272 }
1273 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1274 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1275 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1276 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1277 }
1278 if (filters & FIF_OTHER_BSS) {
1279 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1280 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1281 }
1282 if (filters & FIF_CONTROL) {
1283 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1284 wl->rx_filter |= CFG_RX_CTL_EN;
1285 }
1286 if (filters & FIF_FCSFAIL) {
1287 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1288 wl->rx_filter |= CFG_RX_FCS_ERROR;
1289 }
1290}
1291
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001292static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001293{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001294 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001295 /* we need to use a dummy BSSID for now */
1296 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1297 0xad, 0xbe, 0xef };
1298
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001299 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1300
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001301 /* pass through frames from all BSS */
1302 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1303
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001304 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001305 if (ret < 0)
1306 goto out;
1307
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001308 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001309
1310out:
1311 return ret;
1312}
1313
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001314static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001315{
1316 int ret;
1317
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001318 /*
1319 * One of the side effects of the JOIN command is that is clears
1320 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1321 * to a WPA/WPA2 access point will therefore kill the data-path.
1322 * Currently there is no supported scenario for JOIN during
1323 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1324 * must be handled somehow.
1325 *
1326 */
1327 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1328 wl1271_info("JOIN while associated.");
1329
1330 if (set_assoc)
1331 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1332
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001333 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1334 if (ret < 0)
1335 goto out;
1336
1337 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1338
1339 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1340 goto out;
1341
1342 /*
1343 * The join command disable the keep-alive mode, shut down its process,
1344 * and also clear the template config, so we need to reset it all after
1345 * the join. The acx_aid starts the keep-alive process, and the order
1346 * of the commands below is relevant.
1347 */
1348 ret = wl1271_acx_keep_alive_mode(wl, true);
1349 if (ret < 0)
1350 goto out;
1351
1352 ret = wl1271_acx_aid(wl, wl->aid);
1353 if (ret < 0)
1354 goto out;
1355
1356 ret = wl1271_cmd_build_klv_null_data(wl);
1357 if (ret < 0)
1358 goto out;
1359
1360 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1361 ACX_KEEP_ALIVE_TPL_VALID);
1362 if (ret < 0)
1363 goto out;
1364
1365out:
1366 return ret;
1367}
1368
1369static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001370{
1371 int ret;
1372
1373 /* to stop listening to a channel, we disconnect */
1374 ret = wl1271_cmd_disconnect(wl);
1375 if (ret < 0)
1376 goto out;
1377
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001378 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001379 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001380
1381 /* stop filterting packets based on bssid */
1382 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001383
1384out:
1385 return ret;
1386}
1387
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001388static void wl1271_set_band_rate(struct wl1271 *wl)
1389{
1390 if (wl->band == IEEE80211_BAND_2GHZ)
1391 wl->basic_rate_set = wl->conf.tx.basic_rate;
1392 else
1393 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1394}
1395
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001396static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001397{
1398 int ret;
1399
1400 if (idle) {
1401 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1402 ret = wl1271_unjoin(wl);
1403 if (ret < 0)
1404 goto out;
1405 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001406 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001407 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001408 if (ret < 0)
1409 goto out;
1410 ret = wl1271_acx_keep_alive_config(
1411 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1412 ACX_KEEP_ALIVE_TPL_INVALID);
1413 if (ret < 0)
1414 goto out;
1415 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1416 } else {
1417 /* increment the session counter */
1418 wl->session_counter++;
1419 if (wl->session_counter >= SESSION_COUNTER_MAX)
1420 wl->session_counter = 0;
1421 ret = wl1271_dummy_join(wl);
1422 if (ret < 0)
1423 goto out;
1424 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1425 }
1426
1427out:
1428 return ret;
1429}
1430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1432{
1433 struct wl1271 *wl = hw->priv;
1434 struct ieee80211_conf *conf = &hw->conf;
1435 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001436 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437
1438 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1439
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001440 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1441 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442 channel,
1443 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001444 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001445 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1446 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001448 /*
1449 * mac80211 will go to idle nearly immediately after transmitting some
1450 * frames, such as the deauth. To make sure those frames reach the air,
1451 * wait here until the TX queue is fully flushed.
1452 */
1453 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1454 (conf->flags & IEEE80211_CONF_IDLE))
1455 wl1271_tx_flush(wl);
1456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 mutex_lock(&wl->mutex);
1458
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001459 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1460 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001461 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001462 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001463
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001464 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1465
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 ret = wl1271_ps_elp_wakeup(wl, false);
1467 if (ret < 0)
1468 goto out;
1469
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001470 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001471 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1472 ((wl->band != conf->channel->band) ||
1473 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001474 wl->band = conf->channel->band;
1475 wl->channel = channel;
1476
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001477 if (!is_ap) {
1478 /*
1479 * FIXME: the mac80211 should really provide a fixed
1480 * rate to use here. for now, just use the smallest
1481 * possible rate for the band as a fixed rate for
1482 * association frames and other control messages.
1483 */
1484 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1485 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001486
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001487 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1488 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001489 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001490 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001491 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001492
1493 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1494 ret = wl1271_join(wl, false);
1495 if (ret < 0)
1496 wl1271_warning("cmd join on channel "
1497 "failed %d", ret);
1498 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001499 }
1500 }
1501
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001502 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1503 ret = wl1271_sta_handle_idle(wl,
1504 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001505 if (ret < 0)
1506 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 }
1508
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001509 /*
1510 * if mac80211 changes the PSM mode, make sure the mode is not
1511 * incorrectly changed after the pspoll failure active window.
1512 */
1513 if (changed & IEEE80211_CONF_CHANGE_PS)
1514 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1515
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001516 if (conf->flags & IEEE80211_CONF_PS &&
1517 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1518 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
1520 /*
1521 * We enter PSM only if we're already associated.
1522 * If we're not, we'll enter it when joining an SSID,
1523 * through the bss_info_changed() hook.
1524 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001525 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001526 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001527 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001528 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001529 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001531 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001532 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001534 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001536 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001537 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001538 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 }
1540
1541 if (conf->power_level != wl->power_level) {
1542 ret = wl1271_acx_tx_power(wl, conf->power_level);
1543 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001544 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545
1546 wl->power_level = conf->power_level;
1547 }
1548
1549out_sleep:
1550 wl1271_ps_elp_sleep(wl);
1551
1552out:
1553 mutex_unlock(&wl->mutex);
1554
1555 return ret;
1556}
1557
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001558struct wl1271_filter_params {
1559 bool enabled;
1560 int mc_list_length;
1561 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1562};
1563
Jiri Pirko22bedad32010-04-01 21:22:57 +00001564static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1565 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001566{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001567 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001568 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001569 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001570
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001571 if (unlikely(wl->state == WL1271_STATE_OFF))
1572 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001573
Juuso Oikarinen74441132009-10-13 12:47:53 +03001574 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001575 if (!fp) {
1576 wl1271_error("Out of memory setting filters.");
1577 return 0;
1578 }
1579
1580 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001581 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001582 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1583 fp->enabled = false;
1584 } else {
1585 fp->enabled = true;
1586 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001587 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001588 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001589 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001590 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001591 }
1592
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001593 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001594}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001596#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1597 FIF_ALLMULTI | \
1598 FIF_FCSFAIL | \
1599 FIF_BCN_PRBRESP_PROMISC | \
1600 FIF_CONTROL | \
1601 FIF_OTHER_BSS)
1602
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001603static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1604 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001605 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001607 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001609 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
Arik Nemtsov7d057862010-10-16 19:25:35 +02001611 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1612 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001613
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001614 mutex_lock(&wl->mutex);
1615
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001616 *total &= WL1271_SUPPORTED_FILTERS;
1617 changed &= WL1271_SUPPORTED_FILTERS;
1618
1619 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001620 goto out;
1621
1622 ret = wl1271_ps_elp_wakeup(wl, false);
1623 if (ret < 0)
1624 goto out;
1625
Arik Nemtsov7d057862010-10-16 19:25:35 +02001626 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1627 if (*total & FIF_ALLMULTI)
1628 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1629 else if (fp)
1630 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1631 fp->mc_list,
1632 fp->mc_list_length);
1633 if (ret < 0)
1634 goto out_sleep;
1635 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001636
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001637 /* determine, whether supported filter values have changed */
1638 if (changed == 0)
1639 goto out_sleep;
1640
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001641 /* configure filters */
1642 wl->filters = *total;
1643 wl1271_configure_filters(wl, 0);
1644
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001645 /* apply configured filters */
1646 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1647 if (ret < 0)
1648 goto out_sleep;
1649
1650out_sleep:
1651 wl1271_ps_elp_sleep(wl);
1652
1653out:
1654 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001655 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656}
1657
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001658static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1659 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1660 u16 tx_seq_16)
1661{
1662 struct wl1271_ap_key *ap_key;
1663 int i;
1664
1665 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1666
1667 if (key_size > MAX_KEY_SIZE)
1668 return -EINVAL;
1669
1670 /*
1671 * Find next free entry in ap_keys. Also check we are not replacing
1672 * an existing key.
1673 */
1674 for (i = 0; i < MAX_NUM_KEYS; i++) {
1675 if (wl->recorded_ap_keys[i] == NULL)
1676 break;
1677
1678 if (wl->recorded_ap_keys[i]->id == id) {
1679 wl1271_warning("trying to record key replacement");
1680 return -EINVAL;
1681 }
1682 }
1683
1684 if (i == MAX_NUM_KEYS)
1685 return -EBUSY;
1686
1687 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1688 if (!ap_key)
1689 return -ENOMEM;
1690
1691 ap_key->id = id;
1692 ap_key->key_type = key_type;
1693 ap_key->key_size = key_size;
1694 memcpy(ap_key->key, key, key_size);
1695 ap_key->hlid = hlid;
1696 ap_key->tx_seq_32 = tx_seq_32;
1697 ap_key->tx_seq_16 = tx_seq_16;
1698
1699 wl->recorded_ap_keys[i] = ap_key;
1700 return 0;
1701}
1702
1703static void wl1271_free_ap_keys(struct wl1271 *wl)
1704{
1705 int i;
1706
1707 for (i = 0; i < MAX_NUM_KEYS; i++) {
1708 kfree(wl->recorded_ap_keys[i]);
1709 wl->recorded_ap_keys[i] = NULL;
1710 }
1711}
1712
1713static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1714{
1715 int i, ret = 0;
1716 struct wl1271_ap_key *key;
1717 bool wep_key_added = false;
1718
1719 for (i = 0; i < MAX_NUM_KEYS; i++) {
1720 if (wl->recorded_ap_keys[i] == NULL)
1721 break;
1722
1723 key = wl->recorded_ap_keys[i];
1724 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1725 key->id, key->key_type,
1726 key->key_size, key->key,
1727 key->hlid, key->tx_seq_32,
1728 key->tx_seq_16);
1729 if (ret < 0)
1730 goto out;
1731
1732 if (key->key_type == KEY_WEP)
1733 wep_key_added = true;
1734 }
1735
1736 if (wep_key_added) {
1737 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1738 if (ret < 0)
1739 goto out;
1740 }
1741
1742out:
1743 wl1271_free_ap_keys(wl);
1744 return ret;
1745}
1746
1747static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1748 u8 key_size, const u8 *key, u32 tx_seq_32,
1749 u16 tx_seq_16, struct ieee80211_sta *sta)
1750{
1751 int ret;
1752 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1753
1754 if (is_ap) {
1755 struct wl1271_station *wl_sta;
1756 u8 hlid;
1757
1758 if (sta) {
1759 wl_sta = (struct wl1271_station *)sta->drv_priv;
1760 hlid = wl_sta->hlid;
1761 } else {
1762 hlid = WL1271_AP_BROADCAST_HLID;
1763 }
1764
1765 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1766 /*
1767 * We do not support removing keys after AP shutdown.
1768 * Pretend we do to make mac80211 happy.
1769 */
1770 if (action != KEY_ADD_OR_REPLACE)
1771 return 0;
1772
1773 ret = wl1271_record_ap_key(wl, id,
1774 key_type, key_size,
1775 key, hlid, tx_seq_32,
1776 tx_seq_16);
1777 } else {
1778 ret = wl1271_cmd_set_ap_key(wl, action,
1779 id, key_type, key_size,
1780 key, hlid, tx_seq_32,
1781 tx_seq_16);
1782 }
1783
1784 if (ret < 0)
1785 return ret;
1786 } else {
1787 const u8 *addr;
1788 static const u8 bcast_addr[ETH_ALEN] = {
1789 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1790 };
1791
1792 addr = sta ? sta->addr : bcast_addr;
1793
1794 if (is_zero_ether_addr(addr)) {
1795 /* We dont support TX only encryption */
1796 return -EOPNOTSUPP;
1797 }
1798
1799 /* The wl1271 does not allow to remove unicast keys - they
1800 will be cleared automatically on next CMD_JOIN. Ignore the
1801 request silently, as we dont want the mac80211 to emit
1802 an error message. */
1803 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1804 return 0;
1805
1806 ret = wl1271_cmd_set_sta_key(wl, action,
1807 id, key_type, key_size,
1808 key, addr, tx_seq_32,
1809 tx_seq_16);
1810 if (ret < 0)
1811 return ret;
1812
1813 /* the default WEP key needs to be configured at least once */
1814 if (key_type == KEY_WEP) {
1815 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1816 wl->default_key);
1817 if (ret < 0)
1818 return ret;
1819 }
1820 }
1821
1822 return 0;
1823}
1824
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1826 struct ieee80211_vif *vif,
1827 struct ieee80211_sta *sta,
1828 struct ieee80211_key_conf *key_conf)
1829{
1830 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001832 u32 tx_seq_32 = 0;
1833 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834 u8 key_type;
1835
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1837
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001838 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001840 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 key_conf->keylen, key_conf->flags);
1842 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1843
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 mutex_lock(&wl->mutex);
1845
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001846 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1847 ret = -EAGAIN;
1848 goto out_unlock;
1849 }
1850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 ret = wl1271_ps_elp_wakeup(wl, false);
1852 if (ret < 0)
1853 goto out_unlock;
1854
Johannes Berg97359d12010-08-10 09:46:38 +02001855 switch (key_conf->cipher) {
1856 case WLAN_CIPHER_SUITE_WEP40:
1857 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001858 key_type = KEY_WEP;
1859
1860 key_conf->hw_key_idx = key_conf->keyidx;
1861 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001862 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 key_type = KEY_TKIP;
1864
1865 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001866 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1867 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001869 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870 key_type = KEY_AES;
1871
1872 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001873 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1874 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001876 case WL1271_CIPHER_SUITE_GEM:
1877 key_type = KEY_GEM;
1878 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1879 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1880 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001882 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883
1884 ret = -EOPNOTSUPP;
1885 goto out_sleep;
1886 }
1887
1888 switch (cmd) {
1889 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001890 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1891 key_conf->keyidx, key_type,
1892 key_conf->keylen, key_conf->key,
1893 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001894 if (ret < 0) {
1895 wl1271_error("Could not add or replace key");
1896 goto out_sleep;
1897 }
1898 break;
1899
1900 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001901 ret = wl1271_set_key(wl, KEY_REMOVE,
1902 key_conf->keyidx, key_type,
1903 key_conf->keylen, key_conf->key,
1904 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001905 if (ret < 0) {
1906 wl1271_error("Could not remove key");
1907 goto out_sleep;
1908 }
1909 break;
1910
1911 default:
1912 wl1271_error("Unsupported key cmd 0x%x", cmd);
1913 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914 break;
1915 }
1916
1917out_sleep:
1918 wl1271_ps_elp_sleep(wl);
1919
1920out_unlock:
1921 mutex_unlock(&wl->mutex);
1922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 return ret;
1924}
1925
1926static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001927 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 struct cfg80211_scan_request *req)
1929{
1930 struct wl1271 *wl = hw->priv;
1931 int ret;
1932 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001933 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934
1935 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1936
1937 if (req->n_ssids) {
1938 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001939 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 }
1941
1942 mutex_lock(&wl->mutex);
1943
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001944 if (wl->state == WL1271_STATE_OFF) {
1945 /*
1946 * We cannot return -EBUSY here because cfg80211 will expect
1947 * a call to ieee80211_scan_completed if we do - in this case
1948 * there won't be any call.
1949 */
1950 ret = -EAGAIN;
1951 goto out;
1952 }
1953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 ret = wl1271_ps_elp_wakeup(wl, false);
1955 if (ret < 0)
1956 goto out;
1957
Luciano Coelho5924f892010-08-04 03:46:22 +03001958 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959
1960 wl1271_ps_elp_sleep(wl);
1961
1962out:
1963 mutex_unlock(&wl->mutex);
1964
1965 return ret;
1966}
1967
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001968static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1969{
1970 struct wl1271 *wl = hw->priv;
1971 int ret = 0;
1972
1973 mutex_lock(&wl->mutex);
1974
1975 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1976 ret = -EAGAIN;
1977 goto out;
1978 }
1979
1980 ret = wl1271_ps_elp_wakeup(wl, false);
1981 if (ret < 0)
1982 goto out;
1983
1984 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1985 if (ret < 0)
1986 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1987
1988 wl1271_ps_elp_sleep(wl);
1989
1990out:
1991 mutex_unlock(&wl->mutex);
1992
1993 return ret;
1994}
1995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1997{
1998 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001999 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002000
2001 mutex_lock(&wl->mutex);
2002
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002003 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2004 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002005 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002006 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 ret = wl1271_ps_elp_wakeup(wl, false);
2009 if (ret < 0)
2010 goto out;
2011
2012 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2013 if (ret < 0)
2014 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2015
2016 wl1271_ps_elp_sleep(wl);
2017
2018out:
2019 mutex_unlock(&wl->mutex);
2020
2021 return ret;
2022}
2023
Arik Nemtsove78a2872010-10-16 19:07:21 +02002024static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002025 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002026{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002027 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002028
2029 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002030 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002031 if (ptr[0] == WLAN_EID_SSID) {
2032 wl->ssid_len = ptr[1];
2033 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002034 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002035 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002036 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002037 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002038
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002039 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002040 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002041}
2042
Arik Nemtsove78a2872010-10-16 19:07:21 +02002043static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2044 struct ieee80211_bss_conf *bss_conf,
2045 u32 changed)
2046{
2047 int ret = 0;
2048
2049 if (changed & BSS_CHANGED_ERP_SLOT) {
2050 if (bss_conf->use_short_slot)
2051 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2052 else
2053 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2054 if (ret < 0) {
2055 wl1271_warning("Set slot time failed %d", ret);
2056 goto out;
2057 }
2058 }
2059
2060 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2061 if (bss_conf->use_short_preamble)
2062 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2063 else
2064 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2065 }
2066
2067 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2068 if (bss_conf->use_cts_prot)
2069 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2070 else
2071 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2072 if (ret < 0) {
2073 wl1271_warning("Set ctsprotect failed %d", ret);
2074 goto out;
2075 }
2076 }
2077
2078out:
2079 return ret;
2080}
2081
2082static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2083 struct ieee80211_vif *vif,
2084 struct ieee80211_bss_conf *bss_conf,
2085 u32 changed)
2086{
2087 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2088 int ret = 0;
2089
2090 if ((changed & BSS_CHANGED_BEACON_INT)) {
2091 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2092 bss_conf->beacon_int);
2093
2094 wl->beacon_int = bss_conf->beacon_int;
2095 }
2096
2097 if ((changed & BSS_CHANGED_BEACON)) {
2098 struct ieee80211_hdr *hdr;
2099 int ieoffset = offsetof(struct ieee80211_mgmt,
2100 u.beacon.variable);
2101 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2102 u16 tmpl_id;
2103
2104 if (!beacon)
2105 goto out;
2106
2107 wl1271_debug(DEBUG_MASTER, "beacon updated");
2108
2109 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2110 if (ret < 0) {
2111 dev_kfree_skb(beacon);
2112 goto out;
2113 }
2114 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2115 CMD_TEMPL_BEACON;
2116 ret = wl1271_cmd_template_set(wl, tmpl_id,
2117 beacon->data,
2118 beacon->len, 0,
2119 wl1271_tx_min_rate_get(wl));
2120 if (ret < 0) {
2121 dev_kfree_skb(beacon);
2122 goto out;
2123 }
2124
2125 hdr = (struct ieee80211_hdr *) beacon->data;
2126 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2127 IEEE80211_STYPE_PROBE_RESP);
2128
2129 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2130 CMD_TEMPL_PROBE_RESPONSE;
2131 ret = wl1271_cmd_template_set(wl,
2132 tmpl_id,
2133 beacon->data,
2134 beacon->len, 0,
2135 wl1271_tx_min_rate_get(wl));
2136 dev_kfree_skb(beacon);
2137 if (ret < 0)
2138 goto out;
2139 }
2140
2141out:
2142 return ret;
2143}
2144
2145/* AP mode changes */
2146static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002147 struct ieee80211_vif *vif,
2148 struct ieee80211_bss_conf *bss_conf,
2149 u32 changed)
2150{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002151 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002152
Arik Nemtsove78a2872010-10-16 19:07:21 +02002153 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2154 u32 rates = bss_conf->basic_rates;
2155 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002156
Arik Nemtsove78a2872010-10-16 19:07:21 +02002157 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2158 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2159 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2160 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161
Arik Nemtsove78a2872010-10-16 19:07:21 +02002162 /* update the AP management rate policy with the new rates */
2163 mgmt_rc.enabled_rates = wl->basic_rate_set;
2164 mgmt_rc.long_retry_limit = 10;
2165 mgmt_rc.short_retry_limit = 10;
2166 mgmt_rc.aflags = 0;
2167 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2168 ACX_TX_AP_MODE_MGMT_RATE);
2169 if (ret < 0) {
2170 wl1271_error("AP mgmt policy change failed %d", ret);
2171 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002172 }
2173 }
2174
Arik Nemtsove78a2872010-10-16 19:07:21 +02002175 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2176 if (ret < 0)
2177 goto out;
2178
2179 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2180 if (bss_conf->enable_beacon) {
2181 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2182 ret = wl1271_cmd_start_bss(wl);
2183 if (ret < 0)
2184 goto out;
2185
2186 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2187 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002188
2189 ret = wl1271_ap_init_hwenc(wl);
2190 if (ret < 0)
2191 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002192 }
2193 } else {
2194 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2195 ret = wl1271_cmd_stop_bss(wl);
2196 if (ret < 0)
2197 goto out;
2198
2199 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2200 wl1271_debug(DEBUG_AP, "stopped AP");
2201 }
2202 }
2203 }
2204
2205 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2206 if (ret < 0)
2207 goto out;
2208out:
2209 return;
2210}
2211
2212/* STA/IBSS mode changes */
2213static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2214 struct ieee80211_vif *vif,
2215 struct ieee80211_bss_conf *bss_conf,
2216 u32 changed)
2217{
2218 bool do_join = false, set_assoc = false;
2219 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002220 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002221 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002222 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002223 bool sta_exists = false;
2224 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002225
2226 if (is_ibss) {
2227 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2228 changed);
2229 if (ret < 0)
2230 goto out;
2231 }
2232
2233 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2234 do_join = true;
2235
2236 /* Need to update the SSID (for filtering etc) */
2237 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2238 do_join = true;
2239
2240 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002241 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2242 bss_conf->enable_beacon ? "enabled" : "disabled");
2243
2244 if (bss_conf->enable_beacon)
2245 wl->set_bss_type = BSS_TYPE_IBSS;
2246 else
2247 wl->set_bss_type = BSS_TYPE_STA_BSS;
2248 do_join = true;
2249 }
2250
Arik Nemtsove78a2872010-10-16 19:07:21 +02002251 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002252 bool enable = false;
2253 if (bss_conf->cqm_rssi_thold)
2254 enable = true;
2255 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2256 bss_conf->cqm_rssi_thold,
2257 bss_conf->cqm_rssi_hyst);
2258 if (ret < 0)
2259 goto out;
2260 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2261 }
2262
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002263 if ((changed & BSS_CHANGED_BSSID) &&
2264 /*
2265 * Now we know the correct bssid, so we send a new join command
2266 * and enable the BSSID filter
2267 */
2268 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002269 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002270
Eliad Pellerfa287b82010-12-26 09:27:50 +01002271 if (!is_zero_ether_addr(wl->bssid)) {
2272 ret = wl1271_cmd_build_null_data(wl);
2273 if (ret < 0)
2274 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002275
Eliad Pellerfa287b82010-12-26 09:27:50 +01002276 ret = wl1271_build_qos_null_data(wl);
2277 if (ret < 0)
2278 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002279
Eliad Pellerfa287b82010-12-26 09:27:50 +01002280 /* filter out all packets not from this BSSID */
2281 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002282
Eliad Pellerfa287b82010-12-26 09:27:50 +01002283 /* Need to update the BSSID (for filtering etc) */
2284 do_join = true;
2285 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002286 }
2287
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002288 rcu_read_lock();
2289 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2290 if (sta) {
2291 /* save the supp_rates of the ap */
2292 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2293 if (sta->ht_cap.ht_supported)
2294 sta_rate_set |=
2295 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002296 sta_ht_cap = sta->ht_cap;
2297 sta_exists = true;
2298 }
2299 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002300
Arik Nemtsova1008852011-02-12 23:24:20 +02002301 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002302 /* handle new association with HT and HT information change */
2303 if ((changed & BSS_CHANGED_HT) &&
2304 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002305 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002306 true);
2307 if (ret < 0) {
2308 wl1271_warning("Set ht cap true failed %d",
2309 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002310 goto out;
2311 }
2312 ret = wl1271_acx_set_ht_information(wl,
2313 bss_conf->ht_operation_mode);
2314 if (ret < 0) {
2315 wl1271_warning("Set ht information failed %d",
2316 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002317 goto out;
2318 }
2319 }
2320 /* handle new association without HT and disassociation */
2321 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002322 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002323 false);
2324 if (ret < 0) {
2325 wl1271_warning("Set ht cap false failed %d",
2326 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002327 goto out;
2328 }
2329 }
2330 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002331
Arik Nemtsove78a2872010-10-16 19:07:21 +02002332 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002334 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002335 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002337 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002339 wl->ps_poll_failures = 0;
2340
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002341 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002342 * use basic rates from AP, and determine lowest rate
2343 * to use with control frames.
2344 */
2345 rates = bss_conf->basic_rates;
2346 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2347 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002348 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002349 if (sta_rate_set)
2350 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2351 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002352 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002353 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002354 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002355
2356 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002357 * with wl1271, we don't need to update the
2358 * beacon_int and dtim_period, because the firmware
2359 * updates it by itself when the first beacon is
2360 * received after a join.
2361 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2363 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002364 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002366 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002367 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002368 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002369 dev_kfree_skb(wl->probereq);
2370 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2371 ieoffset = offsetof(struct ieee80211_mgmt,
2372 u.probe_req.variable);
2373 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002374
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002375 /* enable the connection monitoring feature */
2376 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002378 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379
2380 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002381 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2382 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002383 enum wl1271_cmd_ps_mode mode;
2384
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002385 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002386 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002387 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002388 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002390 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002392 } else {
2393 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002394 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002395 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002396 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002397
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002398 /* free probe-request template */
2399 dev_kfree_skb(wl->probereq);
2400 wl->probereq = NULL;
2401
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002402 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002403 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002404
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002405 /* revert back to minimum rates for the current band */
2406 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002407 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002408 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002409 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002410 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002411
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002412 /* disable connection monitor features */
2413 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002414
2415 /* Disable the keep-alive feature */
2416 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002417 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002418 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002419
2420 /* restore the bssid filter and go to dummy bssid */
2421 wl1271_unjoin(wl);
2422 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 }
2424 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002425
Arik Nemtsove78a2872010-10-16 19:07:21 +02002426 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2427 if (ret < 0)
2428 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002429
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002430 if (changed & BSS_CHANGED_ARP_FILTER) {
2431 __be32 addr = bss_conf->arp_addr_list[0];
2432 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2433
Eliad Pellerc5312772010-12-09 11:31:27 +02002434 if (bss_conf->arp_addr_cnt == 1 &&
2435 bss_conf->arp_filter_enabled) {
2436 /*
2437 * The template should have been configured only upon
2438 * association. however, it seems that the correct ip
2439 * isn't being set (when sending), so we have to
2440 * reconfigure the template upon every ip change.
2441 */
2442 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2443 if (ret < 0) {
2444 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002445 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002446 }
2447
2448 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002449 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002450 addr);
2451 } else
2452 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002453
2454 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002455 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002456 }
2457
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002458 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002459 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002460 if (ret < 0) {
2461 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002462 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002463 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002464 }
2465
Arik Nemtsove78a2872010-10-16 19:07:21 +02002466out:
2467 return;
2468}
2469
2470static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2471 struct ieee80211_vif *vif,
2472 struct ieee80211_bss_conf *bss_conf,
2473 u32 changed)
2474{
2475 struct wl1271 *wl = hw->priv;
2476 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2477 int ret;
2478
2479 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2480 (int)changed);
2481
2482 mutex_lock(&wl->mutex);
2483
2484 if (unlikely(wl->state == WL1271_STATE_OFF))
2485 goto out;
2486
2487 ret = wl1271_ps_elp_wakeup(wl, false);
2488 if (ret < 0)
2489 goto out;
2490
2491 if (is_ap)
2492 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2493 else
2494 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496 wl1271_ps_elp_sleep(wl);
2497
2498out:
2499 mutex_unlock(&wl->mutex);
2500}
2501
Kalle Valoc6999d82010-02-18 13:25:41 +02002502static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2503 const struct ieee80211_tx_queue_params *params)
2504{
2505 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002506 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002507 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002508
2509 mutex_lock(&wl->mutex);
2510
2511 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2512
Kalle Valo4695dc92010-03-18 12:26:38 +02002513 if (params->uapsd)
2514 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2515 else
2516 ps_scheme = CONF_PS_SCHEME_LEGACY;
2517
Arik Nemtsov488fc542010-10-16 20:33:45 +02002518 if (wl->state == WL1271_STATE_OFF) {
2519 /*
2520 * If the state is off, the parameters will be recorded and
2521 * configured on init. This happens in AP-mode.
2522 */
2523 struct conf_tx_ac_category *conf_ac =
2524 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2525 struct conf_tx_tid *conf_tid =
2526 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2527
2528 conf_ac->ac = wl1271_tx_get_queue(queue);
2529 conf_ac->cw_min = (u8)params->cw_min;
2530 conf_ac->cw_max = params->cw_max;
2531 conf_ac->aifsn = params->aifs;
2532 conf_ac->tx_op_limit = params->txop << 5;
2533
2534 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2535 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2536 conf_tid->tsid = wl1271_tx_get_queue(queue);
2537 conf_tid->ps_scheme = ps_scheme;
2538 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2539 conf_tid->apsd_conf[0] = 0;
2540 conf_tid->apsd_conf[1] = 0;
2541 } else {
2542 ret = wl1271_ps_elp_wakeup(wl, false);
2543 if (ret < 0)
2544 goto out;
2545
2546 /*
2547 * the txop is confed in units of 32us by the mac80211,
2548 * we need us
2549 */
2550 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2551 params->cw_min, params->cw_max,
2552 params->aifs, params->txop << 5);
2553 if (ret < 0)
2554 goto out_sleep;
2555
2556 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2557 CONF_CHANNEL_TYPE_EDCF,
2558 wl1271_tx_get_queue(queue),
2559 ps_scheme, CONF_ACK_POLICY_LEGACY,
2560 0, 0);
2561 if (ret < 0)
2562 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002563
2564out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002565 wl1271_ps_elp_sleep(wl);
2566 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002567
2568out:
2569 mutex_unlock(&wl->mutex);
2570
2571 return ret;
2572}
2573
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002574static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2575{
2576
2577 struct wl1271 *wl = hw->priv;
2578 u64 mactime = ULLONG_MAX;
2579 int ret;
2580
2581 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2582
2583 mutex_lock(&wl->mutex);
2584
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002585 if (unlikely(wl->state == WL1271_STATE_OFF))
2586 goto out;
2587
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002588 ret = wl1271_ps_elp_wakeup(wl, false);
2589 if (ret < 0)
2590 goto out;
2591
2592 ret = wl1271_acx_tsf_info(wl, &mactime);
2593 if (ret < 0)
2594 goto out_sleep;
2595
2596out_sleep:
2597 wl1271_ps_elp_sleep(wl);
2598
2599out:
2600 mutex_unlock(&wl->mutex);
2601 return mactime;
2602}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002603
John W. Linvilleece550d2010-07-28 16:41:06 -04002604static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2605 struct survey_info *survey)
2606{
2607 struct wl1271 *wl = hw->priv;
2608 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002609
John W. Linvilleece550d2010-07-28 16:41:06 -04002610 if (idx != 0)
2611 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002612
John W. Linvilleece550d2010-07-28 16:41:06 -04002613 survey->channel = conf->channel;
2614 survey->filled = SURVEY_INFO_NOISE_DBM;
2615 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002616
John W. Linvilleece550d2010-07-28 16:41:06 -04002617 return 0;
2618}
2619
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002620static int wl1271_allocate_hlid(struct wl1271 *wl,
2621 struct ieee80211_sta *sta,
2622 u8 *hlid)
2623{
2624 struct wl1271_station *wl_sta;
2625 int id;
2626
2627 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2628 if (id >= AP_MAX_STATIONS) {
2629 wl1271_warning("could not allocate HLID - too much stations");
2630 return -EBUSY;
2631 }
2632
2633 wl_sta = (struct wl1271_station *)sta->drv_priv;
2634
2635 __set_bit(id, wl->ap_hlid_map);
2636 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2637 *hlid = wl_sta->hlid;
2638 return 0;
2639}
2640
2641static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2642{
2643 int id = hlid - WL1271_AP_STA_HLID_START;
2644
2645 __clear_bit(id, wl->ap_hlid_map);
2646}
2647
2648static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2649 struct ieee80211_vif *vif,
2650 struct ieee80211_sta *sta)
2651{
2652 struct wl1271 *wl = hw->priv;
2653 int ret = 0;
2654 u8 hlid;
2655
2656 mutex_lock(&wl->mutex);
2657
2658 if (unlikely(wl->state == WL1271_STATE_OFF))
2659 goto out;
2660
2661 if (wl->bss_type != BSS_TYPE_AP_BSS)
2662 goto out;
2663
2664 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2665
2666 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2667 if (ret < 0)
2668 goto out;
2669
2670 ret = wl1271_ps_elp_wakeup(wl, false);
2671 if (ret < 0)
2672 goto out;
2673
2674 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2675 if (ret < 0)
2676 goto out_sleep;
2677
2678out_sleep:
2679 wl1271_ps_elp_sleep(wl);
2680
2681out:
2682 mutex_unlock(&wl->mutex);
2683 return ret;
2684}
2685
2686static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2687 struct ieee80211_vif *vif,
2688 struct ieee80211_sta *sta)
2689{
2690 struct wl1271 *wl = hw->priv;
2691 struct wl1271_station *wl_sta;
2692 int ret = 0, id;
2693
2694 mutex_lock(&wl->mutex);
2695
2696 if (unlikely(wl->state == WL1271_STATE_OFF))
2697 goto out;
2698
2699 if (wl->bss_type != BSS_TYPE_AP_BSS)
2700 goto out;
2701
2702 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2703
2704 wl_sta = (struct wl1271_station *)sta->drv_priv;
2705 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2706 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2707 goto out;
2708
2709 ret = wl1271_ps_elp_wakeup(wl, false);
2710 if (ret < 0)
2711 goto out;
2712
2713 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2714 if (ret < 0)
2715 goto out_sleep;
2716
2717 wl1271_free_hlid(wl, wl_sta->hlid);
2718
2719out_sleep:
2720 wl1271_ps_elp_sleep(wl);
2721
2722out:
2723 mutex_unlock(&wl->mutex);
2724 return ret;
2725}
2726
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002727int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002728 enum ieee80211_ampdu_mlme_action action,
2729 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2730 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002731{
2732 struct wl1271 *wl = hw->priv;
2733 int ret;
2734
2735 mutex_lock(&wl->mutex);
2736
2737 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2738 ret = -EAGAIN;
2739 goto out;
2740 }
2741
2742 ret = wl1271_ps_elp_wakeup(wl, false);
2743 if (ret < 0)
2744 goto out;
2745
2746 switch (action) {
2747 case IEEE80211_AMPDU_RX_START:
2748 if (wl->ba_support) {
2749 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2750 true);
2751 if (!ret)
2752 wl->ba_rx_bitmap |= BIT(tid);
2753 } else {
2754 ret = -ENOTSUPP;
2755 }
2756 break;
2757
2758 case IEEE80211_AMPDU_RX_STOP:
2759 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2760 if (!ret)
2761 wl->ba_rx_bitmap &= ~BIT(tid);
2762 break;
2763
2764 /*
2765 * The BA initiator session management in FW independently.
2766 * Falling break here on purpose for all TX APDU commands.
2767 */
2768 case IEEE80211_AMPDU_TX_START:
2769 case IEEE80211_AMPDU_TX_STOP:
2770 case IEEE80211_AMPDU_TX_OPERATIONAL:
2771 ret = -EINVAL;
2772 break;
2773
2774 default:
2775 wl1271_error("Incorrect ampdu action id=%x\n", action);
2776 ret = -EINVAL;
2777 }
2778
2779 wl1271_ps_elp_sleep(wl);
2780
2781out:
2782 mutex_unlock(&wl->mutex);
2783
2784 return ret;
2785}
2786
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787/* can't be const, mac80211 writes to this */
2788static struct ieee80211_rate wl1271_rates[] = {
2789 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002790 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2791 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002792 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002793 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2794 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002795 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2796 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002797 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2798 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2800 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002801 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2802 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002803 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2804 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002805 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2806 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002808 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2809 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002810 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002811 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2812 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002813 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002814 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2815 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002816 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002817 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2818 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002820 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2821 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002822 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002823 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2824 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002826 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2827 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828};
2829
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002830/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002832 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002833 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002834 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2835 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2836 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002837 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002838 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2839 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2840 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002841 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002842 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2843 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2844 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002845 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846};
2847
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002848/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002849static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002850 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002851 7, /* CONF_HW_RXTX_RATE_MCS7 */
2852 6, /* CONF_HW_RXTX_RATE_MCS6 */
2853 5, /* CONF_HW_RXTX_RATE_MCS5 */
2854 4, /* CONF_HW_RXTX_RATE_MCS4 */
2855 3, /* CONF_HW_RXTX_RATE_MCS3 */
2856 2, /* CONF_HW_RXTX_RATE_MCS2 */
2857 1, /* CONF_HW_RXTX_RATE_MCS1 */
2858 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002859
2860 11, /* CONF_HW_RXTX_RATE_54 */
2861 10, /* CONF_HW_RXTX_RATE_48 */
2862 9, /* CONF_HW_RXTX_RATE_36 */
2863 8, /* CONF_HW_RXTX_RATE_24 */
2864
2865 /* TI-specific rate */
2866 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2867
2868 7, /* CONF_HW_RXTX_RATE_18 */
2869 6, /* CONF_HW_RXTX_RATE_12 */
2870 3, /* CONF_HW_RXTX_RATE_11 */
2871 5, /* CONF_HW_RXTX_RATE_9 */
2872 4, /* CONF_HW_RXTX_RATE_6 */
2873 2, /* CONF_HW_RXTX_RATE_5_5 */
2874 1, /* CONF_HW_RXTX_RATE_2 */
2875 0 /* CONF_HW_RXTX_RATE_1 */
2876};
2877
Shahar Levie8b03a22010-10-13 16:09:39 +02002878/* 11n STA capabilities */
2879#define HW_RX_HIGHEST_RATE 72
2880
Shahar Levi00d20102010-11-08 11:20:10 +00002881#ifdef CONFIG_WL12XX_HT
2882#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002883 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2884 .ht_supported = true, \
2885 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2886 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2887 .mcs = { \
2888 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2889 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2890 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2891 }, \
2892}
Shahar Levi18357852010-10-13 16:09:41 +02002893#else
Shahar Levi00d20102010-11-08 11:20:10 +00002894#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002895 .ht_supported = false, \
2896}
2897#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899/* can't be const, mac80211 writes to this */
2900static struct ieee80211_supported_band wl1271_band_2ghz = {
2901 .channels = wl1271_channels,
2902 .n_channels = ARRAY_SIZE(wl1271_channels),
2903 .bitrates = wl1271_rates,
2904 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002905 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906};
2907
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002908/* 5 GHz data rates for WL1273 */
2909static struct ieee80211_rate wl1271_rates_5ghz[] = {
2910 { .bitrate = 60,
2911 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2912 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2913 { .bitrate = 90,
2914 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2915 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2916 { .bitrate = 120,
2917 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2918 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2919 { .bitrate = 180,
2920 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2921 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2922 { .bitrate = 240,
2923 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2924 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2925 { .bitrate = 360,
2926 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2927 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2928 { .bitrate = 480,
2929 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2930 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2931 { .bitrate = 540,
2932 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2933 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2934};
2935
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002936/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002937static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002938 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002939 { .hw_value = 8, .center_freq = 5040},
2940 { .hw_value = 9, .center_freq = 5045},
2941 { .hw_value = 11, .center_freq = 5055},
2942 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002943 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002944 { .hw_value = 34, .center_freq = 5170},
2945 { .hw_value = 36, .center_freq = 5180},
2946 { .hw_value = 38, .center_freq = 5190},
2947 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002948 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002949 { .hw_value = 44, .center_freq = 5220},
2950 { .hw_value = 46, .center_freq = 5230},
2951 { .hw_value = 48, .center_freq = 5240},
2952 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002953 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002954 { .hw_value = 60, .center_freq = 5300},
2955 { .hw_value = 64, .center_freq = 5320},
2956 { .hw_value = 100, .center_freq = 5500},
2957 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002958 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002959 { .hw_value = 112, .center_freq = 5560},
2960 { .hw_value = 116, .center_freq = 5580},
2961 { .hw_value = 120, .center_freq = 5600},
2962 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002963 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002964 { .hw_value = 132, .center_freq = 5660},
2965 { .hw_value = 136, .center_freq = 5680},
2966 { .hw_value = 140, .center_freq = 5700},
2967 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002968 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002969 { .hw_value = 157, .center_freq = 5785},
2970 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002971 { .hw_value = 165, .center_freq = 5825},
2972};
2973
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002974/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002975static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002976 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002977 7, /* CONF_HW_RXTX_RATE_MCS7 */
2978 6, /* CONF_HW_RXTX_RATE_MCS6 */
2979 5, /* CONF_HW_RXTX_RATE_MCS5 */
2980 4, /* CONF_HW_RXTX_RATE_MCS4 */
2981 3, /* CONF_HW_RXTX_RATE_MCS3 */
2982 2, /* CONF_HW_RXTX_RATE_MCS2 */
2983 1, /* CONF_HW_RXTX_RATE_MCS1 */
2984 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002985
2986 7, /* CONF_HW_RXTX_RATE_54 */
2987 6, /* CONF_HW_RXTX_RATE_48 */
2988 5, /* CONF_HW_RXTX_RATE_36 */
2989 4, /* CONF_HW_RXTX_RATE_24 */
2990
2991 /* TI-specific rate */
2992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2993
2994 3, /* CONF_HW_RXTX_RATE_18 */
2995 2, /* CONF_HW_RXTX_RATE_12 */
2996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2997 1, /* CONF_HW_RXTX_RATE_9 */
2998 0, /* CONF_HW_RXTX_RATE_6 */
2999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3000 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3001 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3002};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003003
3004static struct ieee80211_supported_band wl1271_band_5ghz = {
3005 .channels = wl1271_channels_5ghz,
3006 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3007 .bitrates = wl1271_rates_5ghz,
3008 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003009 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003010};
3011
Tobias Klausera0ea9492010-05-20 10:38:11 +02003012static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003013 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3014 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3015};
3016
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017static const struct ieee80211_ops wl1271_ops = {
3018 .start = wl1271_op_start,
3019 .stop = wl1271_op_stop,
3020 .add_interface = wl1271_op_add_interface,
3021 .remove_interface = wl1271_op_remove_interface,
3022 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003023 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003024 .configure_filter = wl1271_op_configure_filter,
3025 .tx = wl1271_op_tx,
3026 .set_key = wl1271_op_set_key,
3027 .hw_scan = wl1271_op_hw_scan,
3028 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003029 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003031 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003032 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003033 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003034 .sta_add = wl1271_op_sta_add,
3035 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003036 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003037 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038};
3039
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003040
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003041u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003042{
3043 u8 idx;
3044
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003045 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003046
3047 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3048 wl1271_error("Illegal RX rate from HW: %d", rate);
3049 return 0;
3050 }
3051
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003052 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003053 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3054 wl1271_error("Unsupported RX rate from HW: %d", rate);
3055 return 0;
3056 }
3057
3058 return idx;
3059}
3060
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003061static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3062 struct device_attribute *attr,
3063 char *buf)
3064{
3065 struct wl1271 *wl = dev_get_drvdata(dev);
3066 ssize_t len;
3067
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003068 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003069
3070 mutex_lock(&wl->mutex);
3071 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3072 wl->sg_enabled);
3073 mutex_unlock(&wl->mutex);
3074
3075 return len;
3076
3077}
3078
3079static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3080 struct device_attribute *attr,
3081 const char *buf, size_t count)
3082{
3083 struct wl1271 *wl = dev_get_drvdata(dev);
3084 unsigned long res;
3085 int ret;
3086
3087 ret = strict_strtoul(buf, 10, &res);
3088
3089 if (ret < 0) {
3090 wl1271_warning("incorrect value written to bt_coex_mode");
3091 return count;
3092 }
3093
3094 mutex_lock(&wl->mutex);
3095
3096 res = !!res;
3097
3098 if (res == wl->sg_enabled)
3099 goto out;
3100
3101 wl->sg_enabled = res;
3102
3103 if (wl->state == WL1271_STATE_OFF)
3104 goto out;
3105
3106 ret = wl1271_ps_elp_wakeup(wl, false);
3107 if (ret < 0)
3108 goto out;
3109
3110 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3111 wl1271_ps_elp_sleep(wl);
3112
3113 out:
3114 mutex_unlock(&wl->mutex);
3115 return count;
3116}
3117
3118static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3119 wl1271_sysfs_show_bt_coex_state,
3120 wl1271_sysfs_store_bt_coex_state);
3121
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003122static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3123 struct device_attribute *attr,
3124 char *buf)
3125{
3126 struct wl1271 *wl = dev_get_drvdata(dev);
3127 ssize_t len;
3128
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003129 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003130
3131 mutex_lock(&wl->mutex);
3132 if (wl->hw_pg_ver >= 0)
3133 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3134 else
3135 len = snprintf(buf, len, "n/a\n");
3136 mutex_unlock(&wl->mutex);
3137
3138 return len;
3139}
3140
3141static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3142 wl1271_sysfs_show_hw_pg_ver, NULL);
3143
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003144int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145{
3146 int ret;
3147
3148 if (wl->mac80211_registered)
3149 return 0;
3150
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003151 ret = wl1271_fetch_nvs(wl);
3152 if (ret == 0) {
3153 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3154
3155 wl->mac_addr[0] = nvs_ptr[11];
3156 wl->mac_addr[1] = nvs_ptr[10];
3157 wl->mac_addr[2] = nvs_ptr[6];
3158 wl->mac_addr[3] = nvs_ptr[5];
3159 wl->mac_addr[4] = nvs_ptr[4];
3160 wl->mac_addr[5] = nvs_ptr[3];
3161 }
3162
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3164
3165 ret = ieee80211_register_hw(wl->hw);
3166 if (ret < 0) {
3167 wl1271_error("unable to register mac80211 hw: %d", ret);
3168 return ret;
3169 }
3170
3171 wl->mac80211_registered = true;
3172
Eliad Pellerd60080a2010-11-24 12:53:16 +02003173 wl1271_debugfs_init(wl);
3174
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003175 register_netdevice_notifier(&wl1271_dev_notifier);
3176
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177 wl1271_notice("loaded");
3178
3179 return 0;
3180}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003181EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003182
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003183void wl1271_unregister_hw(struct wl1271 *wl)
3184{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003185 if (wl->state == WL1271_STATE_PLT)
3186 __wl1271_plt_stop(wl);
3187
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003188 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003189 ieee80211_unregister_hw(wl->hw);
3190 wl->mac80211_registered = false;
3191
3192}
3193EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3194
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003195int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003197 static const u32 cipher_suites[] = {
3198 WLAN_CIPHER_SUITE_WEP40,
3199 WLAN_CIPHER_SUITE_WEP104,
3200 WLAN_CIPHER_SUITE_TKIP,
3201 WLAN_CIPHER_SUITE_CCMP,
3202 WL1271_CIPHER_SUITE_GEM,
3203 };
3204
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003205 /* The tx descriptor buffer and the TKIP space. */
3206 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3207 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208
3209 /* unit us */
3210 /* FIXME: find a proper value */
3211 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003212 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213
3214 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003215 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003216 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003217 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003218 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003219 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003220 IEEE80211_HW_SUPPORTS_CQM_RSSI |
3221 IEEE80211_HW_REPORTS_TX_ACK_STATUS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003223 wl->hw->wiphy->cipher_suites = cipher_suites;
3224 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3225
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003226 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003227 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003229 /*
3230 * Maximum length of elements in scanning probe request templates
3231 * should be the maximum length possible for a template, without
3232 * the IEEE80211 header of the template
3233 */
3234 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3235 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003236
3237 /*
3238 * We keep local copies of the band structs because we need to
3239 * modify them on a per-device basis.
3240 */
3241 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3242 sizeof(wl1271_band_2ghz));
3243 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3244 sizeof(wl1271_band_5ghz));
3245
3246 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3247 &wl->bands[IEEE80211_BAND_2GHZ];
3248 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3249 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003250
Kalle Valo12bd8942010-03-18 12:26:33 +02003251 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003252 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003253
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003254 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3255
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003256 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003257
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003258 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3259
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003260 wl->hw->max_rx_aggregation_subframes = 8;
3261
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003262 return 0;
3263}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003264EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003266#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003267
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003268struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003269{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003270 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003271 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003272 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003273 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003274 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003275
3276 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3277 if (!hw) {
3278 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003279 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003280 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003281 }
3282
Julia Lawall929ebd32010-05-15 23:16:39 +02003283 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003284 if (!plat_dev) {
3285 wl1271_error("could not allocate platform_device");
3286 ret = -ENOMEM;
3287 goto err_plat_alloc;
3288 }
3289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003290 wl = hw->priv;
3291 memset(wl, 0, sizeof(*wl));
3292
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003293 INIT_LIST_HEAD(&wl->list);
3294
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003295 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003296 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003297
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003298 for (i = 0; i < NUM_TX_QUEUES; i++)
3299 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003300
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003301 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003302 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003303 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3304 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3305 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3306 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003308 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003311 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3312 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003313 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003314 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003315 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003316 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003317 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003318 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003319 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003320 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003321 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003322 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003323 wl->bss_type = MAX_BSS_TYPE;
3324 wl->set_bss_type = MAX_BSS_TYPE;
3325 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003326
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003327 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003328 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003329 wl->tx_frames[i] = NULL;
3330
3331 spin_lock_init(&wl->wl_lock);
3332
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003333 wl->state = WL1271_STATE_OFF;
3334 mutex_init(&wl->mutex);
3335
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003336 /* Apply default driver configuration. */
3337 wl1271_conf_init(wl);
3338
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003339 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3340 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3341 if (!wl->aggr_buf) {
3342 ret = -ENOMEM;
3343 goto err_hw;
3344 }
3345
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003346 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003347 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003348 if (ret) {
3349 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003350 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003351 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003352 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003353
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003354 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003355 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003356 if (ret < 0) {
3357 wl1271_error("failed to create sysfs file bt_coex_state");
3358 goto err_platform;
3359 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003360
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003361 /* Create sysfs file to get HW PG version */
3362 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3363 if (ret < 0) {
3364 wl1271_error("failed to create sysfs file hw_pg_ver");
3365 goto err_bt_coex_state;
3366 }
3367
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003368 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003369
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003370err_bt_coex_state:
3371 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3372
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003373err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003374 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003375
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003376err_aggr:
3377 free_pages((unsigned long)wl->aggr_buf, order);
3378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003379err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003380 wl1271_debugfs_exit(wl);
3381 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003382
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003383err_plat_alloc:
3384 ieee80211_free_hw(hw);
3385
3386err_hw_alloc:
3387
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003388 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003389}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003390EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003391
3392int wl1271_free_hw(struct wl1271 *wl)
3393{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003394 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003395 free_pages((unsigned long)wl->aggr_buf,
3396 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003397 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003398
3399 wl1271_debugfs_exit(wl);
3400
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003401 vfree(wl->fw);
3402 wl->fw = NULL;
3403 kfree(wl->nvs);
3404 wl->nvs = NULL;
3405
3406 kfree(wl->fw_status);
3407 kfree(wl->tx_res_if);
3408
3409 ieee80211_free_hw(wl->hw);
3410
3411 return 0;
3412}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003413EXPORT_SYMBOL_GPL(wl1271_free_hw);
3414
Guy Eilam491bbd62011-01-12 10:33:29 +01003415u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003416EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003417module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003418MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3419
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003420MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003421MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003422MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");