blob: cf8b3cebe9d63c20bf74350a743b301397d482a9 [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++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200990 spin_unlock_irqrestore(&wl->wl_lock, flags);
991
992 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200993 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
994 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995
996 /*
997 * The chip specific setup must run before the first TX packet -
998 * before that, the tx_work will not be initialized!
999 */
1000
Ido Yariva5225502010-10-12 14:49:10 +02001001 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1002 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
1004 /*
1005 * The workqueue is slow to process the tx_queue and we need stop
1006 * the queue here, otherwise the queue will get too long.
1007 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001008 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001009 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001011 spin_lock_irqsave(&wl->wl_lock, flags);
1012 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001013 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001014 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 }
1016
1017 return NETDEV_TX_OK;
1018}
1019
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001020static struct notifier_block wl1271_dev_notifier = {
1021 .notifier_call = wl1271_dev_notify,
1022};
1023
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024static int wl1271_op_start(struct ieee80211_hw *hw)
1025{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001026 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1027
1028 /*
1029 * We have to delay the booting of the hardware because
1030 * we need to know the local MAC address before downloading and
1031 * initializing the firmware. The MAC address cannot be changed
1032 * after boot, and without the proper MAC address, the firmware
1033 * will not function properly.
1034 *
1035 * The MAC address is first known when the corresponding interface
1036 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001037 *
1038 * In addition, we currently have different firmwares for AP and managed
1039 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001040 */
1041
1042 return 0;
1043}
1044
1045static void wl1271_op_stop(struct ieee80211_hw *hw)
1046{
1047 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1048}
1049
1050static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1051 struct ieee80211_vif *vif)
1052{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001054 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001055 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001057 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001059 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1060 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061
1062 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001063 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001064 wl1271_debug(DEBUG_MAC80211,
1065 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001066 ret = -EBUSY;
1067 goto out;
1068 }
1069
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001070 switch (vif->type) {
1071 case NL80211_IFTYPE_STATION:
1072 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001073 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001074 break;
1075 case NL80211_IFTYPE_ADHOC:
1076 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001077 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001078 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001079 case NL80211_IFTYPE_AP:
1080 wl->bss_type = BSS_TYPE_AP_BSS;
1081 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001082 default:
1083 ret = -EOPNOTSUPP;
1084 goto out;
1085 }
1086
1087 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001088
1089 if (wl->state != WL1271_STATE_OFF) {
1090 wl1271_error("cannot start because not in off state: %d",
1091 wl->state);
1092 ret = -EBUSY;
1093 goto out;
1094 }
1095
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001096 while (retries) {
1097 retries--;
1098 ret = wl1271_chip_wakeup(wl);
1099 if (ret < 0)
1100 goto power_off;
1101
1102 ret = wl1271_boot(wl);
1103 if (ret < 0)
1104 goto power_off;
1105
1106 ret = wl1271_hw_init(wl);
1107 if (ret < 0)
1108 goto irq_disable;
1109
Eliad Peller71125ab2010-10-28 21:46:43 +02001110 booted = true;
1111 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001113irq_disable:
1114 wl1271_disable_interrupts(wl);
1115 mutex_unlock(&wl->mutex);
1116 /* Unlocking the mutex in the middle of handling is
1117 inherently unsafe. In this case we deem it safe to do,
1118 because we need to let any possibly pending IRQ out of
1119 the system (and while we are WL1271_STATE_OFF the IRQ
1120 work function will not do anything.) Also, any other
1121 possible concurrent operations will fail due to the
1122 current state, hence the wl1271 struct should be safe. */
1123 cancel_work_sync(&wl->irq_work);
1124 mutex_lock(&wl->mutex);
1125power_off:
1126 wl1271_power_off(wl);
1127 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128
Eliad Peller71125ab2010-10-28 21:46:43 +02001129 if (!booted) {
1130 wl1271_error("firmware boot failed despite %d retries",
1131 WL1271_BOOT_RETRIES);
1132 goto out;
1133 }
1134
1135 wl->vif = vif;
1136 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001137 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001138
1139 /* update hw/fw version info in wiphy struct */
1140 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001141 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001142 sizeof(wiphy->fw_version));
1143
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001144 /*
1145 * Now we know if 11a is supported (info from the NVS), so disable
1146 * 11a channels if not supported
1147 */
1148 if (!wl->enable_11a)
1149 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1150
1151 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1152 wl->enable_11a ? "" : "not ");
1153
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001154out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001155 mutex_unlock(&wl->mutex);
1156
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001157 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001158 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 return ret;
1161}
1162
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001163static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001165 int i;
1166
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001167 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001169 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001171 list_del(&wl->list);
1172
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173 WARN_ON(wl->state != WL1271_STATE_ON);
1174
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001175 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001176 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001177 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001178
Luciano Coelho08688d62010-07-08 17:50:07 +03001179 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001180 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1181 kfree(wl->scan.scanned_ch);
1182 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001183 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001184 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185 }
1186
1187 wl->state = WL1271_STATE_OFF;
1188
1189 wl1271_disable_interrupts(wl);
1190
1191 mutex_unlock(&wl->mutex);
1192
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001193 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194 cancel_work_sync(&wl->irq_work);
1195 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001196 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001197 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198
1199 mutex_lock(&wl->mutex);
1200
1201 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001202 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 wl1271_power_off(wl);
1204
1205 memset(wl->bssid, 0, ETH_ALEN);
1206 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1207 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001209 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001210 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211
1212 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001213 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1215 wl->tx_blocks_available = 0;
1216 wl->tx_results_count = 0;
1217 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001218 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001219 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 wl->time_offset = 0;
1221 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001222 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001223 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001224 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001225 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001226 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001227 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001228
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 for (i = 0; i < NUM_TX_QUEUES; i++)
1230 wl->tx_blocks_freed[i] = 0;
1231
1232 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001233
1234 kfree(wl->fw_status);
1235 wl->fw_status = NULL;
1236 kfree(wl->tx_res_if);
1237 wl->tx_res_if = NULL;
1238 kfree(wl->target_mem_map);
1239 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001240}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001241
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001242static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1243 struct ieee80211_vif *vif)
1244{
1245 struct wl1271 *wl = hw->priv;
1246
1247 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001248 /*
1249 * wl->vif can be null here if someone shuts down the interface
1250 * just when hardware recovery has been started.
1251 */
1252 if (wl->vif) {
1253 WARN_ON(wl->vif != vif);
1254 __wl1271_op_remove_interface(wl);
1255 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001256
Juuso Oikarinen67353292010-11-18 15:19:02 +02001257 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001258 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259}
1260
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001261static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1262{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001263 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001264
1265 /* combine requested filters with current filter config */
1266 filters = wl->filters | filters;
1267
1268 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1269
1270 if (filters & FIF_PROMISC_IN_BSS) {
1271 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1272 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1273 wl->rx_config |= CFG_BSSID_FILTER_EN;
1274 }
1275 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1276 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1277 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1278 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1279 }
1280 if (filters & FIF_OTHER_BSS) {
1281 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1282 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1283 }
1284 if (filters & FIF_CONTROL) {
1285 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1286 wl->rx_filter |= CFG_RX_CTL_EN;
1287 }
1288 if (filters & FIF_FCSFAIL) {
1289 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1290 wl->rx_filter |= CFG_RX_FCS_ERROR;
1291 }
1292}
1293
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001294static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001295{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001296 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001297 /* we need to use a dummy BSSID for now */
1298 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1299 0xad, 0xbe, 0xef };
1300
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001301 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1302
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001303 /* pass through frames from all BSS */
1304 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1305
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001306 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001307 if (ret < 0)
1308 goto out;
1309
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001310 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001311
1312out:
1313 return ret;
1314}
1315
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001316static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001317{
1318 int ret;
1319
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001320 /*
1321 * One of the side effects of the JOIN command is that is clears
1322 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1323 * to a WPA/WPA2 access point will therefore kill the data-path.
1324 * Currently there is no supported scenario for JOIN during
1325 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1326 * must be handled somehow.
1327 *
1328 */
1329 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1330 wl1271_info("JOIN while associated.");
1331
1332 if (set_assoc)
1333 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1334
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001335 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1336 if (ret < 0)
1337 goto out;
1338
1339 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1340
1341 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1342 goto out;
1343
1344 /*
1345 * The join command disable the keep-alive mode, shut down its process,
1346 * and also clear the template config, so we need to reset it all after
1347 * the join. The acx_aid starts the keep-alive process, and the order
1348 * of the commands below is relevant.
1349 */
1350 ret = wl1271_acx_keep_alive_mode(wl, true);
1351 if (ret < 0)
1352 goto out;
1353
1354 ret = wl1271_acx_aid(wl, wl->aid);
1355 if (ret < 0)
1356 goto out;
1357
1358 ret = wl1271_cmd_build_klv_null_data(wl);
1359 if (ret < 0)
1360 goto out;
1361
1362 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1363 ACX_KEEP_ALIVE_TPL_VALID);
1364 if (ret < 0)
1365 goto out;
1366
1367out:
1368 return ret;
1369}
1370
1371static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001372{
1373 int ret;
1374
1375 /* to stop listening to a channel, we disconnect */
1376 ret = wl1271_cmd_disconnect(wl);
1377 if (ret < 0)
1378 goto out;
1379
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001380 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001381 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001382
1383 /* stop filterting packets based on bssid */
1384 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001385
1386out:
1387 return ret;
1388}
1389
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001390static void wl1271_set_band_rate(struct wl1271 *wl)
1391{
1392 if (wl->band == IEEE80211_BAND_2GHZ)
1393 wl->basic_rate_set = wl->conf.tx.basic_rate;
1394 else
1395 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1396}
1397
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001398static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001399{
1400 int ret;
1401
1402 if (idle) {
1403 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1404 ret = wl1271_unjoin(wl);
1405 if (ret < 0)
1406 goto out;
1407 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001408 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001409 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001410 if (ret < 0)
1411 goto out;
1412 ret = wl1271_acx_keep_alive_config(
1413 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1414 ACX_KEEP_ALIVE_TPL_INVALID);
1415 if (ret < 0)
1416 goto out;
1417 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1418 } else {
1419 /* increment the session counter */
1420 wl->session_counter++;
1421 if (wl->session_counter >= SESSION_COUNTER_MAX)
1422 wl->session_counter = 0;
1423 ret = wl1271_dummy_join(wl);
1424 if (ret < 0)
1425 goto out;
1426 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1427 }
1428
1429out:
1430 return ret;
1431}
1432
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1434{
1435 struct wl1271 *wl = hw->priv;
1436 struct ieee80211_conf *conf = &hw->conf;
1437 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001438 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439
1440 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1441
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001442 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1443 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 channel,
1445 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001446 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001447 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1448 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001450 /*
1451 * mac80211 will go to idle nearly immediately after transmitting some
1452 * frames, such as the deauth. To make sure those frames reach the air,
1453 * wait here until the TX queue is fully flushed.
1454 */
1455 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1456 (conf->flags & IEEE80211_CONF_IDLE))
1457 wl1271_tx_flush(wl);
1458
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459 mutex_lock(&wl->mutex);
1460
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001461 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1462 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001463 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001464 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001465
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001466 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1467
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 ret = wl1271_ps_elp_wakeup(wl, false);
1469 if (ret < 0)
1470 goto out;
1471
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001472 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001473 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1474 ((wl->band != conf->channel->band) ||
1475 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001476 wl->band = conf->channel->band;
1477 wl->channel = channel;
1478
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001479 if (!is_ap) {
1480 /*
1481 * FIXME: the mac80211 should really provide a fixed
1482 * rate to use here. for now, just use the smallest
1483 * possible rate for the band as a fixed rate for
1484 * association frames and other control messages.
1485 */
1486 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1487 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001488
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001489 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1490 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001491 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001492 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001493 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001494
1495 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1496 ret = wl1271_join(wl, false);
1497 if (ret < 0)
1498 wl1271_warning("cmd join on channel "
1499 "failed %d", ret);
1500 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001501 }
1502 }
1503
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001504 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1505 ret = wl1271_sta_handle_idle(wl,
1506 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001507 if (ret < 0)
1508 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 }
1510
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001511 /*
1512 * if mac80211 changes the PSM mode, make sure the mode is not
1513 * incorrectly changed after the pspoll failure active window.
1514 */
1515 if (changed & IEEE80211_CONF_CHANGE_PS)
1516 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1517
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001518 if (conf->flags & IEEE80211_CONF_PS &&
1519 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1520 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521
1522 /*
1523 * We enter PSM only if we're already associated.
1524 * If we're not, we'll enter it when joining an SSID,
1525 * through the bss_info_changed() hook.
1526 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001527 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001528 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001529 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001530 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001531 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001533 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001534 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001536 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001538 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001539 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001540 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541 }
1542
1543 if (conf->power_level != wl->power_level) {
1544 ret = wl1271_acx_tx_power(wl, conf->power_level);
1545 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001546 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547
1548 wl->power_level = conf->power_level;
1549 }
1550
1551out_sleep:
1552 wl1271_ps_elp_sleep(wl);
1553
1554out:
1555 mutex_unlock(&wl->mutex);
1556
1557 return ret;
1558}
1559
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001560struct wl1271_filter_params {
1561 bool enabled;
1562 int mc_list_length;
1563 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1564};
1565
Jiri Pirko22bedad2010-04-01 21:22:57 +00001566static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1567 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001568{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001569 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001570 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001571 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001572
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001573 if (unlikely(wl->state == WL1271_STATE_OFF))
1574 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001575
Juuso Oikarinen74441132009-10-13 12:47:53 +03001576 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001577 if (!fp) {
1578 wl1271_error("Out of memory setting filters.");
1579 return 0;
1580 }
1581
1582 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001583 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001584 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1585 fp->enabled = false;
1586 } else {
1587 fp->enabled = true;
1588 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001589 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001590 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001591 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001592 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001593 }
1594
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001595 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001596}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001598#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1599 FIF_ALLMULTI | \
1600 FIF_FCSFAIL | \
1601 FIF_BCN_PRBRESP_PROMISC | \
1602 FIF_CONTROL | \
1603 FIF_OTHER_BSS)
1604
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1606 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001607 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001609 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001611 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001612
Arik Nemtsov7d057862010-10-16 19:25:35 +02001613 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1614 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001616 mutex_lock(&wl->mutex);
1617
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001618 *total &= WL1271_SUPPORTED_FILTERS;
1619 changed &= WL1271_SUPPORTED_FILTERS;
1620
1621 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001622 goto out;
1623
1624 ret = wl1271_ps_elp_wakeup(wl, false);
1625 if (ret < 0)
1626 goto out;
1627
Arik Nemtsov7d057862010-10-16 19:25:35 +02001628 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1629 if (*total & FIF_ALLMULTI)
1630 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1631 else if (fp)
1632 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1633 fp->mc_list,
1634 fp->mc_list_length);
1635 if (ret < 0)
1636 goto out_sleep;
1637 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001639 /* determine, whether supported filter values have changed */
1640 if (changed == 0)
1641 goto out_sleep;
1642
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001643 /* configure filters */
1644 wl->filters = *total;
1645 wl1271_configure_filters(wl, 0);
1646
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001647 /* apply configured filters */
1648 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1649 if (ret < 0)
1650 goto out_sleep;
1651
1652out_sleep:
1653 wl1271_ps_elp_sleep(wl);
1654
1655out:
1656 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001657 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658}
1659
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001660static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1661 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1662 u16 tx_seq_16)
1663{
1664 struct wl1271_ap_key *ap_key;
1665 int i;
1666
1667 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1668
1669 if (key_size > MAX_KEY_SIZE)
1670 return -EINVAL;
1671
1672 /*
1673 * Find next free entry in ap_keys. Also check we are not replacing
1674 * an existing key.
1675 */
1676 for (i = 0; i < MAX_NUM_KEYS; i++) {
1677 if (wl->recorded_ap_keys[i] == NULL)
1678 break;
1679
1680 if (wl->recorded_ap_keys[i]->id == id) {
1681 wl1271_warning("trying to record key replacement");
1682 return -EINVAL;
1683 }
1684 }
1685
1686 if (i == MAX_NUM_KEYS)
1687 return -EBUSY;
1688
1689 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1690 if (!ap_key)
1691 return -ENOMEM;
1692
1693 ap_key->id = id;
1694 ap_key->key_type = key_type;
1695 ap_key->key_size = key_size;
1696 memcpy(ap_key->key, key, key_size);
1697 ap_key->hlid = hlid;
1698 ap_key->tx_seq_32 = tx_seq_32;
1699 ap_key->tx_seq_16 = tx_seq_16;
1700
1701 wl->recorded_ap_keys[i] = ap_key;
1702 return 0;
1703}
1704
1705static void wl1271_free_ap_keys(struct wl1271 *wl)
1706{
1707 int i;
1708
1709 for (i = 0; i < MAX_NUM_KEYS; i++) {
1710 kfree(wl->recorded_ap_keys[i]);
1711 wl->recorded_ap_keys[i] = NULL;
1712 }
1713}
1714
1715static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1716{
1717 int i, ret = 0;
1718 struct wl1271_ap_key *key;
1719 bool wep_key_added = false;
1720
1721 for (i = 0; i < MAX_NUM_KEYS; i++) {
1722 if (wl->recorded_ap_keys[i] == NULL)
1723 break;
1724
1725 key = wl->recorded_ap_keys[i];
1726 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1727 key->id, key->key_type,
1728 key->key_size, key->key,
1729 key->hlid, key->tx_seq_32,
1730 key->tx_seq_16);
1731 if (ret < 0)
1732 goto out;
1733
1734 if (key->key_type == KEY_WEP)
1735 wep_key_added = true;
1736 }
1737
1738 if (wep_key_added) {
1739 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1740 if (ret < 0)
1741 goto out;
1742 }
1743
1744out:
1745 wl1271_free_ap_keys(wl);
1746 return ret;
1747}
1748
1749static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1750 u8 key_size, const u8 *key, u32 tx_seq_32,
1751 u16 tx_seq_16, struct ieee80211_sta *sta)
1752{
1753 int ret;
1754 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1755
1756 if (is_ap) {
1757 struct wl1271_station *wl_sta;
1758 u8 hlid;
1759
1760 if (sta) {
1761 wl_sta = (struct wl1271_station *)sta->drv_priv;
1762 hlid = wl_sta->hlid;
1763 } else {
1764 hlid = WL1271_AP_BROADCAST_HLID;
1765 }
1766
1767 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1768 /*
1769 * We do not support removing keys after AP shutdown.
1770 * Pretend we do to make mac80211 happy.
1771 */
1772 if (action != KEY_ADD_OR_REPLACE)
1773 return 0;
1774
1775 ret = wl1271_record_ap_key(wl, id,
1776 key_type, key_size,
1777 key, hlid, tx_seq_32,
1778 tx_seq_16);
1779 } else {
1780 ret = wl1271_cmd_set_ap_key(wl, action,
1781 id, key_type, key_size,
1782 key, hlid, tx_seq_32,
1783 tx_seq_16);
1784 }
1785
1786 if (ret < 0)
1787 return ret;
1788 } else {
1789 const u8 *addr;
1790 static const u8 bcast_addr[ETH_ALEN] = {
1791 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1792 };
1793
1794 addr = sta ? sta->addr : bcast_addr;
1795
1796 if (is_zero_ether_addr(addr)) {
1797 /* We dont support TX only encryption */
1798 return -EOPNOTSUPP;
1799 }
1800
1801 /* The wl1271 does not allow to remove unicast keys - they
1802 will be cleared automatically on next CMD_JOIN. Ignore the
1803 request silently, as we dont want the mac80211 to emit
1804 an error message. */
1805 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1806 return 0;
1807
1808 ret = wl1271_cmd_set_sta_key(wl, action,
1809 id, key_type, key_size,
1810 key, addr, tx_seq_32,
1811 tx_seq_16);
1812 if (ret < 0)
1813 return ret;
1814
1815 /* the default WEP key needs to be configured at least once */
1816 if (key_type == KEY_WEP) {
1817 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1818 wl->default_key);
1819 if (ret < 0)
1820 return ret;
1821 }
1822 }
1823
1824 return 0;
1825}
1826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1828 struct ieee80211_vif *vif,
1829 struct ieee80211_sta *sta,
1830 struct ieee80211_key_conf *key_conf)
1831{
1832 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001834 u32 tx_seq_32 = 0;
1835 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 u8 key_type;
1837
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001838 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1839
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001840 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001842 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 key_conf->keylen, key_conf->flags);
1844 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 mutex_lock(&wl->mutex);
1847
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001848 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1849 ret = -EAGAIN;
1850 goto out_unlock;
1851 }
1852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853 ret = wl1271_ps_elp_wakeup(wl, false);
1854 if (ret < 0)
1855 goto out_unlock;
1856
Johannes Berg97359d12010-08-10 09:46:38 +02001857 switch (key_conf->cipher) {
1858 case WLAN_CIPHER_SUITE_WEP40:
1859 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 key_type = KEY_WEP;
1861
1862 key_conf->hw_key_idx = key_conf->keyidx;
1863 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001864 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 key_type = KEY_TKIP;
1866
1867 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001868 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1869 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001871 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872 key_type = KEY_AES;
1873
1874 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001875 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1876 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001878 case WL1271_CIPHER_SUITE_GEM:
1879 key_type = KEY_GEM;
1880 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1881 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1882 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001884 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001885
1886 ret = -EOPNOTSUPP;
1887 goto out_sleep;
1888 }
1889
1890 switch (cmd) {
1891 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001892 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1893 key_conf->keyidx, key_type,
1894 key_conf->keylen, key_conf->key,
1895 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 if (ret < 0) {
1897 wl1271_error("Could not add or replace key");
1898 goto out_sleep;
1899 }
1900 break;
1901
1902 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001903 ret = wl1271_set_key(wl, KEY_REMOVE,
1904 key_conf->keyidx, key_type,
1905 key_conf->keylen, key_conf->key,
1906 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001907 if (ret < 0) {
1908 wl1271_error("Could not remove key");
1909 goto out_sleep;
1910 }
1911 break;
1912
1913 default:
1914 wl1271_error("Unsupported key cmd 0x%x", cmd);
1915 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916 break;
1917 }
1918
1919out_sleep:
1920 wl1271_ps_elp_sleep(wl);
1921
1922out_unlock:
1923 mutex_unlock(&wl->mutex);
1924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001925 return ret;
1926}
1927
1928static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001929 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 struct cfg80211_scan_request *req)
1931{
1932 struct wl1271 *wl = hw->priv;
1933 int ret;
1934 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001935 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936
1937 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1938
1939 if (req->n_ssids) {
1940 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001941 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 }
1943
1944 mutex_lock(&wl->mutex);
1945
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001946 if (wl->state == WL1271_STATE_OFF) {
1947 /*
1948 * We cannot return -EBUSY here because cfg80211 will expect
1949 * a call to ieee80211_scan_completed if we do - in this case
1950 * there won't be any call.
1951 */
1952 ret = -EAGAIN;
1953 goto out;
1954 }
1955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 ret = wl1271_ps_elp_wakeup(wl, false);
1957 if (ret < 0)
1958 goto out;
1959
Luciano Coelho5924f892010-08-04 03:46:22 +03001960 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961
1962 wl1271_ps_elp_sleep(wl);
1963
1964out:
1965 mutex_unlock(&wl->mutex);
1966
1967 return ret;
1968}
1969
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001970static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1971{
1972 struct wl1271 *wl = hw->priv;
1973 int ret = 0;
1974
1975 mutex_lock(&wl->mutex);
1976
1977 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1978 ret = -EAGAIN;
1979 goto out;
1980 }
1981
1982 ret = wl1271_ps_elp_wakeup(wl, false);
1983 if (ret < 0)
1984 goto out;
1985
1986 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1987 if (ret < 0)
1988 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1989
1990 wl1271_ps_elp_sleep(wl);
1991
1992out:
1993 mutex_unlock(&wl->mutex);
1994
1995 return ret;
1996}
1997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1999{
2000 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002001 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002002
2003 mutex_lock(&wl->mutex);
2004
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002005 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2006 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002007 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002008 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002010 ret = wl1271_ps_elp_wakeup(wl, false);
2011 if (ret < 0)
2012 goto out;
2013
2014 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2015 if (ret < 0)
2016 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2017
2018 wl1271_ps_elp_sleep(wl);
2019
2020out:
2021 mutex_unlock(&wl->mutex);
2022
2023 return ret;
2024}
2025
Arik Nemtsove78a2872010-10-16 19:07:21 +02002026static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002027 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002028{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002029 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002030
2031 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002032 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002033 if (ptr[0] == WLAN_EID_SSID) {
2034 wl->ssid_len = ptr[1];
2035 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002036 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002037 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002038 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002039 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002040
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002041 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002042 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002043}
2044
Arik Nemtsove78a2872010-10-16 19:07:21 +02002045static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2046 struct ieee80211_bss_conf *bss_conf,
2047 u32 changed)
2048{
2049 int ret = 0;
2050
2051 if (changed & BSS_CHANGED_ERP_SLOT) {
2052 if (bss_conf->use_short_slot)
2053 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2054 else
2055 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2056 if (ret < 0) {
2057 wl1271_warning("Set slot time failed %d", ret);
2058 goto out;
2059 }
2060 }
2061
2062 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2063 if (bss_conf->use_short_preamble)
2064 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2065 else
2066 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2067 }
2068
2069 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2070 if (bss_conf->use_cts_prot)
2071 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2072 else
2073 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2074 if (ret < 0) {
2075 wl1271_warning("Set ctsprotect failed %d", ret);
2076 goto out;
2077 }
2078 }
2079
2080out:
2081 return ret;
2082}
2083
2084static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2085 struct ieee80211_vif *vif,
2086 struct ieee80211_bss_conf *bss_conf,
2087 u32 changed)
2088{
2089 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2090 int ret = 0;
2091
2092 if ((changed & BSS_CHANGED_BEACON_INT)) {
2093 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2094 bss_conf->beacon_int);
2095
2096 wl->beacon_int = bss_conf->beacon_int;
2097 }
2098
2099 if ((changed & BSS_CHANGED_BEACON)) {
2100 struct ieee80211_hdr *hdr;
2101 int ieoffset = offsetof(struct ieee80211_mgmt,
2102 u.beacon.variable);
2103 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2104 u16 tmpl_id;
2105
2106 if (!beacon)
2107 goto out;
2108
2109 wl1271_debug(DEBUG_MASTER, "beacon updated");
2110
2111 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2112 if (ret < 0) {
2113 dev_kfree_skb(beacon);
2114 goto out;
2115 }
2116 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2117 CMD_TEMPL_BEACON;
2118 ret = wl1271_cmd_template_set(wl, tmpl_id,
2119 beacon->data,
2120 beacon->len, 0,
2121 wl1271_tx_min_rate_get(wl));
2122 if (ret < 0) {
2123 dev_kfree_skb(beacon);
2124 goto out;
2125 }
2126
2127 hdr = (struct ieee80211_hdr *) beacon->data;
2128 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2129 IEEE80211_STYPE_PROBE_RESP);
2130
2131 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2132 CMD_TEMPL_PROBE_RESPONSE;
2133 ret = wl1271_cmd_template_set(wl,
2134 tmpl_id,
2135 beacon->data,
2136 beacon->len, 0,
2137 wl1271_tx_min_rate_get(wl));
2138 dev_kfree_skb(beacon);
2139 if (ret < 0)
2140 goto out;
2141 }
2142
2143out:
2144 return ret;
2145}
2146
2147/* AP mode changes */
2148static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149 struct ieee80211_vif *vif,
2150 struct ieee80211_bss_conf *bss_conf,
2151 u32 changed)
2152{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002153 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2156 u32 rates = bss_conf->basic_rates;
2157 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158
Arik Nemtsove78a2872010-10-16 19:07:21 +02002159 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2160 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2161 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2162 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163
Arik Nemtsove78a2872010-10-16 19:07:21 +02002164 /* update the AP management rate policy with the new rates */
2165 mgmt_rc.enabled_rates = wl->basic_rate_set;
2166 mgmt_rc.long_retry_limit = 10;
2167 mgmt_rc.short_retry_limit = 10;
2168 mgmt_rc.aflags = 0;
2169 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2170 ACX_TX_AP_MODE_MGMT_RATE);
2171 if (ret < 0) {
2172 wl1271_error("AP mgmt policy change failed %d", ret);
2173 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002174 }
2175 }
2176
Arik Nemtsove78a2872010-10-16 19:07:21 +02002177 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2178 if (ret < 0)
2179 goto out;
2180
2181 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2182 if (bss_conf->enable_beacon) {
2183 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2184 ret = wl1271_cmd_start_bss(wl);
2185 if (ret < 0)
2186 goto out;
2187
2188 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2189 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002190
2191 ret = wl1271_ap_init_hwenc(wl);
2192 if (ret < 0)
2193 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002194 }
2195 } else {
2196 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2197 ret = wl1271_cmd_stop_bss(wl);
2198 if (ret < 0)
2199 goto out;
2200
2201 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2202 wl1271_debug(DEBUG_AP, "stopped AP");
2203 }
2204 }
2205 }
2206
2207 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2208 if (ret < 0)
2209 goto out;
2210out:
2211 return;
2212}
2213
2214/* STA/IBSS mode changes */
2215static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2216 struct ieee80211_vif *vif,
2217 struct ieee80211_bss_conf *bss_conf,
2218 u32 changed)
2219{
2220 bool do_join = false, set_assoc = false;
2221 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002222 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002223 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002224 struct ieee80211_sta *sta;
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);
2296
2297 /* handle new association with HT and HT information change */
2298 if ((changed & BSS_CHANGED_HT) &&
2299 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2300 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2301 true);
2302 if (ret < 0) {
2303 wl1271_warning("Set ht cap true failed %d",
2304 ret);
2305 rcu_read_unlock();
2306 goto out;
2307 }
2308 ret = wl1271_acx_set_ht_information(wl,
2309 bss_conf->ht_operation_mode);
2310 if (ret < 0) {
2311 wl1271_warning("Set ht information failed %d",
2312 ret);
2313 rcu_read_unlock();
2314 goto out;
2315 }
2316 }
2317 /* handle new association without HT and disassociation */
2318 else if (changed & BSS_CHANGED_ASSOC) {
2319 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2320 false);
2321 if (ret < 0) {
2322 wl1271_warning("Set ht cap false failed %d",
2323 ret);
2324 rcu_read_unlock();
2325 goto out;
2326 }
2327 }
2328 }
2329 rcu_read_unlock();
2330
Arik Nemtsove78a2872010-10-16 19:07:21 +02002331 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002334 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002336 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002338 wl->ps_poll_failures = 0;
2339
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002340 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002341 * use basic rates from AP, and determine lowest rate
2342 * to use with control frames.
2343 */
2344 rates = bss_conf->basic_rates;
2345 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2346 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002347 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002348 if (sta_rate_set)
2349 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2350 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002351 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002352 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002353 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002354
2355 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002356 * with wl1271, we don't need to update the
2357 * beacon_int and dtim_period, because the firmware
2358 * updates it by itself when the first beacon is
2359 * received after a join.
2360 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2362 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002363 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002365 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002366 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002367 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002368 dev_kfree_skb(wl->probereq);
2369 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2370 ieoffset = offsetof(struct ieee80211_mgmt,
2371 u.probe_req.variable);
2372 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002373
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002374 /* enable the connection monitoring feature */
2375 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002377 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378
2379 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002380 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2381 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002382 enum wl1271_cmd_ps_mode mode;
2383
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002385 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002386 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002387 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002389 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002391 } else {
2392 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002393 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002394 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002395 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002396
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002397 /* free probe-request template */
2398 dev_kfree_skb(wl->probereq);
2399 wl->probereq = NULL;
2400
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002401 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002402 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002403
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404 /* revert back to minimum rates for the current band */
2405 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002406 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002407 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002408 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002409 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002410
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002411 /* disable connection monitor features */
2412 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002413
2414 /* Disable the keep-alive feature */
2415 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002416 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002417 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002418
2419 /* restore the bssid filter and go to dummy bssid */
2420 wl1271_unjoin(wl);
2421 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422 }
2423 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002424
Arik Nemtsove78a2872010-10-16 19:07:21 +02002425 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2426 if (ret < 0)
2427 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002428
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002429 if (changed & BSS_CHANGED_ARP_FILTER) {
2430 __be32 addr = bss_conf->arp_addr_list[0];
2431 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2432
Eliad Pellerc5312772010-12-09 11:31:27 +02002433 if (bss_conf->arp_addr_cnt == 1 &&
2434 bss_conf->arp_filter_enabled) {
2435 /*
2436 * The template should have been configured only upon
2437 * association. however, it seems that the correct ip
2438 * isn't being set (when sending), so we have to
2439 * reconfigure the template upon every ip change.
2440 */
2441 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2442 if (ret < 0) {
2443 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002445 }
2446
2447 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002448 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002449 addr);
2450 } else
2451 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002452
2453 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002454 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002455 }
2456
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002457 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002458 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002459 if (ret < 0) {
2460 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002461 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002462 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002463 }
2464
Arik Nemtsove78a2872010-10-16 19:07:21 +02002465out:
2466 return;
2467}
2468
2469static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2470 struct ieee80211_vif *vif,
2471 struct ieee80211_bss_conf *bss_conf,
2472 u32 changed)
2473{
2474 struct wl1271 *wl = hw->priv;
2475 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2476 int ret;
2477
2478 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2479 (int)changed);
2480
2481 mutex_lock(&wl->mutex);
2482
2483 if (unlikely(wl->state == WL1271_STATE_OFF))
2484 goto out;
2485
2486 ret = wl1271_ps_elp_wakeup(wl, false);
2487 if (ret < 0)
2488 goto out;
2489
2490 if (is_ap)
2491 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2492 else
2493 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495 wl1271_ps_elp_sleep(wl);
2496
2497out:
2498 mutex_unlock(&wl->mutex);
2499}
2500
Kalle Valoc6999d82010-02-18 13:25:41 +02002501static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2502 const struct ieee80211_tx_queue_params *params)
2503{
2504 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002505 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002506 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002507
2508 mutex_lock(&wl->mutex);
2509
2510 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2511
Kalle Valo4695dc92010-03-18 12:26:38 +02002512 if (params->uapsd)
2513 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2514 else
2515 ps_scheme = CONF_PS_SCHEME_LEGACY;
2516
Arik Nemtsov488fc542010-10-16 20:33:45 +02002517 if (wl->state == WL1271_STATE_OFF) {
2518 /*
2519 * If the state is off, the parameters will be recorded and
2520 * configured on init. This happens in AP-mode.
2521 */
2522 struct conf_tx_ac_category *conf_ac =
2523 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2524 struct conf_tx_tid *conf_tid =
2525 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2526
2527 conf_ac->ac = wl1271_tx_get_queue(queue);
2528 conf_ac->cw_min = (u8)params->cw_min;
2529 conf_ac->cw_max = params->cw_max;
2530 conf_ac->aifsn = params->aifs;
2531 conf_ac->tx_op_limit = params->txop << 5;
2532
2533 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2534 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2535 conf_tid->tsid = wl1271_tx_get_queue(queue);
2536 conf_tid->ps_scheme = ps_scheme;
2537 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2538 conf_tid->apsd_conf[0] = 0;
2539 conf_tid->apsd_conf[1] = 0;
2540 } else {
2541 ret = wl1271_ps_elp_wakeup(wl, false);
2542 if (ret < 0)
2543 goto out;
2544
2545 /*
2546 * the txop is confed in units of 32us by the mac80211,
2547 * we need us
2548 */
2549 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2550 params->cw_min, params->cw_max,
2551 params->aifs, params->txop << 5);
2552 if (ret < 0)
2553 goto out_sleep;
2554
2555 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2556 CONF_CHANNEL_TYPE_EDCF,
2557 wl1271_tx_get_queue(queue),
2558 ps_scheme, CONF_ACK_POLICY_LEGACY,
2559 0, 0);
2560 if (ret < 0)
2561 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002562
2563out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002564 wl1271_ps_elp_sleep(wl);
2565 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002566
2567out:
2568 mutex_unlock(&wl->mutex);
2569
2570 return ret;
2571}
2572
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002573static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2574{
2575
2576 struct wl1271 *wl = hw->priv;
2577 u64 mactime = ULLONG_MAX;
2578 int ret;
2579
2580 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2581
2582 mutex_lock(&wl->mutex);
2583
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002584 if (unlikely(wl->state == WL1271_STATE_OFF))
2585 goto out;
2586
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002587 ret = wl1271_ps_elp_wakeup(wl, false);
2588 if (ret < 0)
2589 goto out;
2590
2591 ret = wl1271_acx_tsf_info(wl, &mactime);
2592 if (ret < 0)
2593 goto out_sleep;
2594
2595out_sleep:
2596 wl1271_ps_elp_sleep(wl);
2597
2598out:
2599 mutex_unlock(&wl->mutex);
2600 return mactime;
2601}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602
John W. Linvilleece550d2010-07-28 16:41:06 -04002603static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2604 struct survey_info *survey)
2605{
2606 struct wl1271 *wl = hw->priv;
2607 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002608
John W. Linvilleece550d2010-07-28 16:41:06 -04002609 if (idx != 0)
2610 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002611
John W. Linvilleece550d2010-07-28 16:41:06 -04002612 survey->channel = conf->channel;
2613 survey->filled = SURVEY_INFO_NOISE_DBM;
2614 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002615
John W. Linvilleece550d2010-07-28 16:41:06 -04002616 return 0;
2617}
2618
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002619static int wl1271_allocate_hlid(struct wl1271 *wl,
2620 struct ieee80211_sta *sta,
2621 u8 *hlid)
2622{
2623 struct wl1271_station *wl_sta;
2624 int id;
2625
2626 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2627 if (id >= AP_MAX_STATIONS) {
2628 wl1271_warning("could not allocate HLID - too much stations");
2629 return -EBUSY;
2630 }
2631
2632 wl_sta = (struct wl1271_station *)sta->drv_priv;
2633
2634 __set_bit(id, wl->ap_hlid_map);
2635 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2636 *hlid = wl_sta->hlid;
2637 return 0;
2638}
2639
2640static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2641{
2642 int id = hlid - WL1271_AP_STA_HLID_START;
2643
2644 __clear_bit(id, wl->ap_hlid_map);
2645}
2646
2647static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2648 struct ieee80211_vif *vif,
2649 struct ieee80211_sta *sta)
2650{
2651 struct wl1271 *wl = hw->priv;
2652 int ret = 0;
2653 u8 hlid;
2654
2655 mutex_lock(&wl->mutex);
2656
2657 if (unlikely(wl->state == WL1271_STATE_OFF))
2658 goto out;
2659
2660 if (wl->bss_type != BSS_TYPE_AP_BSS)
2661 goto out;
2662
2663 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2664
2665 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2666 if (ret < 0)
2667 goto out;
2668
2669 ret = wl1271_ps_elp_wakeup(wl, false);
2670 if (ret < 0)
2671 goto out;
2672
2673 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2674 if (ret < 0)
2675 goto out_sleep;
2676
2677out_sleep:
2678 wl1271_ps_elp_sleep(wl);
2679
2680out:
2681 mutex_unlock(&wl->mutex);
2682 return ret;
2683}
2684
2685static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2686 struct ieee80211_vif *vif,
2687 struct ieee80211_sta *sta)
2688{
2689 struct wl1271 *wl = hw->priv;
2690 struct wl1271_station *wl_sta;
2691 int ret = 0, id;
2692
2693 mutex_lock(&wl->mutex);
2694
2695 if (unlikely(wl->state == WL1271_STATE_OFF))
2696 goto out;
2697
2698 if (wl->bss_type != BSS_TYPE_AP_BSS)
2699 goto out;
2700
2701 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2702
2703 wl_sta = (struct wl1271_station *)sta->drv_priv;
2704 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2705 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2706 goto out;
2707
2708 ret = wl1271_ps_elp_wakeup(wl, false);
2709 if (ret < 0)
2710 goto out;
2711
2712 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2713 if (ret < 0)
2714 goto out_sleep;
2715
2716 wl1271_free_hlid(wl, wl_sta->hlid);
2717
2718out_sleep:
2719 wl1271_ps_elp_sleep(wl);
2720
2721out:
2722 mutex_unlock(&wl->mutex);
2723 return ret;
2724}
2725
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002726int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002727 enum ieee80211_ampdu_mlme_action action,
2728 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2729 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002730{
2731 struct wl1271 *wl = hw->priv;
2732 int ret;
2733
2734 mutex_lock(&wl->mutex);
2735
2736 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2737 ret = -EAGAIN;
2738 goto out;
2739 }
2740
2741 ret = wl1271_ps_elp_wakeup(wl, false);
2742 if (ret < 0)
2743 goto out;
2744
2745 switch (action) {
2746 case IEEE80211_AMPDU_RX_START:
2747 if (wl->ba_support) {
2748 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2749 true);
2750 if (!ret)
2751 wl->ba_rx_bitmap |= BIT(tid);
2752 } else {
2753 ret = -ENOTSUPP;
2754 }
2755 break;
2756
2757 case IEEE80211_AMPDU_RX_STOP:
2758 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2759 if (!ret)
2760 wl->ba_rx_bitmap &= ~BIT(tid);
2761 break;
2762
2763 /*
2764 * The BA initiator session management in FW independently.
2765 * Falling break here on purpose for all TX APDU commands.
2766 */
2767 case IEEE80211_AMPDU_TX_START:
2768 case IEEE80211_AMPDU_TX_STOP:
2769 case IEEE80211_AMPDU_TX_OPERATIONAL:
2770 ret = -EINVAL;
2771 break;
2772
2773 default:
2774 wl1271_error("Incorrect ampdu action id=%x\n", action);
2775 ret = -EINVAL;
2776 }
2777
2778 wl1271_ps_elp_sleep(wl);
2779
2780out:
2781 mutex_unlock(&wl->mutex);
2782
2783 return ret;
2784}
2785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002786/* can't be const, mac80211 writes to this */
2787static struct ieee80211_rate wl1271_rates[] = {
2788 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002789 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2790 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002791 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002792 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2793 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002794 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2795 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002796 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2797 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2799 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002800 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2801 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2803 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002804 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2805 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002806 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002807 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2808 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002810 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2811 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002812 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002813 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2814 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002816 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2817 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002818 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002819 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2820 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002822 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2823 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002825 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2826 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827};
2828
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002829/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002830static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002831 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002832 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002833 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2834 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2835 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002836 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002837 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2838 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2839 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002840 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002841 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2842 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2843 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002844 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002845};
2846
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002847/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002848static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002849 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002850 7, /* CONF_HW_RXTX_RATE_MCS7 */
2851 6, /* CONF_HW_RXTX_RATE_MCS6 */
2852 5, /* CONF_HW_RXTX_RATE_MCS5 */
2853 4, /* CONF_HW_RXTX_RATE_MCS4 */
2854 3, /* CONF_HW_RXTX_RATE_MCS3 */
2855 2, /* CONF_HW_RXTX_RATE_MCS2 */
2856 1, /* CONF_HW_RXTX_RATE_MCS1 */
2857 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002858
2859 11, /* CONF_HW_RXTX_RATE_54 */
2860 10, /* CONF_HW_RXTX_RATE_48 */
2861 9, /* CONF_HW_RXTX_RATE_36 */
2862 8, /* CONF_HW_RXTX_RATE_24 */
2863
2864 /* TI-specific rate */
2865 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2866
2867 7, /* CONF_HW_RXTX_RATE_18 */
2868 6, /* CONF_HW_RXTX_RATE_12 */
2869 3, /* CONF_HW_RXTX_RATE_11 */
2870 5, /* CONF_HW_RXTX_RATE_9 */
2871 4, /* CONF_HW_RXTX_RATE_6 */
2872 2, /* CONF_HW_RXTX_RATE_5_5 */
2873 1, /* CONF_HW_RXTX_RATE_2 */
2874 0 /* CONF_HW_RXTX_RATE_1 */
2875};
2876
Shahar Levie8b03a22010-10-13 16:09:39 +02002877/* 11n STA capabilities */
2878#define HW_RX_HIGHEST_RATE 72
2879
Shahar Levi00d20102010-11-08 11:20:10 +00002880#ifdef CONFIG_WL12XX_HT
2881#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002882 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2883 .ht_supported = true, \
2884 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2885 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2886 .mcs = { \
2887 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2888 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2889 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2890 }, \
2891}
Shahar Levi18357852010-10-13 16:09:41 +02002892#else
Shahar Levi00d20102010-11-08 11:20:10 +00002893#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002894 .ht_supported = false, \
2895}
2896#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898/* can't be const, mac80211 writes to this */
2899static struct ieee80211_supported_band wl1271_band_2ghz = {
2900 .channels = wl1271_channels,
2901 .n_channels = ARRAY_SIZE(wl1271_channels),
2902 .bitrates = wl1271_rates,
2903 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002904 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905};
2906
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002907/* 5 GHz data rates for WL1273 */
2908static struct ieee80211_rate wl1271_rates_5ghz[] = {
2909 { .bitrate = 60,
2910 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2911 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2912 { .bitrate = 90,
2913 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2914 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2915 { .bitrate = 120,
2916 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2917 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2918 { .bitrate = 180,
2919 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2920 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2921 { .bitrate = 240,
2922 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2923 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2924 { .bitrate = 360,
2925 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2926 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2927 { .bitrate = 480,
2928 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2929 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2930 { .bitrate = 540,
2931 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2932 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2933};
2934
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002935/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002936static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002937 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002938 { .hw_value = 8, .center_freq = 5040},
2939 { .hw_value = 9, .center_freq = 5045},
2940 { .hw_value = 11, .center_freq = 5055},
2941 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002942 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002943 { .hw_value = 34, .center_freq = 5170},
2944 { .hw_value = 36, .center_freq = 5180},
2945 { .hw_value = 38, .center_freq = 5190},
2946 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002947 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002948 { .hw_value = 44, .center_freq = 5220},
2949 { .hw_value = 46, .center_freq = 5230},
2950 { .hw_value = 48, .center_freq = 5240},
2951 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002952 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002953 { .hw_value = 60, .center_freq = 5300},
2954 { .hw_value = 64, .center_freq = 5320},
2955 { .hw_value = 100, .center_freq = 5500},
2956 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002957 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002958 { .hw_value = 112, .center_freq = 5560},
2959 { .hw_value = 116, .center_freq = 5580},
2960 { .hw_value = 120, .center_freq = 5600},
2961 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002962 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002963 { .hw_value = 132, .center_freq = 5660},
2964 { .hw_value = 136, .center_freq = 5680},
2965 { .hw_value = 140, .center_freq = 5700},
2966 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002967 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002968 { .hw_value = 157, .center_freq = 5785},
2969 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002970 { .hw_value = 165, .center_freq = 5825},
2971};
2972
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002973/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002974static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002975 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002976 7, /* CONF_HW_RXTX_RATE_MCS7 */
2977 6, /* CONF_HW_RXTX_RATE_MCS6 */
2978 5, /* CONF_HW_RXTX_RATE_MCS5 */
2979 4, /* CONF_HW_RXTX_RATE_MCS4 */
2980 3, /* CONF_HW_RXTX_RATE_MCS3 */
2981 2, /* CONF_HW_RXTX_RATE_MCS2 */
2982 1, /* CONF_HW_RXTX_RATE_MCS1 */
2983 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002984
2985 7, /* CONF_HW_RXTX_RATE_54 */
2986 6, /* CONF_HW_RXTX_RATE_48 */
2987 5, /* CONF_HW_RXTX_RATE_36 */
2988 4, /* CONF_HW_RXTX_RATE_24 */
2989
2990 /* TI-specific rate */
2991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2992
2993 3, /* CONF_HW_RXTX_RATE_18 */
2994 2, /* CONF_HW_RXTX_RATE_12 */
2995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2996 1, /* CONF_HW_RXTX_RATE_9 */
2997 0, /* CONF_HW_RXTX_RATE_6 */
2998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3000 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3001};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003002
3003static struct ieee80211_supported_band wl1271_band_5ghz = {
3004 .channels = wl1271_channels_5ghz,
3005 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3006 .bitrates = wl1271_rates_5ghz,
3007 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003008 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003009};
3010
Tobias Klausera0ea9492010-05-20 10:38:11 +02003011static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003012 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3013 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3014};
3015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016static const struct ieee80211_ops wl1271_ops = {
3017 .start = wl1271_op_start,
3018 .stop = wl1271_op_stop,
3019 .add_interface = wl1271_op_add_interface,
3020 .remove_interface = wl1271_op_remove_interface,
3021 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003022 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 .configure_filter = wl1271_op_configure_filter,
3024 .tx = wl1271_op_tx,
3025 .set_key = wl1271_op_set_key,
3026 .hw_scan = wl1271_op_hw_scan,
3027 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003028 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003030 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003031 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003032 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003033 .sta_add = wl1271_op_sta_add,
3034 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003035 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003036 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037};
3038
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003039
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003040u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003041{
3042 u8 idx;
3043
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003044 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003045
3046 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3047 wl1271_error("Illegal RX rate from HW: %d", rate);
3048 return 0;
3049 }
3050
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003051 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003052 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3053 wl1271_error("Unsupported RX rate from HW: %d", rate);
3054 return 0;
3055 }
3056
3057 return idx;
3058}
3059
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003060static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3061 struct device_attribute *attr,
3062 char *buf)
3063{
3064 struct wl1271 *wl = dev_get_drvdata(dev);
3065 ssize_t len;
3066
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003067 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003068
3069 mutex_lock(&wl->mutex);
3070 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3071 wl->sg_enabled);
3072 mutex_unlock(&wl->mutex);
3073
3074 return len;
3075
3076}
3077
3078static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3079 struct device_attribute *attr,
3080 const char *buf, size_t count)
3081{
3082 struct wl1271 *wl = dev_get_drvdata(dev);
3083 unsigned long res;
3084 int ret;
3085
3086 ret = strict_strtoul(buf, 10, &res);
3087
3088 if (ret < 0) {
3089 wl1271_warning("incorrect value written to bt_coex_mode");
3090 return count;
3091 }
3092
3093 mutex_lock(&wl->mutex);
3094
3095 res = !!res;
3096
3097 if (res == wl->sg_enabled)
3098 goto out;
3099
3100 wl->sg_enabled = res;
3101
3102 if (wl->state == WL1271_STATE_OFF)
3103 goto out;
3104
3105 ret = wl1271_ps_elp_wakeup(wl, false);
3106 if (ret < 0)
3107 goto out;
3108
3109 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3110 wl1271_ps_elp_sleep(wl);
3111
3112 out:
3113 mutex_unlock(&wl->mutex);
3114 return count;
3115}
3116
3117static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3118 wl1271_sysfs_show_bt_coex_state,
3119 wl1271_sysfs_store_bt_coex_state);
3120
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003121static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3122 struct device_attribute *attr,
3123 char *buf)
3124{
3125 struct wl1271 *wl = dev_get_drvdata(dev);
3126 ssize_t len;
3127
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003128 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003129
3130 mutex_lock(&wl->mutex);
3131 if (wl->hw_pg_ver >= 0)
3132 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3133 else
3134 len = snprintf(buf, len, "n/a\n");
3135 mutex_unlock(&wl->mutex);
3136
3137 return len;
3138}
3139
3140static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3141 wl1271_sysfs_show_hw_pg_ver, NULL);
3142
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003143int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003144{
3145 int ret;
3146
3147 if (wl->mac80211_registered)
3148 return 0;
3149
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003150 ret = wl1271_fetch_nvs(wl);
3151 if (ret == 0) {
3152 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3153
3154 wl->mac_addr[0] = nvs_ptr[11];
3155 wl->mac_addr[1] = nvs_ptr[10];
3156 wl->mac_addr[2] = nvs_ptr[6];
3157 wl->mac_addr[3] = nvs_ptr[5];
3158 wl->mac_addr[4] = nvs_ptr[4];
3159 wl->mac_addr[5] = nvs_ptr[3];
3160 }
3161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3163
3164 ret = ieee80211_register_hw(wl->hw);
3165 if (ret < 0) {
3166 wl1271_error("unable to register mac80211 hw: %d", ret);
3167 return ret;
3168 }
3169
3170 wl->mac80211_registered = true;
3171
Eliad Pellerd60080a2010-11-24 12:53:16 +02003172 wl1271_debugfs_init(wl);
3173
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003174 register_netdevice_notifier(&wl1271_dev_notifier);
3175
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003176 wl1271_notice("loaded");
3177
3178 return 0;
3179}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003180EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003181
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003182void wl1271_unregister_hw(struct wl1271 *wl)
3183{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003184 if (wl->state == WL1271_STATE_PLT)
3185 __wl1271_plt_stop(wl);
3186
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003187 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003188 ieee80211_unregister_hw(wl->hw);
3189 wl->mac80211_registered = false;
3190
3191}
3192EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3193
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003194int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003195{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003196 static const u32 cipher_suites[] = {
3197 WLAN_CIPHER_SUITE_WEP40,
3198 WLAN_CIPHER_SUITE_WEP104,
3199 WLAN_CIPHER_SUITE_TKIP,
3200 WLAN_CIPHER_SUITE_CCMP,
3201 WL1271_CIPHER_SUITE_GEM,
3202 };
3203
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003204 /* The tx descriptor buffer and the TKIP space. */
3205 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3206 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003207
3208 /* unit us */
3209 /* FIXME: find a proper value */
3210 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003211 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212
3213 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003214 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003215 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003216 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003217 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003218 IEEE80211_HW_CONNECTION_MONITOR |
3219 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003221 wl->hw->wiphy->cipher_suites = cipher_suites;
3222 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3223
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003224 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003225 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003227 /*
3228 * Maximum length of elements in scanning probe request templates
3229 * should be the maximum length possible for a template, without
3230 * the IEEE80211 header of the template
3231 */
3232 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3233 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003234
3235 /*
3236 * We keep local copies of the band structs because we need to
3237 * modify them on a per-device basis.
3238 */
3239 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3240 sizeof(wl1271_band_2ghz));
3241 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3242 sizeof(wl1271_band_5ghz));
3243
3244 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3245 &wl->bands[IEEE80211_BAND_2GHZ];
3246 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3247 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003248
Kalle Valo12bd8942010-03-18 12:26:33 +02003249 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003250 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003251
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003252 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3253
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003254 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003256 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3257
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003258 wl->hw->max_rx_aggregation_subframes = 8;
3259
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003260 return 0;
3261}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003262EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003265
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003266struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003269 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003270 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003271 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003272 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003273
3274 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3275 if (!hw) {
3276 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003277 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003278 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003279 }
3280
Julia Lawall929ebd32010-05-15 23:16:39 +02003281 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003282 if (!plat_dev) {
3283 wl1271_error("could not allocate platform_device");
3284 ret = -ENOMEM;
3285 goto err_plat_alloc;
3286 }
3287
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003288 wl = hw->priv;
3289 memset(wl, 0, sizeof(*wl));
3290
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003291 INIT_LIST_HEAD(&wl->list);
3292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003293 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003294 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003295
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003296 for (i = 0; i < NUM_TX_QUEUES; i++)
3297 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003298
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003299 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003300 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003301 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3302 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3303 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3304 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003306 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003309 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3310 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003311 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003312 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003313 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003314 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003315 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003316 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003317 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003318 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003319 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003320 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003321 wl->bss_type = MAX_BSS_TYPE;
3322 wl->set_bss_type = MAX_BSS_TYPE;
3323 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003325 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003326 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003327 wl->tx_frames[i] = NULL;
3328
3329 spin_lock_init(&wl->wl_lock);
3330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331 wl->state = WL1271_STATE_OFF;
3332 mutex_init(&wl->mutex);
3333
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003334 /* Apply default driver configuration. */
3335 wl1271_conf_init(wl);
3336
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003337 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3338 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3339 if (!wl->aggr_buf) {
3340 ret = -ENOMEM;
3341 goto err_hw;
3342 }
3343
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003344 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003345 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003346 if (ret) {
3347 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003348 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003349 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003350 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003351
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003352 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003353 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003354 if (ret < 0) {
3355 wl1271_error("failed to create sysfs file bt_coex_state");
3356 goto err_platform;
3357 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003358
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003359 /* Create sysfs file to get HW PG version */
3360 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3361 if (ret < 0) {
3362 wl1271_error("failed to create sysfs file hw_pg_ver");
3363 goto err_bt_coex_state;
3364 }
3365
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003366 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003367
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003368err_bt_coex_state:
3369 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3370
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003371err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003372 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003373
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003374err_aggr:
3375 free_pages((unsigned long)wl->aggr_buf, order);
3376
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003377err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003378 wl1271_debugfs_exit(wl);
3379 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003380
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003381err_plat_alloc:
3382 ieee80211_free_hw(hw);
3383
3384err_hw_alloc:
3385
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003386 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003387}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003388EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003389
3390int wl1271_free_hw(struct wl1271 *wl)
3391{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003392 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003393 free_pages((unsigned long)wl->aggr_buf,
3394 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003395 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003396
3397 wl1271_debugfs_exit(wl);
3398
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003399 vfree(wl->fw);
3400 wl->fw = NULL;
3401 kfree(wl->nvs);
3402 wl->nvs = NULL;
3403
3404 kfree(wl->fw_status);
3405 kfree(wl->tx_res_if);
3406
3407 ieee80211_free_hw(wl->hw);
3408
3409 return 0;
3410}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003411EXPORT_SYMBOL_GPL(wl1271_free_hw);
3412
Guy Eilam491bbd62011-01-12 10:33:29 +01003413u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003414EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003415module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003416MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3417
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003418MODULE_LICENSE("GPL");
3419MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3420MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");