blob: 91d681221286820dc908c94bba04213398460c7e [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 = {
302 .dynamic_memory = 0,
303 .min_req_tx_blocks = 104,
304 .min_req_rx_blocks = 22,
305 .tx_min = 27,
306 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300307};
308
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200309static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200310static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200311
312
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200313static void wl1271_device_release(struct device *dev)
314{
315
316}
317
318static struct platform_device wl1271_device = {
319 .name = "wl1271",
320 .id = -1,
321
322 /* device model insists to have a release function */
323 .dev = {
324 .release = wl1271_device_release,
325 },
326};
327
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300328static LIST_HEAD(wl_list);
329
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300330static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
331 void *arg)
332{
333 struct net_device *dev = arg;
334 struct wireless_dev *wdev;
335 struct wiphy *wiphy;
336 struct ieee80211_hw *hw;
337 struct wl1271 *wl;
338 struct wl1271 *wl_temp;
339 int ret = 0;
340
341 /* Check that this notification is for us. */
342 if (what != NETDEV_CHANGE)
343 return NOTIFY_DONE;
344
345 wdev = dev->ieee80211_ptr;
346 if (wdev == NULL)
347 return NOTIFY_DONE;
348
349 wiphy = wdev->wiphy;
350 if (wiphy == NULL)
351 return NOTIFY_DONE;
352
353 hw = wiphy_priv(wiphy);
354 if (hw == NULL)
355 return NOTIFY_DONE;
356
357 wl_temp = hw->priv;
358 list_for_each_entry(wl, &wl_list, list) {
359 if (wl == wl_temp)
360 break;
361 }
362 if (wl != wl_temp)
363 return NOTIFY_DONE;
364
365 mutex_lock(&wl->mutex);
366
367 if (wl->state == WL1271_STATE_OFF)
368 goto out;
369
370 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
371 goto out;
372
373 ret = wl1271_ps_elp_wakeup(wl, false);
374 if (ret < 0)
375 goto out;
376
377 if ((dev->operstate == IF_OPER_UP) &&
378 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
379 wl1271_cmd_set_sta_state(wl);
380 wl1271_info("Association completed.");
381 }
382
383 wl1271_ps_elp_sleep(wl);
384
385out:
386 mutex_unlock(&wl->mutex);
387
388 return NOTIFY_OK;
389}
390
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100391static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200392 struct regulatory_request *request)
393{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100394 struct ieee80211_supported_band *band;
395 struct ieee80211_channel *ch;
396 int i;
397
398 band = wiphy->bands[IEEE80211_BAND_5GHZ];
399 for (i = 0; i < band->n_channels; i++) {
400 ch = &band->channels[i];
401 if (ch->flags & IEEE80211_CHAN_DISABLED)
402 continue;
403
404 if (ch->flags & IEEE80211_CHAN_RADAR)
405 ch->flags |= IEEE80211_CHAN_NO_IBSS |
406 IEEE80211_CHAN_PASSIVE_SCAN;
407
408 }
409
410 return 0;
411}
412
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300413static void wl1271_conf_init(struct wl1271 *wl)
414{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300415
416 /*
417 * This function applies the default configuration to the driver. This
418 * function is invoked upon driver load (spi probe.)
419 *
420 * The configuration is stored in a run-time structure in order to
421 * facilitate for run-time adjustment of any of the parameters. Making
422 * changes to the configuration structure will apply the new values on
423 * the next interface up (wl1271_op_start.)
424 */
425
426 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300427 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300428}
429
430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431static int wl1271_plt_init(struct wl1271 *wl)
432{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200433 struct conf_tx_ac_category *conf_ac;
434 struct conf_tx_tid *conf_tid;
435 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200437 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200438 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200439 return ret;
440
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200441 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200442 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200443 return ret;
444
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200445 ret = wl1271_cmd_ext_radio_parms(wl);
446 if (ret < 0)
447 return ret;
448
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200449 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200450 if (ret < 0)
451 return ret;
452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453 ret = wl1271_acx_init_mem_config(wl);
454 if (ret < 0)
455 return ret;
456
Luciano Coelho12419cc2010-02-18 13:25:44 +0200457 /* PHY layer config */
458 ret = wl1271_init_phy_config(wl);
459 if (ret < 0)
460 goto out_free_memmap;
461
462 ret = wl1271_acx_dco_itrim_params(wl);
463 if (ret < 0)
464 goto out_free_memmap;
465
466 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200467 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200468 if (ret < 0)
469 goto out_free_memmap;
470
471 /* Bluetooth WLAN coexistence */
472 ret = wl1271_init_pta(wl);
473 if (ret < 0)
474 goto out_free_memmap;
475
476 /* Energy detection */
477 ret = wl1271_init_energy_detection(wl);
478 if (ret < 0)
479 goto out_free_memmap;
480
481 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100482 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200483 if (ret < 0)
484 goto out_free_memmap;
485
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200486 /* Default TID/AC configuration */
487 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200488 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200489 conf_ac = &wl->conf.tx.ac_conf[i];
490 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
491 conf_ac->cw_max, conf_ac->aifsn,
492 conf_ac->tx_op_limit);
493 if (ret < 0)
494 goto out_free_memmap;
495
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 conf_tid = &wl->conf.tx.tid_conf[i];
497 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
498 conf_tid->channel_type,
499 conf_tid->tsid,
500 conf_tid->ps_scheme,
501 conf_tid->ack_policy,
502 conf_tid->apsd_conf[0],
503 conf_tid->apsd_conf[1]);
504 if (ret < 0)
505 goto out_free_memmap;
506 }
507
Luciano Coelho12419cc2010-02-18 13:25:44 +0200508 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200509 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200511 goto out_free_memmap;
512
513 /* Configure for CAM power saving (ie. always active) */
514 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
515 if (ret < 0)
516 goto out_free_memmap;
517
518 /* configure PM */
519 ret = wl1271_acx_pm_config(wl);
520 if (ret < 0)
521 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300522
523 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200524
525 out_free_memmap:
526 kfree(wl->target_mem_map);
527 wl->target_mem_map = NULL;
528
529 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530}
531
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300532static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200533 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300534{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200535 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200536 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300537 u32 total = 0;
538 int i;
539
Eliad Pellerc8bde242011-02-02 09:59:35 +0200540 if (wl->bss_type == BSS_TYPE_AP_BSS)
541 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
542 sizeof(struct wl1271_fw_ap_status), false);
543 else
544 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
545 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300546
547 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
548 "drv_rx_counter = %d, tx_results_counter = %d)",
549 status->intr,
550 status->fw_rx_counter,
551 status->drv_rx_counter,
552 status->tx_results_counter);
553
554 /* update number of available TX blocks */
555 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300556 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
557 wl->tx_blocks_freed[i];
558
559 wl->tx_blocks_freed[i] =
560 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561 wl->tx_blocks_available += cnt;
562 total += cnt;
563 }
564
Ido Yariva5225502010-10-12 14:49:10 +0200565 /* if more blocks are available now, tx work can be scheduled */
566 if (total)
567 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300568
569 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200570 getnstimeofday(&ts);
571 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
572 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300573}
574
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200575#define WL1271_IRQ_MAX_LOOPS 10
576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577static void wl1271_irq_work(struct work_struct *work)
578{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300580 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200581 int loopcount = WL1271_IRQ_MAX_LOOPS;
582 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583 struct wl1271 *wl =
584 container_of(work, struct wl1271, irq_work);
585
586 mutex_lock(&wl->mutex);
587
588 wl1271_debug(DEBUG_IRQ, "IRQ work");
589
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200590 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591 goto out;
592
593 ret = wl1271_ps_elp_wakeup(wl, true);
594 if (ret < 0)
595 goto out;
596
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200597 spin_lock_irqsave(&wl->wl_lock, flags);
598 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
599 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
600 spin_unlock_irqrestore(&wl->wl_lock, flags);
601 loopcount--;
602
603 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200604 intr = le32_to_cpu(wl->fw_status->common.intr);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 if (!intr) {
606 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200607 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200608 continue;
609 }
610
611 intr &= WL1271_INTR_MASK;
612
Eliad Pellerccc83b02010-10-27 14:09:57 +0200613 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
614 wl1271_error("watchdog interrupt received! "
615 "starting recovery.");
616 ieee80211_queue_work(wl->hw, &wl->recovery_work);
617
618 /* restarting the chip. ignore any other interrupt. */
619 goto out;
620 }
621
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200622 if (intr & WL1271_ACX_INTR_DATA) {
623 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
624
625 /* check for tx results */
Eliad Pellerc8bde242011-02-02 09:59:35 +0200626 if (wl->fw_status->common.tx_results_counter !=
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200627 (wl->tx_results_count & 0xff))
628 wl1271_tx_complete(wl);
629
Ido Yariva5225502010-10-12 14:49:10 +0200630 /* Check if any tx blocks were freed */
631 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200632 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200633 /*
634 * In order to avoid starvation of the TX path,
635 * call the work function directly.
636 */
637 wl1271_tx_work_locked(wl);
638 }
639
Eliad Pellerc8bde242011-02-02 09:59:35 +0200640 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200641 }
642
643 if (intr & WL1271_ACX_INTR_EVENT_A) {
644 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
645 wl1271_event_handle(wl, 0);
646 }
647
648 if (intr & WL1271_ACX_INTR_EVENT_B) {
649 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
650 wl1271_event_handle(wl, 1);
651 }
652
653 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
654 wl1271_debug(DEBUG_IRQ,
655 "WL1271_ACX_INTR_INIT_COMPLETE");
656
657 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
658 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
659
660 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661 }
662
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200663 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
664 ieee80211_queue_work(wl->hw, &wl->irq_work);
665 else
666 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
667 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 wl1271_ps_elp_sleep(wl);
670
671out:
672 mutex_unlock(&wl->mutex);
673}
674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675static int wl1271_fetch_firmware(struct wl1271 *wl)
676{
677 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200678 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 int ret;
680
Arik Nemtsov166d5042010-10-16 21:44:57 +0200681 switch (wl->bss_type) {
682 case BSS_TYPE_AP_BSS:
683 fw_name = WL1271_AP_FW_NAME;
684 break;
685 case BSS_TYPE_IBSS:
686 case BSS_TYPE_STA_BSS:
687 fw_name = WL1271_FW_NAME;
688 break;
689 default:
690 wl1271_error("no compatible firmware for bss_type %d",
691 wl->bss_type);
692 return -EINVAL;
693 }
694
695 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
696
697 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300698
699 if (ret < 0) {
700 wl1271_error("could not get firmware: %d", ret);
701 return ret;
702 }
703
704 if (fw->size % 4) {
705 wl1271_error("firmware size is not multiple of 32 bits: %zu",
706 fw->size);
707 ret = -EILSEQ;
708 goto out;
709 }
710
Arik Nemtsov166d5042010-10-16 21:44:57 +0200711 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300713 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714
715 if (!wl->fw) {
716 wl1271_error("could not allocate memory for the firmware");
717 ret = -ENOMEM;
718 goto out;
719 }
720
721 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200722 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723 ret = 0;
724
725out:
726 release_firmware(fw);
727
728 return ret;
729}
730
731static int wl1271_fetch_nvs(struct wl1271 *wl)
732{
733 const struct firmware *fw;
734 int ret;
735
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200736 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737
738 if (ret < 0) {
739 wl1271_error("could not get nvs file: %d", ret);
740 return ret;
741 }
742
Julia Lawall929ebd32010-05-15 23:16:39 +0200743 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744
745 if (!wl->nvs) {
746 wl1271_error("could not allocate memory for the nvs file");
747 ret = -ENOMEM;
748 goto out;
749 }
750
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200751 wl->nvs_len = fw->size;
752
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300753out:
754 release_firmware(fw);
755
756 return ret;
757}
758
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200759static void wl1271_recovery_work(struct work_struct *work)
760{
761 struct wl1271 *wl =
762 container_of(work, struct wl1271, recovery_work);
763
764 mutex_lock(&wl->mutex);
765
766 if (wl->state != WL1271_STATE_ON)
767 goto out;
768
769 wl1271_info("Hardware recovery in progress.");
770
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200771 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
772 ieee80211_connection_loss(wl->vif);
773
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200774 /* reboot the chipset */
775 __wl1271_op_remove_interface(wl);
776 ieee80211_restart_hw(wl->hw);
777
778out:
779 mutex_unlock(&wl->mutex);
780}
781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782static void wl1271_fw_wakeup(struct wl1271 *wl)
783{
784 u32 elp_reg;
785
786 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300787 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788}
789
790static int wl1271_setup(struct wl1271 *wl)
791{
792 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
793 if (!wl->fw_status)
794 return -ENOMEM;
795
796 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
797 if (!wl->tx_res_if) {
798 kfree(wl->fw_status);
799 return -ENOMEM;
800 }
801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802 return 0;
803}
804
805static int wl1271_chip_wakeup(struct wl1271 *wl)
806{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300807 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 int ret = 0;
809
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200810 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200811 ret = wl1271_power_on(wl);
812 if (ret < 0)
813 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200815 wl1271_io_reset(wl);
816 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817
818 /* We don't need a real memory partition here, because we only want
819 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300820 memset(&partition, 0, sizeof(partition));
821 partition.reg.start = REGISTERS_BASE;
822 partition.reg.size = REGISTERS_DOWN_SIZE;
823 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
825 /* ELP module wake up */
826 wl1271_fw_wakeup(wl);
827
828 /* whal_FwCtrl_BootSm() */
829
830 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200831 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
833 /* 1. check if chip id is valid */
834
835 switch (wl->chip.id) {
836 case CHIP_ID_1271_PG10:
837 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
838 wl->chip.id);
839
840 ret = wl1271_setup(wl);
841 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200842 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 break;
844 case CHIP_ID_1271_PG20:
845 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
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 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200853 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200855 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856 }
857
Arik Nemtsov166d5042010-10-16 21:44:57 +0200858 /* Make sure the firmware type matches the BSS type */
859 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860 ret = wl1271_fetch_firmware(wl);
861 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200862 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863 }
864
865 /* No NVS from netlink, try to get it from the filesystem */
866 if (wl->nvs == NULL) {
867 ret = wl1271_fetch_nvs(wl);
868 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200869 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300870 }
871
872out:
873 return ret;
874}
875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876int wl1271_plt_start(struct wl1271 *wl)
877{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200878 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879 int ret;
880
881 mutex_lock(&wl->mutex);
882
883 wl1271_notice("power up");
884
885 if (wl->state != WL1271_STATE_OFF) {
886 wl1271_error("cannot go into PLT state because not "
887 "in off state: %d", wl->state);
888 ret = -EBUSY;
889 goto out;
890 }
891
Arik Nemtsov166d5042010-10-16 21:44:57 +0200892 wl->bss_type = BSS_TYPE_STA_BSS;
893
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200894 while (retries) {
895 retries--;
896 ret = wl1271_chip_wakeup(wl);
897 if (ret < 0)
898 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200900 ret = wl1271_boot(wl);
901 if (ret < 0)
902 goto power_off;
903
904 ret = wl1271_plt_init(wl);
905 if (ret < 0)
906 goto irq_disable;
907
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200908 wl->state = WL1271_STATE_PLT;
909 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100910 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911 goto out;
912
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200913irq_disable:
914 wl1271_disable_interrupts(wl);
915 mutex_unlock(&wl->mutex);
916 /* Unlocking the mutex in the middle of handling is
917 inherently unsafe. In this case we deem it safe to do,
918 because we need to let any possibly pending IRQ out of
919 the system (and while we are WL1271_STATE_OFF the IRQ
920 work function will not do anything.) Also, any other
921 possible concurrent operations will fail due to the
922 current state, hence the wl1271 struct should be safe. */
923 cancel_work_sync(&wl->irq_work);
924 mutex_lock(&wl->mutex);
925power_off:
926 wl1271_power_off(wl);
927 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200929 wl1271_error("firmware boot in PLT mode failed despite %d retries",
930 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931out:
932 mutex_unlock(&wl->mutex);
933
934 return ret;
935}
936
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100937int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938{
939 int ret = 0;
940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 wl1271_notice("power down");
942
943 if (wl->state != WL1271_STATE_PLT) {
944 wl1271_error("cannot power down because not in PLT "
945 "state: %d", wl->state);
946 ret = -EBUSY;
947 goto out;
948 }
949
950 wl1271_disable_interrupts(wl);
951 wl1271_power_off(wl);
952
953 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300954 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200957 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200958 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100959 mutex_lock(&wl->mutex);
960out:
961 return ret;
962}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200963
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100964int wl1271_plt_stop(struct wl1271 *wl)
965{
966 int ret;
967
968 mutex_lock(&wl->mutex);
969 ret = __wl1271_plt_stop(wl);
970 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 return ret;
972}
973
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
975{
976 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200977 struct ieee80211_conf *conf = &hw->conf;
978 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
979 struct ieee80211_sta *sta = txinfo->control.sta;
980 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200981 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982
Shahar Levi18357852010-10-13 16:09:41 +0200983 /*
984 * peek into the rates configured in the STA entry.
985 * The rates set after connection stage, The first block only BG sets:
986 * the compare is for bit 0-16 of sta_rate_set. The second block add
987 * HT rates in case of HT supported.
988 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200989 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200990 if (sta &&
991 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200992 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
993 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200994 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
995 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
996 }
Shahar Levi18357852010-10-13 16:09:41 +0200997
Shahar Levi00d20102010-11-08 11:20:10 +0000998#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200999 if (sta &&
1000 sta->ht_cap.ht_supported &&
1001 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
1002 sta->ht_cap.mcs.rx_mask[0])) {
1003 /* Clean MCS bits before setting them */
1004 wl->sta_rate_set &= HW_BG_RATES_MASK;
1005 wl->sta_rate_set |=
1006 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
1007 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
1008 }
1009#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001010 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001011 spin_unlock_irqrestore(&wl->wl_lock, flags);
1012
1013 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001014 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1015 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016
1017 /*
1018 * The chip specific setup must run before the first TX packet -
1019 * before that, the tx_work will not be initialized!
1020 */
1021
Ido Yariva5225502010-10-12 14:49:10 +02001022 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1023 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024
1025 /*
1026 * The workqueue is slow to process the tx_queue and we need stop
1027 * the queue here, otherwise the queue will get too long.
1028 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001029 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001030 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001032 spin_lock_irqsave(&wl->wl_lock, flags);
1033 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001034 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001035 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 }
1037
1038 return NETDEV_TX_OK;
1039}
1040
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001041static struct notifier_block wl1271_dev_notifier = {
1042 .notifier_call = wl1271_dev_notify,
1043};
1044
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045static int wl1271_op_start(struct ieee80211_hw *hw)
1046{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001047 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1048
1049 /*
1050 * We have to delay the booting of the hardware because
1051 * we need to know the local MAC address before downloading and
1052 * initializing the firmware. The MAC address cannot be changed
1053 * after boot, and without the proper MAC address, the firmware
1054 * will not function properly.
1055 *
1056 * The MAC address is first known when the corresponding interface
1057 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001058 *
1059 * In addition, we currently have different firmwares for AP and managed
1060 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001061 */
1062
1063 return 0;
1064}
1065
1066static void wl1271_op_stop(struct ieee80211_hw *hw)
1067{
1068 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1069}
1070
1071static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1072 struct ieee80211_vif *vif)
1073{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001075 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001076 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001078 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001080 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1081 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082
1083 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001084 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001085 wl1271_debug(DEBUG_MAC80211,
1086 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001087 ret = -EBUSY;
1088 goto out;
1089 }
1090
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001091 switch (vif->type) {
1092 case NL80211_IFTYPE_STATION:
1093 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001094 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001095 break;
1096 case NL80211_IFTYPE_ADHOC:
1097 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001098 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001099 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001100 case NL80211_IFTYPE_AP:
1101 wl->bss_type = BSS_TYPE_AP_BSS;
1102 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001103 default:
1104 ret = -EOPNOTSUPP;
1105 goto out;
1106 }
1107
1108 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109
1110 if (wl->state != WL1271_STATE_OFF) {
1111 wl1271_error("cannot start because not in off state: %d",
1112 wl->state);
1113 ret = -EBUSY;
1114 goto out;
1115 }
1116
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001117 while (retries) {
1118 retries--;
1119 ret = wl1271_chip_wakeup(wl);
1120 if (ret < 0)
1121 goto power_off;
1122
1123 ret = wl1271_boot(wl);
1124 if (ret < 0)
1125 goto power_off;
1126
1127 ret = wl1271_hw_init(wl);
1128 if (ret < 0)
1129 goto irq_disable;
1130
Eliad Peller71125ab2010-10-28 21:46:43 +02001131 booted = true;
1132 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001133
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001134irq_disable:
1135 wl1271_disable_interrupts(wl);
1136 mutex_unlock(&wl->mutex);
1137 /* Unlocking the mutex in the middle of handling is
1138 inherently unsafe. In this case we deem it safe to do,
1139 because we need to let any possibly pending IRQ out of
1140 the system (and while we are WL1271_STATE_OFF the IRQ
1141 work function will not do anything.) Also, any other
1142 possible concurrent operations will fail due to the
1143 current state, hence the wl1271 struct should be safe. */
1144 cancel_work_sync(&wl->irq_work);
1145 mutex_lock(&wl->mutex);
1146power_off:
1147 wl1271_power_off(wl);
1148 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001149
Eliad Peller71125ab2010-10-28 21:46:43 +02001150 if (!booted) {
1151 wl1271_error("firmware boot failed despite %d retries",
1152 WL1271_BOOT_RETRIES);
1153 goto out;
1154 }
1155
1156 wl->vif = vif;
1157 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001158 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001159
1160 /* update hw/fw version info in wiphy struct */
1161 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001162 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001163 sizeof(wiphy->fw_version));
1164
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001165 /*
1166 * Now we know if 11a is supported (info from the NVS), so disable
1167 * 11a channels if not supported
1168 */
1169 if (!wl->enable_11a)
1170 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1171
1172 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1173 wl->enable_11a ? "" : "not ");
1174
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001175out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176 mutex_unlock(&wl->mutex);
1177
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001178 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001179 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 return ret;
1182}
1183
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001184static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186 int i;
1187
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001188 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001190 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001191
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001192 list_del(&wl->list);
1193
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194 WARN_ON(wl->state != WL1271_STATE_ON);
1195
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001196 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001197 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001198 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001199
Luciano Coelho08688d62010-07-08 17:50:07 +03001200 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001201 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1202 kfree(wl->scan.scanned_ch);
1203 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001204 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001205 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 }
1207
1208 wl->state = WL1271_STATE_OFF;
1209
1210 wl1271_disable_interrupts(wl);
1211
1212 mutex_unlock(&wl->mutex);
1213
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001214 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215 cancel_work_sync(&wl->irq_work);
1216 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001217 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001218 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219
1220 mutex_lock(&wl->mutex);
1221
1222 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001223 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224 wl1271_power_off(wl);
1225
1226 memset(wl->bssid, 0, ETH_ALEN);
1227 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1228 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001230 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001231 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232
1233 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001234 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1236 wl->tx_blocks_available = 0;
1237 wl->tx_results_count = 0;
1238 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001239 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001240 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241 wl->time_offset = 0;
1242 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001243 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1244 wl->sta_rate_set = 0;
1245 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001246 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001247 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001248 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001249 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001250
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251 for (i = 0; i < NUM_TX_QUEUES; i++)
1252 wl->tx_blocks_freed[i] = 0;
1253
1254 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001255
1256 kfree(wl->fw_status);
1257 wl->fw_status = NULL;
1258 kfree(wl->tx_res_if);
1259 wl->tx_res_if = NULL;
1260 kfree(wl->target_mem_map);
1261 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001262}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001263
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001264static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1265 struct ieee80211_vif *vif)
1266{
1267 struct wl1271 *wl = hw->priv;
1268
1269 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001270 /*
1271 * wl->vif can be null here if someone shuts down the interface
1272 * just when hardware recovery has been started.
1273 */
1274 if (wl->vif) {
1275 WARN_ON(wl->vif != vif);
1276 __wl1271_op_remove_interface(wl);
1277 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001278
Juuso Oikarinen67353292010-11-18 15:19:02 +02001279 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001280 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281}
1282
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001283static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1284{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001285 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001286
1287 /* combine requested filters with current filter config */
1288 filters = wl->filters | filters;
1289
1290 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1291
1292 if (filters & FIF_PROMISC_IN_BSS) {
1293 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1294 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1295 wl->rx_config |= CFG_BSSID_FILTER_EN;
1296 }
1297 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1298 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1299 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1300 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1301 }
1302 if (filters & FIF_OTHER_BSS) {
1303 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1304 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1305 }
1306 if (filters & FIF_CONTROL) {
1307 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1308 wl->rx_filter |= CFG_RX_CTL_EN;
1309 }
1310 if (filters & FIF_FCSFAIL) {
1311 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1312 wl->rx_filter |= CFG_RX_FCS_ERROR;
1313 }
1314}
1315
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001316static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001317{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001318 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001319 /* we need to use a dummy BSSID for now */
1320 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1321 0xad, 0xbe, 0xef };
1322
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001323 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1324
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001325 /* pass through frames from all BSS */
1326 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1327
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001328 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001329 if (ret < 0)
1330 goto out;
1331
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001332 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001333
1334out:
1335 return ret;
1336}
1337
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001338static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001339{
1340 int ret;
1341
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001342 /*
1343 * One of the side effects of the JOIN command is that is clears
1344 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1345 * to a WPA/WPA2 access point will therefore kill the data-path.
1346 * Currently there is no supported scenario for JOIN during
1347 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1348 * must be handled somehow.
1349 *
1350 */
1351 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1352 wl1271_info("JOIN while associated.");
1353
1354 if (set_assoc)
1355 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1356
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001357 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1358 if (ret < 0)
1359 goto out;
1360
1361 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1362
1363 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1364 goto out;
1365
1366 /*
1367 * The join command disable the keep-alive mode, shut down its process,
1368 * and also clear the template config, so we need to reset it all after
1369 * the join. The acx_aid starts the keep-alive process, and the order
1370 * of the commands below is relevant.
1371 */
1372 ret = wl1271_acx_keep_alive_mode(wl, true);
1373 if (ret < 0)
1374 goto out;
1375
1376 ret = wl1271_acx_aid(wl, wl->aid);
1377 if (ret < 0)
1378 goto out;
1379
1380 ret = wl1271_cmd_build_klv_null_data(wl);
1381 if (ret < 0)
1382 goto out;
1383
1384 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1385 ACX_KEEP_ALIVE_TPL_VALID);
1386 if (ret < 0)
1387 goto out;
1388
1389out:
1390 return ret;
1391}
1392
1393static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001394{
1395 int ret;
1396
1397 /* to stop listening to a channel, we disconnect */
1398 ret = wl1271_cmd_disconnect(wl);
1399 if (ret < 0)
1400 goto out;
1401
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001402 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001403 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001404
1405 /* stop filterting packets based on bssid */
1406 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001407
1408out:
1409 return ret;
1410}
1411
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001412static void wl1271_set_band_rate(struct wl1271 *wl)
1413{
1414 if (wl->band == IEEE80211_BAND_2GHZ)
1415 wl->basic_rate_set = wl->conf.tx.basic_rate;
1416 else
1417 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1418}
1419
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001420static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001421{
1422 int ret;
1423
1424 if (idle) {
1425 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1426 ret = wl1271_unjoin(wl);
1427 if (ret < 0)
1428 goto out;
1429 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001430 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001431 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001432 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001433 if (ret < 0)
1434 goto out;
1435 ret = wl1271_acx_keep_alive_config(
1436 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1437 ACX_KEEP_ALIVE_TPL_INVALID);
1438 if (ret < 0)
1439 goto out;
1440 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1441 } else {
1442 /* increment the session counter */
1443 wl->session_counter++;
1444 if (wl->session_counter >= SESSION_COUNTER_MAX)
1445 wl->session_counter = 0;
1446 ret = wl1271_dummy_join(wl);
1447 if (ret < 0)
1448 goto out;
1449 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1450 }
1451
1452out:
1453 return ret;
1454}
1455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1457{
1458 struct wl1271 *wl = hw->priv;
1459 struct ieee80211_conf *conf = &hw->conf;
1460 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001461 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462
1463 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1464
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001465 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1466 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 channel,
1468 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001469 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001470 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1471 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001473 /*
1474 * mac80211 will go to idle nearly immediately after transmitting some
1475 * frames, such as the deauth. To make sure those frames reach the air,
1476 * wait here until the TX queue is fully flushed.
1477 */
1478 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1479 (conf->flags & IEEE80211_CONF_IDLE))
1480 wl1271_tx_flush(wl);
1481
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 mutex_lock(&wl->mutex);
1483
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001484 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1485 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001486 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001487 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001488
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001489 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491 ret = wl1271_ps_elp_wakeup(wl, false);
1492 if (ret < 0)
1493 goto out;
1494
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001495 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001496 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1497 ((wl->band != conf->channel->band) ||
1498 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001499 wl->band = conf->channel->band;
1500 wl->channel = channel;
1501
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001502 if (!is_ap) {
1503 /*
1504 * FIXME: the mac80211 should really provide a fixed
1505 * rate to use here. for now, just use the smallest
1506 * possible rate for the band as a fixed rate for
1507 * association frames and other control messages.
1508 */
1509 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1510 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001511
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001512 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1513 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001514 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001515 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001516 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001517
1518 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1519 ret = wl1271_join(wl, false);
1520 if (ret < 0)
1521 wl1271_warning("cmd join on channel "
1522 "failed %d", ret);
1523 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001524 }
1525 }
1526
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001527 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1528 ret = wl1271_sta_handle_idle(wl,
1529 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001530 if (ret < 0)
1531 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 }
1533
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001534 /*
1535 * if mac80211 changes the PSM mode, make sure the mode is not
1536 * incorrectly changed after the pspoll failure active window.
1537 */
1538 if (changed & IEEE80211_CONF_CHANGE_PS)
1539 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1540
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001541 if (conf->flags & IEEE80211_CONF_PS &&
1542 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1543 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544
1545 /*
1546 * We enter PSM only if we're already associated.
1547 * If we're not, we'll enter it when joining an SSID,
1548 * through the bss_info_changed() hook.
1549 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001550 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001551 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001552 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001553 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001554 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001555 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001556 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001557 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001559 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001561 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001562 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001563 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001564 }
1565
1566 if (conf->power_level != wl->power_level) {
1567 ret = wl1271_acx_tx_power(wl, conf->power_level);
1568 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001569 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570
1571 wl->power_level = conf->power_level;
1572 }
1573
1574out_sleep:
1575 wl1271_ps_elp_sleep(wl);
1576
1577out:
1578 mutex_unlock(&wl->mutex);
1579
1580 return ret;
1581}
1582
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001583struct wl1271_filter_params {
1584 bool enabled;
1585 int mc_list_length;
1586 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1587};
1588
Jiri Pirko22bedad32010-04-01 21:22:57 +00001589static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1590 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001591{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001592 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001593 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001594 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001595
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001596 if (unlikely(wl->state == WL1271_STATE_OFF))
1597 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001598
Juuso Oikarinen74441132009-10-13 12:47:53 +03001599 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001600 if (!fp) {
1601 wl1271_error("Out of memory setting filters.");
1602 return 0;
1603 }
1604
1605 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001606 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001607 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1608 fp->enabled = false;
1609 } else {
1610 fp->enabled = true;
1611 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001612 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001613 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001614 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001615 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001616 }
1617
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001618 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001619}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001621#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1622 FIF_ALLMULTI | \
1623 FIF_FCSFAIL | \
1624 FIF_BCN_PRBRESP_PROMISC | \
1625 FIF_CONTROL | \
1626 FIF_OTHER_BSS)
1627
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1629 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001630 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001632 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001633 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001634 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635
Arik Nemtsov7d057862010-10-16 19:25:35 +02001636 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1637 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001639 mutex_lock(&wl->mutex);
1640
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001641 *total &= WL1271_SUPPORTED_FILTERS;
1642 changed &= WL1271_SUPPORTED_FILTERS;
1643
1644 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001645 goto out;
1646
1647 ret = wl1271_ps_elp_wakeup(wl, false);
1648 if (ret < 0)
1649 goto out;
1650
Arik Nemtsov7d057862010-10-16 19:25:35 +02001651 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1652 if (*total & FIF_ALLMULTI)
1653 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1654 else if (fp)
1655 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1656 fp->mc_list,
1657 fp->mc_list_length);
1658 if (ret < 0)
1659 goto out_sleep;
1660 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001662 /* determine, whether supported filter values have changed */
1663 if (changed == 0)
1664 goto out_sleep;
1665
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001666 /* configure filters */
1667 wl->filters = *total;
1668 wl1271_configure_filters(wl, 0);
1669
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001670 /* apply configured filters */
1671 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1672 if (ret < 0)
1673 goto out_sleep;
1674
1675out_sleep:
1676 wl1271_ps_elp_sleep(wl);
1677
1678out:
1679 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001680 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001681}
1682
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001683static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1684 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1685 u16 tx_seq_16)
1686{
1687 struct wl1271_ap_key *ap_key;
1688 int i;
1689
1690 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1691
1692 if (key_size > MAX_KEY_SIZE)
1693 return -EINVAL;
1694
1695 /*
1696 * Find next free entry in ap_keys. Also check we are not replacing
1697 * an existing key.
1698 */
1699 for (i = 0; i < MAX_NUM_KEYS; i++) {
1700 if (wl->recorded_ap_keys[i] == NULL)
1701 break;
1702
1703 if (wl->recorded_ap_keys[i]->id == id) {
1704 wl1271_warning("trying to record key replacement");
1705 return -EINVAL;
1706 }
1707 }
1708
1709 if (i == MAX_NUM_KEYS)
1710 return -EBUSY;
1711
1712 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1713 if (!ap_key)
1714 return -ENOMEM;
1715
1716 ap_key->id = id;
1717 ap_key->key_type = key_type;
1718 ap_key->key_size = key_size;
1719 memcpy(ap_key->key, key, key_size);
1720 ap_key->hlid = hlid;
1721 ap_key->tx_seq_32 = tx_seq_32;
1722 ap_key->tx_seq_16 = tx_seq_16;
1723
1724 wl->recorded_ap_keys[i] = ap_key;
1725 return 0;
1726}
1727
1728static void wl1271_free_ap_keys(struct wl1271 *wl)
1729{
1730 int i;
1731
1732 for (i = 0; i < MAX_NUM_KEYS; i++) {
1733 kfree(wl->recorded_ap_keys[i]);
1734 wl->recorded_ap_keys[i] = NULL;
1735 }
1736}
1737
1738static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1739{
1740 int i, ret = 0;
1741 struct wl1271_ap_key *key;
1742 bool wep_key_added = false;
1743
1744 for (i = 0; i < MAX_NUM_KEYS; i++) {
1745 if (wl->recorded_ap_keys[i] == NULL)
1746 break;
1747
1748 key = wl->recorded_ap_keys[i];
1749 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1750 key->id, key->key_type,
1751 key->key_size, key->key,
1752 key->hlid, key->tx_seq_32,
1753 key->tx_seq_16);
1754 if (ret < 0)
1755 goto out;
1756
1757 if (key->key_type == KEY_WEP)
1758 wep_key_added = true;
1759 }
1760
1761 if (wep_key_added) {
1762 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1763 if (ret < 0)
1764 goto out;
1765 }
1766
1767out:
1768 wl1271_free_ap_keys(wl);
1769 return ret;
1770}
1771
1772static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1773 u8 key_size, const u8 *key, u32 tx_seq_32,
1774 u16 tx_seq_16, struct ieee80211_sta *sta)
1775{
1776 int ret;
1777 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1778
1779 if (is_ap) {
1780 struct wl1271_station *wl_sta;
1781 u8 hlid;
1782
1783 if (sta) {
1784 wl_sta = (struct wl1271_station *)sta->drv_priv;
1785 hlid = wl_sta->hlid;
1786 } else {
1787 hlid = WL1271_AP_BROADCAST_HLID;
1788 }
1789
1790 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1791 /*
1792 * We do not support removing keys after AP shutdown.
1793 * Pretend we do to make mac80211 happy.
1794 */
1795 if (action != KEY_ADD_OR_REPLACE)
1796 return 0;
1797
1798 ret = wl1271_record_ap_key(wl, id,
1799 key_type, key_size,
1800 key, hlid, tx_seq_32,
1801 tx_seq_16);
1802 } else {
1803 ret = wl1271_cmd_set_ap_key(wl, action,
1804 id, key_type, key_size,
1805 key, hlid, tx_seq_32,
1806 tx_seq_16);
1807 }
1808
1809 if (ret < 0)
1810 return ret;
1811 } else {
1812 const u8 *addr;
1813 static const u8 bcast_addr[ETH_ALEN] = {
1814 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1815 };
1816
1817 addr = sta ? sta->addr : bcast_addr;
1818
1819 if (is_zero_ether_addr(addr)) {
1820 /* We dont support TX only encryption */
1821 return -EOPNOTSUPP;
1822 }
1823
1824 /* The wl1271 does not allow to remove unicast keys - they
1825 will be cleared automatically on next CMD_JOIN. Ignore the
1826 request silently, as we dont want the mac80211 to emit
1827 an error message. */
1828 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1829 return 0;
1830
1831 ret = wl1271_cmd_set_sta_key(wl, action,
1832 id, key_type, key_size,
1833 key, addr, tx_seq_32,
1834 tx_seq_16);
1835 if (ret < 0)
1836 return ret;
1837
1838 /* the default WEP key needs to be configured at least once */
1839 if (key_type == KEY_WEP) {
1840 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1841 wl->default_key);
1842 if (ret < 0)
1843 return ret;
1844 }
1845 }
1846
1847 return 0;
1848}
1849
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001850static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1851 struct ieee80211_vif *vif,
1852 struct ieee80211_sta *sta,
1853 struct ieee80211_key_conf *key_conf)
1854{
1855 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001857 u32 tx_seq_32 = 0;
1858 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 u8 key_type;
1860
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1862
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001863 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001864 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001865 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 key_conf->keylen, key_conf->flags);
1867 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1868
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001869 mutex_lock(&wl->mutex);
1870
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001871 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1872 ret = -EAGAIN;
1873 goto out_unlock;
1874 }
1875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001876 ret = wl1271_ps_elp_wakeup(wl, false);
1877 if (ret < 0)
1878 goto out_unlock;
1879
Johannes Berg97359d12010-08-10 09:46:38 +02001880 switch (key_conf->cipher) {
1881 case WLAN_CIPHER_SUITE_WEP40:
1882 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 key_type = KEY_WEP;
1884
1885 key_conf->hw_key_idx = key_conf->keyidx;
1886 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001887 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888 key_type = KEY_TKIP;
1889
1890 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001891 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1892 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001893 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001894 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895 key_type = KEY_AES;
1896
1897 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001898 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1899 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001900 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001901 case WL1271_CIPHER_SUITE_GEM:
1902 key_type = KEY_GEM;
1903 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1904 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1905 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001907 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908
1909 ret = -EOPNOTSUPP;
1910 goto out_sleep;
1911 }
1912
1913 switch (cmd) {
1914 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001915 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1916 key_conf->keyidx, key_type,
1917 key_conf->keylen, key_conf->key,
1918 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919 if (ret < 0) {
1920 wl1271_error("Could not add or replace key");
1921 goto out_sleep;
1922 }
1923 break;
1924
1925 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001926 ret = wl1271_set_key(wl, KEY_REMOVE,
1927 key_conf->keyidx, key_type,
1928 key_conf->keylen, key_conf->key,
1929 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 if (ret < 0) {
1931 wl1271_error("Could not remove key");
1932 goto out_sleep;
1933 }
1934 break;
1935
1936 default:
1937 wl1271_error("Unsupported key cmd 0x%x", cmd);
1938 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939 break;
1940 }
1941
1942out_sleep:
1943 wl1271_ps_elp_sleep(wl);
1944
1945out_unlock:
1946 mutex_unlock(&wl->mutex);
1947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 return ret;
1949}
1950
1951static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001952 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 struct cfg80211_scan_request *req)
1954{
1955 struct wl1271 *wl = hw->priv;
1956 int ret;
1957 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001958 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959
1960 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1961
1962 if (req->n_ssids) {
1963 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001964 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 }
1966
1967 mutex_lock(&wl->mutex);
1968
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001969 if (wl->state == WL1271_STATE_OFF) {
1970 /*
1971 * We cannot return -EBUSY here because cfg80211 will expect
1972 * a call to ieee80211_scan_completed if we do - in this case
1973 * there won't be any call.
1974 */
1975 ret = -EAGAIN;
1976 goto out;
1977 }
1978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979 ret = wl1271_ps_elp_wakeup(wl, false);
1980 if (ret < 0)
1981 goto out;
1982
Luciano Coelho5924f892010-08-04 03:46:22 +03001983 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984
1985 wl1271_ps_elp_sleep(wl);
1986
1987out:
1988 mutex_unlock(&wl->mutex);
1989
1990 return ret;
1991}
1992
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001993static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1994{
1995 struct wl1271 *wl = hw->priv;
1996 int ret = 0;
1997
1998 mutex_lock(&wl->mutex);
1999
2000 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2001 ret = -EAGAIN;
2002 goto out;
2003 }
2004
2005 ret = wl1271_ps_elp_wakeup(wl, false);
2006 if (ret < 0)
2007 goto out;
2008
2009 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2010 if (ret < 0)
2011 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2012
2013 wl1271_ps_elp_sleep(wl);
2014
2015out:
2016 mutex_unlock(&wl->mutex);
2017
2018 return ret;
2019}
2020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2022{
2023 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002024 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025
2026 mutex_lock(&wl->mutex);
2027
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002028 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2029 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002030 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002031 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 ret = wl1271_ps_elp_wakeup(wl, false);
2034 if (ret < 0)
2035 goto out;
2036
2037 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2038 if (ret < 0)
2039 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2040
2041 wl1271_ps_elp_sleep(wl);
2042
2043out:
2044 mutex_unlock(&wl->mutex);
2045
2046 return ret;
2047}
2048
Arik Nemtsove78a2872010-10-16 19:07:21 +02002049static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002050 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002051{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002052 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002053
2054 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002055 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002056 if (ptr[0] == WLAN_EID_SSID) {
2057 wl->ssid_len = ptr[1];
2058 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002059 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002060 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002061 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002062 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002063
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002064 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002065 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002066}
2067
Arik Nemtsove78a2872010-10-16 19:07:21 +02002068static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2069 struct ieee80211_bss_conf *bss_conf,
2070 u32 changed)
2071{
2072 int ret = 0;
2073
2074 if (changed & BSS_CHANGED_ERP_SLOT) {
2075 if (bss_conf->use_short_slot)
2076 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2077 else
2078 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2079 if (ret < 0) {
2080 wl1271_warning("Set slot time failed %d", ret);
2081 goto out;
2082 }
2083 }
2084
2085 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2086 if (bss_conf->use_short_preamble)
2087 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2088 else
2089 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2090 }
2091
2092 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2093 if (bss_conf->use_cts_prot)
2094 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2095 else
2096 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2097 if (ret < 0) {
2098 wl1271_warning("Set ctsprotect failed %d", ret);
2099 goto out;
2100 }
2101 }
2102
2103out:
2104 return ret;
2105}
2106
2107static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2108 struct ieee80211_vif *vif,
2109 struct ieee80211_bss_conf *bss_conf,
2110 u32 changed)
2111{
2112 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2113 int ret = 0;
2114
2115 if ((changed & BSS_CHANGED_BEACON_INT)) {
2116 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2117 bss_conf->beacon_int);
2118
2119 wl->beacon_int = bss_conf->beacon_int;
2120 }
2121
2122 if ((changed & BSS_CHANGED_BEACON)) {
2123 struct ieee80211_hdr *hdr;
2124 int ieoffset = offsetof(struct ieee80211_mgmt,
2125 u.beacon.variable);
2126 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2127 u16 tmpl_id;
2128
2129 if (!beacon)
2130 goto out;
2131
2132 wl1271_debug(DEBUG_MASTER, "beacon updated");
2133
2134 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2135 if (ret < 0) {
2136 dev_kfree_skb(beacon);
2137 goto out;
2138 }
2139 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2140 CMD_TEMPL_BEACON;
2141 ret = wl1271_cmd_template_set(wl, tmpl_id,
2142 beacon->data,
2143 beacon->len, 0,
2144 wl1271_tx_min_rate_get(wl));
2145 if (ret < 0) {
2146 dev_kfree_skb(beacon);
2147 goto out;
2148 }
2149
2150 hdr = (struct ieee80211_hdr *) beacon->data;
2151 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2152 IEEE80211_STYPE_PROBE_RESP);
2153
2154 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2155 CMD_TEMPL_PROBE_RESPONSE;
2156 ret = wl1271_cmd_template_set(wl,
2157 tmpl_id,
2158 beacon->data,
2159 beacon->len, 0,
2160 wl1271_tx_min_rate_get(wl));
2161 dev_kfree_skb(beacon);
2162 if (ret < 0)
2163 goto out;
2164 }
2165
2166out:
2167 return ret;
2168}
2169
2170/* AP mode changes */
2171static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 struct ieee80211_vif *vif,
2173 struct ieee80211_bss_conf *bss_conf,
2174 u32 changed)
2175{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002176 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177
Arik Nemtsove78a2872010-10-16 19:07:21 +02002178 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2179 u32 rates = bss_conf->basic_rates;
2180 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Arik Nemtsove78a2872010-10-16 19:07:21 +02002182 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2183 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2184 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2185 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186
Arik Nemtsove78a2872010-10-16 19:07:21 +02002187 /* update the AP management rate policy with the new rates */
2188 mgmt_rc.enabled_rates = wl->basic_rate_set;
2189 mgmt_rc.long_retry_limit = 10;
2190 mgmt_rc.short_retry_limit = 10;
2191 mgmt_rc.aflags = 0;
2192 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2193 ACX_TX_AP_MODE_MGMT_RATE);
2194 if (ret < 0) {
2195 wl1271_error("AP mgmt policy change failed %d", ret);
2196 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002197 }
2198 }
2199
Arik Nemtsove78a2872010-10-16 19:07:21 +02002200 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2201 if (ret < 0)
2202 goto out;
2203
2204 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2205 if (bss_conf->enable_beacon) {
2206 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2207 ret = wl1271_cmd_start_bss(wl);
2208 if (ret < 0)
2209 goto out;
2210
2211 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2212 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002213
2214 ret = wl1271_ap_init_hwenc(wl);
2215 if (ret < 0)
2216 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002217 }
2218 } else {
2219 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2220 ret = wl1271_cmd_stop_bss(wl);
2221 if (ret < 0)
2222 goto out;
2223
2224 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2225 wl1271_debug(DEBUG_AP, "stopped AP");
2226 }
2227 }
2228 }
2229
2230 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2231 if (ret < 0)
2232 goto out;
2233out:
2234 return;
2235}
2236
2237/* STA/IBSS mode changes */
2238static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2239 struct ieee80211_vif *vif,
2240 struct ieee80211_bss_conf *bss_conf,
2241 u32 changed)
2242{
2243 bool do_join = false, set_assoc = false;
2244 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2245 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002246 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002247
2248 if (is_ibss) {
2249 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2250 changed);
2251 if (ret < 0)
2252 goto out;
2253 }
2254
2255 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2256 do_join = true;
2257
2258 /* Need to update the SSID (for filtering etc) */
2259 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2260 do_join = true;
2261
2262 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002263 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2264 bss_conf->enable_beacon ? "enabled" : "disabled");
2265
2266 if (bss_conf->enable_beacon)
2267 wl->set_bss_type = BSS_TYPE_IBSS;
2268 else
2269 wl->set_bss_type = BSS_TYPE_STA_BSS;
2270 do_join = true;
2271 }
2272
Arik Nemtsove78a2872010-10-16 19:07:21 +02002273 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002274 bool enable = false;
2275 if (bss_conf->cqm_rssi_thold)
2276 enable = true;
2277 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2278 bss_conf->cqm_rssi_thold,
2279 bss_conf->cqm_rssi_hyst);
2280 if (ret < 0)
2281 goto out;
2282 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2283 }
2284
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002285 if ((changed & BSS_CHANGED_BSSID) &&
2286 /*
2287 * Now we know the correct bssid, so we send a new join command
2288 * and enable the BSSID filter
2289 */
2290 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002291 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002292
Eliad Pellerfa287b82010-12-26 09:27:50 +01002293 if (!is_zero_ether_addr(wl->bssid)) {
2294 ret = wl1271_cmd_build_null_data(wl);
2295 if (ret < 0)
2296 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002297
Eliad Pellerfa287b82010-12-26 09:27:50 +01002298 ret = wl1271_build_qos_null_data(wl);
2299 if (ret < 0)
2300 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002301
Eliad Pellerfa287b82010-12-26 09:27:50 +01002302 /* filter out all packets not from this BSSID */
2303 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002304
Eliad Pellerfa287b82010-12-26 09:27:50 +01002305 /* Need to update the BSSID (for filtering etc) */
2306 do_join = true;
2307 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002308 }
2309
Arik Nemtsove78a2872010-10-16 19:07:21 +02002310 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002312 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002313 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002314 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002315 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002317 wl->ps_poll_failures = 0;
2318
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002319 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002320 * use basic rates from AP, and determine lowest rate
2321 * to use with control frames.
2322 */
2323 rates = bss_conf->basic_rates;
2324 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2325 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002326 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002327 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002328 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002329 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002330
2331 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002332 * with wl1271, we don't need to update the
2333 * beacon_int and dtim_period, because the firmware
2334 * updates it by itself when the first beacon is
2335 * received after a join.
2336 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2338 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002339 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002341 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002342 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002343 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002344 dev_kfree_skb(wl->probereq);
2345 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2346 ieoffset = offsetof(struct ieee80211_mgmt,
2347 u.probe_req.variable);
2348 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002349
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002350 /* enable the connection monitoring feature */
2351 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002353 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002354
2355 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002356 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2357 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002358 enum wl1271_cmd_ps_mode mode;
2359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002361 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002362 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002363 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002365 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002367 } else {
2368 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002369 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002370 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002371 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002372
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002373 /* free probe-request template */
2374 dev_kfree_skb(wl->probereq);
2375 wl->probereq = NULL;
2376
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002377 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002378 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002379
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002380 /* revert back to minimum rates for the current band */
2381 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002382 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002383 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002384 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002385 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002386
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002387 /* disable connection monitor features */
2388 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002389
2390 /* Disable the keep-alive feature */
2391 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002392 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002393 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002394
2395 /* restore the bssid filter and go to dummy bssid */
2396 wl1271_unjoin(wl);
2397 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398 }
2399 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002400
Arik Nemtsove78a2872010-10-16 19:07:21 +02002401 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2402 if (ret < 0)
2403 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002405 rcu_read_lock();
2406 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2407 if (sta) {
2408 /* handle new association with HT and HT information change */
2409 if ((changed & BSS_CHANGED_HT) &&
2410 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2411 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2412 true);
2413 if (ret < 0) {
2414 wl1271_warning("Set ht cap true failed %d",
2415 ret);
2416 rcu_read_unlock();
2417 goto out;
2418 }
Shahar Levi18357852010-10-13 16:09:41 +02002419 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002420 bss_conf->ht_operation_mode);
2421 if (ret < 0) {
2422 wl1271_warning("Set ht information failed %d",
2423 ret);
2424 rcu_read_unlock();
2425 goto out;
2426 }
2427 }
2428 /* handle new association without HT and disassociation */
2429 else if (changed & BSS_CHANGED_ASSOC) {
2430 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2431 false);
2432 if (ret < 0) {
2433 wl1271_warning("Set ht cap false failed %d",
2434 ret);
2435 rcu_read_unlock();
2436 goto out;
2437 }
Shahar Levi18357852010-10-13 16:09:41 +02002438 }
2439 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002440 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002441
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002442 if (changed & BSS_CHANGED_ARP_FILTER) {
2443 __be32 addr = bss_conf->arp_addr_list[0];
2444 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2445
Eliad Pellerc5312772010-12-09 11:31:27 +02002446 if (bss_conf->arp_addr_cnt == 1 &&
2447 bss_conf->arp_filter_enabled) {
2448 /*
2449 * The template should have been configured only upon
2450 * association. however, it seems that the correct ip
2451 * isn't being set (when sending), so we have to
2452 * reconfigure the template upon every ip change.
2453 */
2454 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2455 if (ret < 0) {
2456 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002457 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002458 }
2459
2460 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002461 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002462 addr);
2463 } else
2464 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002465
2466 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002467 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002468 }
2469
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002470 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002471 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002472 if (ret < 0) {
2473 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002474 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002475 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002476 }
2477
Arik Nemtsove78a2872010-10-16 19:07:21 +02002478out:
2479 return;
2480}
2481
2482static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2483 struct ieee80211_vif *vif,
2484 struct ieee80211_bss_conf *bss_conf,
2485 u32 changed)
2486{
2487 struct wl1271 *wl = hw->priv;
2488 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2489 int ret;
2490
2491 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2492 (int)changed);
2493
2494 mutex_lock(&wl->mutex);
2495
2496 if (unlikely(wl->state == WL1271_STATE_OFF))
2497 goto out;
2498
2499 ret = wl1271_ps_elp_wakeup(wl, false);
2500 if (ret < 0)
2501 goto out;
2502
2503 if (is_ap)
2504 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2505 else
2506 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508 wl1271_ps_elp_sleep(wl);
2509
2510out:
2511 mutex_unlock(&wl->mutex);
2512}
2513
Kalle Valoc6999d82010-02-18 13:25:41 +02002514static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2515 const struct ieee80211_tx_queue_params *params)
2516{
2517 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002518 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002519 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002520
2521 mutex_lock(&wl->mutex);
2522
2523 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2524
Kalle Valo4695dc92010-03-18 12:26:38 +02002525 if (params->uapsd)
2526 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2527 else
2528 ps_scheme = CONF_PS_SCHEME_LEGACY;
2529
Arik Nemtsov488fc542010-10-16 20:33:45 +02002530 if (wl->state == WL1271_STATE_OFF) {
2531 /*
2532 * If the state is off, the parameters will be recorded and
2533 * configured on init. This happens in AP-mode.
2534 */
2535 struct conf_tx_ac_category *conf_ac =
2536 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2537 struct conf_tx_tid *conf_tid =
2538 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2539
2540 conf_ac->ac = wl1271_tx_get_queue(queue);
2541 conf_ac->cw_min = (u8)params->cw_min;
2542 conf_ac->cw_max = params->cw_max;
2543 conf_ac->aifsn = params->aifs;
2544 conf_ac->tx_op_limit = params->txop << 5;
2545
2546 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2547 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2548 conf_tid->tsid = wl1271_tx_get_queue(queue);
2549 conf_tid->ps_scheme = ps_scheme;
2550 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2551 conf_tid->apsd_conf[0] = 0;
2552 conf_tid->apsd_conf[1] = 0;
2553 } else {
2554 ret = wl1271_ps_elp_wakeup(wl, false);
2555 if (ret < 0)
2556 goto out;
2557
2558 /*
2559 * the txop is confed in units of 32us by the mac80211,
2560 * we need us
2561 */
2562 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2563 params->cw_min, params->cw_max,
2564 params->aifs, params->txop << 5);
2565 if (ret < 0)
2566 goto out_sleep;
2567
2568 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2569 CONF_CHANNEL_TYPE_EDCF,
2570 wl1271_tx_get_queue(queue),
2571 ps_scheme, CONF_ACK_POLICY_LEGACY,
2572 0, 0);
2573 if (ret < 0)
2574 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002575
2576out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002577 wl1271_ps_elp_sleep(wl);
2578 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002579
2580out:
2581 mutex_unlock(&wl->mutex);
2582
2583 return ret;
2584}
2585
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002586static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2587{
2588
2589 struct wl1271 *wl = hw->priv;
2590 u64 mactime = ULLONG_MAX;
2591 int ret;
2592
2593 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2594
2595 mutex_lock(&wl->mutex);
2596
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002597 if (unlikely(wl->state == WL1271_STATE_OFF))
2598 goto out;
2599
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002600 ret = wl1271_ps_elp_wakeup(wl, false);
2601 if (ret < 0)
2602 goto out;
2603
2604 ret = wl1271_acx_tsf_info(wl, &mactime);
2605 if (ret < 0)
2606 goto out_sleep;
2607
2608out_sleep:
2609 wl1271_ps_elp_sleep(wl);
2610
2611out:
2612 mutex_unlock(&wl->mutex);
2613 return mactime;
2614}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002615
John W. Linvilleece550d2010-07-28 16:41:06 -04002616static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2617 struct survey_info *survey)
2618{
2619 struct wl1271 *wl = hw->priv;
2620 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002621
John W. Linvilleece550d2010-07-28 16:41:06 -04002622 if (idx != 0)
2623 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002624
John W. Linvilleece550d2010-07-28 16:41:06 -04002625 survey->channel = conf->channel;
2626 survey->filled = SURVEY_INFO_NOISE_DBM;
2627 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002628
John W. Linvilleece550d2010-07-28 16:41:06 -04002629 return 0;
2630}
2631
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002632static int wl1271_allocate_hlid(struct wl1271 *wl,
2633 struct ieee80211_sta *sta,
2634 u8 *hlid)
2635{
2636 struct wl1271_station *wl_sta;
2637 int id;
2638
2639 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2640 if (id >= AP_MAX_STATIONS) {
2641 wl1271_warning("could not allocate HLID - too much stations");
2642 return -EBUSY;
2643 }
2644
2645 wl_sta = (struct wl1271_station *)sta->drv_priv;
2646
2647 __set_bit(id, wl->ap_hlid_map);
2648 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2649 *hlid = wl_sta->hlid;
2650 return 0;
2651}
2652
2653static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2654{
2655 int id = hlid - WL1271_AP_STA_HLID_START;
2656
2657 __clear_bit(id, wl->ap_hlid_map);
2658}
2659
2660static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2661 struct ieee80211_vif *vif,
2662 struct ieee80211_sta *sta)
2663{
2664 struct wl1271 *wl = hw->priv;
2665 int ret = 0;
2666 u8 hlid;
2667
2668 mutex_lock(&wl->mutex);
2669
2670 if (unlikely(wl->state == WL1271_STATE_OFF))
2671 goto out;
2672
2673 if (wl->bss_type != BSS_TYPE_AP_BSS)
2674 goto out;
2675
2676 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2677
2678 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2679 if (ret < 0)
2680 goto out;
2681
2682 ret = wl1271_ps_elp_wakeup(wl, false);
2683 if (ret < 0)
2684 goto out;
2685
2686 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2687 if (ret < 0)
2688 goto out_sleep;
2689
2690out_sleep:
2691 wl1271_ps_elp_sleep(wl);
2692
2693out:
2694 mutex_unlock(&wl->mutex);
2695 return ret;
2696}
2697
2698static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2699 struct ieee80211_vif *vif,
2700 struct ieee80211_sta *sta)
2701{
2702 struct wl1271 *wl = hw->priv;
2703 struct wl1271_station *wl_sta;
2704 int ret = 0, id;
2705
2706 mutex_lock(&wl->mutex);
2707
2708 if (unlikely(wl->state == WL1271_STATE_OFF))
2709 goto out;
2710
2711 if (wl->bss_type != BSS_TYPE_AP_BSS)
2712 goto out;
2713
2714 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2715
2716 wl_sta = (struct wl1271_station *)sta->drv_priv;
2717 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2718 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2719 goto out;
2720
2721 ret = wl1271_ps_elp_wakeup(wl, false);
2722 if (ret < 0)
2723 goto out;
2724
2725 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2726 if (ret < 0)
2727 goto out_sleep;
2728
2729 wl1271_free_hlid(wl, wl_sta->hlid);
2730
2731out_sleep:
2732 wl1271_ps_elp_sleep(wl);
2733
2734out:
2735 mutex_unlock(&wl->mutex);
2736 return ret;
2737}
2738
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002739int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002740 enum ieee80211_ampdu_mlme_action action,
2741 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2742 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002743{
2744 struct wl1271 *wl = hw->priv;
2745 int ret;
2746
2747 mutex_lock(&wl->mutex);
2748
2749 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2750 ret = -EAGAIN;
2751 goto out;
2752 }
2753
2754 ret = wl1271_ps_elp_wakeup(wl, false);
2755 if (ret < 0)
2756 goto out;
2757
2758 switch (action) {
2759 case IEEE80211_AMPDU_RX_START:
2760 if (wl->ba_support) {
2761 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2762 true);
2763 if (!ret)
2764 wl->ba_rx_bitmap |= BIT(tid);
2765 } else {
2766 ret = -ENOTSUPP;
2767 }
2768 break;
2769
2770 case IEEE80211_AMPDU_RX_STOP:
2771 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2772 if (!ret)
2773 wl->ba_rx_bitmap &= ~BIT(tid);
2774 break;
2775
2776 /*
2777 * The BA initiator session management in FW independently.
2778 * Falling break here on purpose for all TX APDU commands.
2779 */
2780 case IEEE80211_AMPDU_TX_START:
2781 case IEEE80211_AMPDU_TX_STOP:
2782 case IEEE80211_AMPDU_TX_OPERATIONAL:
2783 ret = -EINVAL;
2784 break;
2785
2786 default:
2787 wl1271_error("Incorrect ampdu action id=%x\n", action);
2788 ret = -EINVAL;
2789 }
2790
2791 wl1271_ps_elp_sleep(wl);
2792
2793out:
2794 mutex_unlock(&wl->mutex);
2795
2796 return ret;
2797}
2798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799/* can't be const, mac80211 writes to this */
2800static struct ieee80211_rate wl1271_rates[] = {
2801 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002802 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2803 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002805 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2806 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2808 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002809 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2810 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2812 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002813 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2814 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2816 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002817 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2818 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002820 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2821 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002822 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002823 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2824 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002826 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2827 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002829 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2830 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002832 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2833 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002834 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002835 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2836 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002837 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002838 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2839 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002840};
2841
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002842/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002843static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002844 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002845 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002846 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2847 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2848 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002849 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002850 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2851 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2852 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002853 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002854 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2855 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2856 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002857 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002858};
2859
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002860/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002861static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002862 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002863 7, /* CONF_HW_RXTX_RATE_MCS7 */
2864 6, /* CONF_HW_RXTX_RATE_MCS6 */
2865 5, /* CONF_HW_RXTX_RATE_MCS5 */
2866 4, /* CONF_HW_RXTX_RATE_MCS4 */
2867 3, /* CONF_HW_RXTX_RATE_MCS3 */
2868 2, /* CONF_HW_RXTX_RATE_MCS2 */
2869 1, /* CONF_HW_RXTX_RATE_MCS1 */
2870 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002871
2872 11, /* CONF_HW_RXTX_RATE_54 */
2873 10, /* CONF_HW_RXTX_RATE_48 */
2874 9, /* CONF_HW_RXTX_RATE_36 */
2875 8, /* CONF_HW_RXTX_RATE_24 */
2876
2877 /* TI-specific rate */
2878 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2879
2880 7, /* CONF_HW_RXTX_RATE_18 */
2881 6, /* CONF_HW_RXTX_RATE_12 */
2882 3, /* CONF_HW_RXTX_RATE_11 */
2883 5, /* CONF_HW_RXTX_RATE_9 */
2884 4, /* CONF_HW_RXTX_RATE_6 */
2885 2, /* CONF_HW_RXTX_RATE_5_5 */
2886 1, /* CONF_HW_RXTX_RATE_2 */
2887 0 /* CONF_HW_RXTX_RATE_1 */
2888};
2889
Shahar Levie8b03a22010-10-13 16:09:39 +02002890/* 11n STA capabilities */
2891#define HW_RX_HIGHEST_RATE 72
2892
Shahar Levi00d20102010-11-08 11:20:10 +00002893#ifdef CONFIG_WL12XX_HT
2894#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002895 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2896 .ht_supported = true, \
2897 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2898 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2899 .mcs = { \
2900 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2901 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2902 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2903 }, \
2904}
Shahar Levi18357852010-10-13 16:09:41 +02002905#else
Shahar Levi00d20102010-11-08 11:20:10 +00002906#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002907 .ht_supported = false, \
2908}
2909#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002911/* can't be const, mac80211 writes to this */
2912static struct ieee80211_supported_band wl1271_band_2ghz = {
2913 .channels = wl1271_channels,
2914 .n_channels = ARRAY_SIZE(wl1271_channels),
2915 .bitrates = wl1271_rates,
2916 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002917 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918};
2919
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002920/* 5 GHz data rates for WL1273 */
2921static struct ieee80211_rate wl1271_rates_5ghz[] = {
2922 { .bitrate = 60,
2923 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2924 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2925 { .bitrate = 90,
2926 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2927 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2928 { .bitrate = 120,
2929 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2930 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2931 { .bitrate = 180,
2932 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2933 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2934 { .bitrate = 240,
2935 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2936 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2937 { .bitrate = 360,
2938 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2939 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2940 { .bitrate = 480,
2941 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2942 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2943 { .bitrate = 540,
2944 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2945 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2946};
2947
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002948/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002949static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002950 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002951 { .hw_value = 8, .center_freq = 5040},
2952 { .hw_value = 9, .center_freq = 5045},
2953 { .hw_value = 11, .center_freq = 5055},
2954 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002955 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002956 { .hw_value = 34, .center_freq = 5170},
2957 { .hw_value = 36, .center_freq = 5180},
2958 { .hw_value = 38, .center_freq = 5190},
2959 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002960 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002961 { .hw_value = 44, .center_freq = 5220},
2962 { .hw_value = 46, .center_freq = 5230},
2963 { .hw_value = 48, .center_freq = 5240},
2964 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002965 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002966 { .hw_value = 60, .center_freq = 5300},
2967 { .hw_value = 64, .center_freq = 5320},
2968 { .hw_value = 100, .center_freq = 5500},
2969 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002970 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002971 { .hw_value = 112, .center_freq = 5560},
2972 { .hw_value = 116, .center_freq = 5580},
2973 { .hw_value = 120, .center_freq = 5600},
2974 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002975 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002976 { .hw_value = 132, .center_freq = 5660},
2977 { .hw_value = 136, .center_freq = 5680},
2978 { .hw_value = 140, .center_freq = 5700},
2979 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002980 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002981 { .hw_value = 157, .center_freq = 5785},
2982 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002983 { .hw_value = 165, .center_freq = 5825},
2984};
2985
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002986/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002987static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002988 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002989 7, /* CONF_HW_RXTX_RATE_MCS7 */
2990 6, /* CONF_HW_RXTX_RATE_MCS6 */
2991 5, /* CONF_HW_RXTX_RATE_MCS5 */
2992 4, /* CONF_HW_RXTX_RATE_MCS4 */
2993 3, /* CONF_HW_RXTX_RATE_MCS3 */
2994 2, /* CONF_HW_RXTX_RATE_MCS2 */
2995 1, /* CONF_HW_RXTX_RATE_MCS1 */
2996 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002997
2998 7, /* CONF_HW_RXTX_RATE_54 */
2999 6, /* CONF_HW_RXTX_RATE_48 */
3000 5, /* CONF_HW_RXTX_RATE_36 */
3001 4, /* CONF_HW_RXTX_RATE_24 */
3002
3003 /* TI-specific rate */
3004 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3005
3006 3, /* CONF_HW_RXTX_RATE_18 */
3007 2, /* CONF_HW_RXTX_RATE_12 */
3008 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3009 1, /* CONF_HW_RXTX_RATE_9 */
3010 0, /* CONF_HW_RXTX_RATE_6 */
3011 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3012 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3013 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3014};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003015
3016static struct ieee80211_supported_band wl1271_band_5ghz = {
3017 .channels = wl1271_channels_5ghz,
3018 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3019 .bitrates = wl1271_rates_5ghz,
3020 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003021 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003022};
3023
Tobias Klausera0ea9492010-05-20 10:38:11 +02003024static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003025 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3026 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3027};
3028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029static const struct ieee80211_ops wl1271_ops = {
3030 .start = wl1271_op_start,
3031 .stop = wl1271_op_stop,
3032 .add_interface = wl1271_op_add_interface,
3033 .remove_interface = wl1271_op_remove_interface,
3034 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003035 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036 .configure_filter = wl1271_op_configure_filter,
3037 .tx = wl1271_op_tx,
3038 .set_key = wl1271_op_set_key,
3039 .hw_scan = wl1271_op_hw_scan,
3040 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003041 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003042 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003043 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003044 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003045 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003046 .sta_add = wl1271_op_sta_add,
3047 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003048 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003049 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050};
3051
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003052
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003053u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003054{
3055 u8 idx;
3056
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003057 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003058
3059 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3060 wl1271_error("Illegal RX rate from HW: %d", rate);
3061 return 0;
3062 }
3063
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003064 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003065 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3066 wl1271_error("Unsupported RX rate from HW: %d", rate);
3067 return 0;
3068 }
3069
3070 return idx;
3071}
3072
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003073static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3074 struct device_attribute *attr,
3075 char *buf)
3076{
3077 struct wl1271 *wl = dev_get_drvdata(dev);
3078 ssize_t len;
3079
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003080 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003081
3082 mutex_lock(&wl->mutex);
3083 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3084 wl->sg_enabled);
3085 mutex_unlock(&wl->mutex);
3086
3087 return len;
3088
3089}
3090
3091static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3092 struct device_attribute *attr,
3093 const char *buf, size_t count)
3094{
3095 struct wl1271 *wl = dev_get_drvdata(dev);
3096 unsigned long res;
3097 int ret;
3098
3099 ret = strict_strtoul(buf, 10, &res);
3100
3101 if (ret < 0) {
3102 wl1271_warning("incorrect value written to bt_coex_mode");
3103 return count;
3104 }
3105
3106 mutex_lock(&wl->mutex);
3107
3108 res = !!res;
3109
3110 if (res == wl->sg_enabled)
3111 goto out;
3112
3113 wl->sg_enabled = res;
3114
3115 if (wl->state == WL1271_STATE_OFF)
3116 goto out;
3117
3118 ret = wl1271_ps_elp_wakeup(wl, false);
3119 if (ret < 0)
3120 goto out;
3121
3122 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3123 wl1271_ps_elp_sleep(wl);
3124
3125 out:
3126 mutex_unlock(&wl->mutex);
3127 return count;
3128}
3129
3130static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3131 wl1271_sysfs_show_bt_coex_state,
3132 wl1271_sysfs_store_bt_coex_state);
3133
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003134static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3135 struct device_attribute *attr,
3136 char *buf)
3137{
3138 struct wl1271 *wl = dev_get_drvdata(dev);
3139 ssize_t len;
3140
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003141 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003142
3143 mutex_lock(&wl->mutex);
3144 if (wl->hw_pg_ver >= 0)
3145 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3146 else
3147 len = snprintf(buf, len, "n/a\n");
3148 mutex_unlock(&wl->mutex);
3149
3150 return len;
3151}
3152
3153static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3154 wl1271_sysfs_show_hw_pg_ver, NULL);
3155
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003156int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003157{
3158 int ret;
3159
3160 if (wl->mac80211_registered)
3161 return 0;
3162
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003163 ret = wl1271_fetch_nvs(wl);
3164 if (ret == 0) {
3165 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3166
3167 wl->mac_addr[0] = nvs_ptr[11];
3168 wl->mac_addr[1] = nvs_ptr[10];
3169 wl->mac_addr[2] = nvs_ptr[6];
3170 wl->mac_addr[3] = nvs_ptr[5];
3171 wl->mac_addr[4] = nvs_ptr[4];
3172 wl->mac_addr[5] = nvs_ptr[3];
3173 }
3174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003175 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3176
3177 ret = ieee80211_register_hw(wl->hw);
3178 if (ret < 0) {
3179 wl1271_error("unable to register mac80211 hw: %d", ret);
3180 return ret;
3181 }
3182
3183 wl->mac80211_registered = true;
3184
Eliad Pellerd60080a2010-11-24 12:53:16 +02003185 wl1271_debugfs_init(wl);
3186
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003187 register_netdevice_notifier(&wl1271_dev_notifier);
3188
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003189 wl1271_notice("loaded");
3190
3191 return 0;
3192}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003193EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003194
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003195void wl1271_unregister_hw(struct wl1271 *wl)
3196{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003197 if (wl->state == WL1271_STATE_PLT)
3198 __wl1271_plt_stop(wl);
3199
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003200 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003201 ieee80211_unregister_hw(wl->hw);
3202 wl->mac80211_registered = false;
3203
3204}
3205EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3206
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003207int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003209 static const u32 cipher_suites[] = {
3210 WLAN_CIPHER_SUITE_WEP40,
3211 WLAN_CIPHER_SUITE_WEP104,
3212 WLAN_CIPHER_SUITE_TKIP,
3213 WLAN_CIPHER_SUITE_CCMP,
3214 WL1271_CIPHER_SUITE_GEM,
3215 };
3216
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003217 /* The tx descriptor buffer and the TKIP space. */
3218 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3219 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220
3221 /* unit us */
3222 /* FIXME: find a proper value */
3223 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003224 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003225
3226 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003227 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003228 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003229 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003230 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003231 IEEE80211_HW_CONNECTION_MONITOR |
3232 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003233
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003234 wl->hw->wiphy->cipher_suites = cipher_suites;
3235 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3236
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003237 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003238 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003239 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003240 /*
3241 * Maximum length of elements in scanning probe request templates
3242 * should be the maximum length possible for a template, without
3243 * the IEEE80211 header of the template
3244 */
3245 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3246 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003247
3248 /*
3249 * We keep local copies of the band structs because we need to
3250 * modify them on a per-device basis.
3251 */
3252 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3253 sizeof(wl1271_band_2ghz));
3254 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3255 sizeof(wl1271_band_5ghz));
3256
3257 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3258 &wl->bands[IEEE80211_BAND_2GHZ];
3259 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3260 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003261
Kalle Valo12bd8942010-03-18 12:26:33 +02003262 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003263 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003264
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003265 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3266
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003267 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003269 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3270
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003271 wl->hw->max_rx_aggregation_subframes = 8;
3272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003273 return 0;
3274}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003275EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003276
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003277#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003278
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003279struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003280{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003281 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003282 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003283 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003284 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003285 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003286
3287 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3288 if (!hw) {
3289 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003290 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003291 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003292 }
3293
Julia Lawall929ebd32010-05-15 23:16:39 +02003294 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003295 if (!plat_dev) {
3296 wl1271_error("could not allocate platform_device");
3297 ret = -ENOMEM;
3298 goto err_plat_alloc;
3299 }
3300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003301 wl = hw->priv;
3302 memset(wl, 0, sizeof(*wl));
3303
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003304 INIT_LIST_HEAD(&wl->list);
3305
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003307 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003309 for (i = 0; i < NUM_TX_QUEUES; i++)
3310 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003312 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003313 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003314 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3315 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3316 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3317 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003318 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003319 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003320 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003321 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003322 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3323 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003324 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003326 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003327 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003328 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3329 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003330 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003331 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003332 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003333 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003334 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003335 wl->bss_type = MAX_BSS_TYPE;
3336 wl->set_bss_type = MAX_BSS_TYPE;
3337 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003338
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003339 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003340 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341 wl->tx_frames[i] = NULL;
3342
3343 spin_lock_init(&wl->wl_lock);
3344
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003345 wl->state = WL1271_STATE_OFF;
3346 mutex_init(&wl->mutex);
3347
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003348 /* Apply default driver configuration. */
3349 wl1271_conf_init(wl);
3350
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003351 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3352 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3353 if (!wl->aggr_buf) {
3354 ret = -ENOMEM;
3355 goto err_hw;
3356 }
3357
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003358 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003359 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003360 if (ret) {
3361 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003362 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003363 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003364 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003365
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003366 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003367 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003368 if (ret < 0) {
3369 wl1271_error("failed to create sysfs file bt_coex_state");
3370 goto err_platform;
3371 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003372
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003373 /* Create sysfs file to get HW PG version */
3374 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3375 if (ret < 0) {
3376 wl1271_error("failed to create sysfs file hw_pg_ver");
3377 goto err_bt_coex_state;
3378 }
3379
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003380 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003381
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003382err_bt_coex_state:
3383 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3384
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003385err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003386 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003387
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003388err_aggr:
3389 free_pages((unsigned long)wl->aggr_buf, order);
3390
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003391err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003392 wl1271_debugfs_exit(wl);
3393 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003394
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003395err_plat_alloc:
3396 ieee80211_free_hw(hw);
3397
3398err_hw_alloc:
3399
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003400 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003401}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003402EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003403
3404int wl1271_free_hw(struct wl1271 *wl)
3405{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003406 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003407 free_pages((unsigned long)wl->aggr_buf,
3408 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003409 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003410
3411 wl1271_debugfs_exit(wl);
3412
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003413 vfree(wl->fw);
3414 wl->fw = NULL;
3415 kfree(wl->nvs);
3416 wl->nvs = NULL;
3417
3418 kfree(wl->fw_status);
3419 kfree(wl->tx_res_if);
3420
3421 ieee80211_free_hw(wl->hw);
3422
3423 return 0;
3424}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003425EXPORT_SYMBOL_GPL(wl1271_free_hw);
3426
Guy Eilam491bbd62011-01-12 10:33:29 +01003427u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003428EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003429module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003430MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3431
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003432MODULE_LICENSE("GPL");
3433MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3434MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");