blob: 24cdc78c00b356b74e70fc2bcf2178fd6e256756 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200259 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_nullfunc_retries = 3,
261 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300262 .keep_alive_interval = 55000,
263 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200265 .itrim = {
266 .enable = false,
267 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200268 },
269 .pm_config = {
270 .host_clk_settling_time = 5000,
271 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300272 },
273 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 .trigger_pacing = 1,
275 .avg_weight_rssi_beacon = 20,
276 .avg_weight_rssi_data = 10,
277 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100278 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200279 },
280 .scan = {
281 .min_dwell_time_active = 7500,
282 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100283 .min_dwell_time_passive = 100000,
284 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200285 .num_probe_reqs = 2,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
300 },
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .mem = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 70,
305 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200306 .dynamic_memory = 0,
307 .min_req_tx_blocks = 104,
308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
310 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311};
312
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200313static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200314static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200315
316
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200317static void wl1271_device_release(struct device *dev)
318{
319
320}
321
322static struct platform_device wl1271_device = {
323 .name = "wl1271",
324 .id = -1,
325
326 /* device model insists to have a release function */
327 .dev = {
328 .release = wl1271_device_release,
329 },
330};
331
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300332static LIST_HEAD(wl_list);
333
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300334static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
335 void *arg)
336{
337 struct net_device *dev = arg;
338 struct wireless_dev *wdev;
339 struct wiphy *wiphy;
340 struct ieee80211_hw *hw;
341 struct wl1271 *wl;
342 struct wl1271 *wl_temp;
343 int ret = 0;
344
345 /* Check that this notification is for us. */
346 if (what != NETDEV_CHANGE)
347 return NOTIFY_DONE;
348
349 wdev = dev->ieee80211_ptr;
350 if (wdev == NULL)
351 return NOTIFY_DONE;
352
353 wiphy = wdev->wiphy;
354 if (wiphy == NULL)
355 return NOTIFY_DONE;
356
357 hw = wiphy_priv(wiphy);
358 if (hw == NULL)
359 return NOTIFY_DONE;
360
361 wl_temp = hw->priv;
362 list_for_each_entry(wl, &wl_list, list) {
363 if (wl == wl_temp)
364 break;
365 }
366 if (wl != wl_temp)
367 return NOTIFY_DONE;
368
369 mutex_lock(&wl->mutex);
370
371 if (wl->state == WL1271_STATE_OFF)
372 goto out;
373
374 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
375 goto out;
376
377 ret = wl1271_ps_elp_wakeup(wl, false);
378 if (ret < 0)
379 goto out;
380
381 if ((dev->operstate == IF_OPER_UP) &&
382 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
383 wl1271_cmd_set_sta_state(wl);
384 wl1271_info("Association completed.");
385 }
386
387 wl1271_ps_elp_sleep(wl);
388
389out:
390 mutex_unlock(&wl->mutex);
391
392 return NOTIFY_OK;
393}
394
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100395static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200396 struct regulatory_request *request)
397{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100398 struct ieee80211_supported_band *band;
399 struct ieee80211_channel *ch;
400 int i;
401
402 band = wiphy->bands[IEEE80211_BAND_5GHZ];
403 for (i = 0; i < band->n_channels; i++) {
404 ch = &band->channels[i];
405 if (ch->flags & IEEE80211_CHAN_DISABLED)
406 continue;
407
408 if (ch->flags & IEEE80211_CHAN_RADAR)
409 ch->flags |= IEEE80211_CHAN_NO_IBSS |
410 IEEE80211_CHAN_PASSIVE_SCAN;
411
412 }
413
414 return 0;
415}
416
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417static void wl1271_conf_init(struct wl1271 *wl)
418{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300419
420 /*
421 * This function applies the default configuration to the driver. This
422 * function is invoked upon driver load (spi probe.)
423 *
424 * The configuration is stored in a run-time structure in order to
425 * facilitate for run-time adjustment of any of the parameters. Making
426 * changes to the configuration structure will apply the new values on
427 * the next interface up (wl1271_op_start.)
428 */
429
430 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300431 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300432}
433
434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435static int wl1271_plt_init(struct wl1271 *wl)
436{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 struct conf_tx_ac_category *conf_ac;
438 struct conf_tx_tid *conf_tid;
439 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200441 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200442 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200443 return ret;
444
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200445 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200446 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200447 return ret;
448
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200449 ret = wl1271_cmd_ext_radio_parms(wl);
450 if (ret < 0)
451 return ret;
452
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200453 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200454 if (ret < 0)
455 return ret;
456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457 ret = wl1271_acx_init_mem_config(wl);
458 if (ret < 0)
459 return ret;
460
Luciano Coelho12419cc2010-02-18 13:25:44 +0200461 /* PHY layer config */
462 ret = wl1271_init_phy_config(wl);
463 if (ret < 0)
464 goto out_free_memmap;
465
466 ret = wl1271_acx_dco_itrim_params(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200471 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
475 /* Bluetooth WLAN coexistence */
476 ret = wl1271_init_pta(wl);
477 if (ret < 0)
478 goto out_free_memmap;
479
480 /* Energy detection */
481 ret = wl1271_init_energy_detection(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
485 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100486 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200487 if (ret < 0)
488 goto out_free_memmap;
489
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200490 /* Default TID/AC configuration */
491 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200492 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200493 conf_ac = &wl->conf.tx.ac_conf[i];
494 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
495 conf_ac->cw_max, conf_ac->aifsn,
496 conf_ac->tx_op_limit);
497 if (ret < 0)
498 goto out_free_memmap;
499
Luciano Coelho12419cc2010-02-18 13:25:44 +0200500 conf_tid = &wl->conf.tx.tid_conf[i];
501 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
502 conf_tid->channel_type,
503 conf_tid->tsid,
504 conf_tid->ps_scheme,
505 conf_tid->ack_policy,
506 conf_tid->apsd_conf[0],
507 conf_tid->apsd_conf[1]);
508 if (ret < 0)
509 goto out_free_memmap;
510 }
511
Luciano Coelho12419cc2010-02-18 13:25:44 +0200512 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200513 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200515 goto out_free_memmap;
516
517 /* Configure for CAM power saving (ie. always active) */
518 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
519 if (ret < 0)
520 goto out_free_memmap;
521
522 /* configure PM */
523 ret = wl1271_acx_pm_config(wl);
524 if (ret < 0)
525 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300526
527 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200528
529 out_free_memmap:
530 kfree(wl->target_mem_map);
531 wl->target_mem_map = NULL;
532
533 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300534}
535
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300536static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200537 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200539 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200540 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300541 u32 total = 0;
542 int i;
543
Eliad Pellerc8bde242011-02-02 09:59:35 +0200544 if (wl->bss_type == BSS_TYPE_AP_BSS)
545 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
546 sizeof(struct wl1271_fw_ap_status), false);
547 else
548 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
549 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300550
551 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
552 "drv_rx_counter = %d, tx_results_counter = %d)",
553 status->intr,
554 status->fw_rx_counter,
555 status->drv_rx_counter,
556 status->tx_results_counter);
557
558 /* update number of available TX blocks */
559 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300560 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
561 wl->tx_blocks_freed[i];
562
563 wl->tx_blocks_freed[i] =
564 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565 wl->tx_blocks_available += cnt;
566 total += cnt;
567 }
568
Ido Yariva5225502010-10-12 14:49:10 +0200569 /* if more blocks are available now, tx work can be scheduled */
570 if (total)
571 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300572
573 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200574 getnstimeofday(&ts);
575 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
576 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300577}
578
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200579#define WL1271_IRQ_MAX_LOOPS 10
580
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581static void wl1271_irq_work(struct work_struct *work)
582{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300584 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200585 int loopcount = WL1271_IRQ_MAX_LOOPS;
586 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 struct wl1271 *wl =
588 container_of(work, struct wl1271, irq_work);
589
590 mutex_lock(&wl->mutex);
591
592 wl1271_debug(DEBUG_IRQ, "IRQ work");
593
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200594 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl, true);
598 if (ret < 0)
599 goto out;
600
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200601 spin_lock_irqsave(&wl->wl_lock, flags);
602 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
603 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
604 spin_unlock_irqrestore(&wl->wl_lock, flags);
605 loopcount--;
606
607 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200608 intr = le32_to_cpu(wl->fw_status->common.intr);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200609 if (!intr) {
610 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200611 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200612 continue;
613 }
614
615 intr &= WL1271_INTR_MASK;
616
Eliad Pellerccc83b02010-10-27 14:09:57 +0200617 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
618 wl1271_error("watchdog interrupt received! "
619 "starting recovery.");
620 ieee80211_queue_work(wl->hw, &wl->recovery_work);
621
622 /* restarting the chip. ignore any other interrupt. */
623 goto out;
624 }
625
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200626 if (intr & WL1271_ACX_INTR_DATA) {
627 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
628
629 /* check for tx results */
Eliad Pellerc8bde242011-02-02 09:59:35 +0200630 if (wl->fw_status->common.tx_results_counter !=
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200631 (wl->tx_results_count & 0xff))
632 wl1271_tx_complete(wl);
633
Ido Yariva5225502010-10-12 14:49:10 +0200634 /* Check if any tx blocks were freed */
635 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200636 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200637 /*
638 * In order to avoid starvation of the TX path,
639 * call the work function directly.
640 */
641 wl1271_tx_work_locked(wl);
642 }
643
Eliad Pellerc8bde242011-02-02 09:59:35 +0200644 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200645 }
646
647 if (intr & WL1271_ACX_INTR_EVENT_A) {
648 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
649 wl1271_event_handle(wl, 0);
650 }
651
652 if (intr & WL1271_ACX_INTR_EVENT_B) {
653 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
654 wl1271_event_handle(wl, 1);
655 }
656
657 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
658 wl1271_debug(DEBUG_IRQ,
659 "WL1271_ACX_INTR_INIT_COMPLETE");
660
661 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
662 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
663
664 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 }
666
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200667 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
668 ieee80211_queue_work(wl->hw, &wl->irq_work);
669 else
670 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
671 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 wl1271_ps_elp_sleep(wl);
674
675out:
676 mutex_unlock(&wl->mutex);
677}
678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679static int wl1271_fetch_firmware(struct wl1271 *wl)
680{
681 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200682 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 int ret;
684
Arik Nemtsov166d5042010-10-16 21:44:57 +0200685 switch (wl->bss_type) {
686 case BSS_TYPE_AP_BSS:
687 fw_name = WL1271_AP_FW_NAME;
688 break;
689 case BSS_TYPE_IBSS:
690 case BSS_TYPE_STA_BSS:
691 fw_name = WL1271_FW_NAME;
692 break;
693 default:
694 wl1271_error("no compatible firmware for bss_type %d",
695 wl->bss_type);
696 return -EINVAL;
697 }
698
699 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
700
701 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 if (ret < 0) {
704 wl1271_error("could not get firmware: %d", ret);
705 return ret;
706 }
707
708 if (fw->size % 4) {
709 wl1271_error("firmware size is not multiple of 32 bits: %zu",
710 fw->size);
711 ret = -EILSEQ;
712 goto out;
713 }
714
Arik Nemtsov166d5042010-10-16 21:44:57 +0200715 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300717 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718
719 if (!wl->fw) {
720 wl1271_error("could not allocate memory for the firmware");
721 ret = -ENOMEM;
722 goto out;
723 }
724
725 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200726 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727 ret = 0;
728
729out:
730 release_firmware(fw);
731
732 return ret;
733}
734
735static int wl1271_fetch_nvs(struct wl1271 *wl)
736{
737 const struct firmware *fw;
738 int ret;
739
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200740 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
742 if (ret < 0) {
743 wl1271_error("could not get nvs file: %d", ret);
744 return ret;
745 }
746
Julia Lawall929ebd32010-05-15 23:16:39 +0200747 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748
749 if (!wl->nvs) {
750 wl1271_error("could not allocate memory for the nvs file");
751 ret = -ENOMEM;
752 goto out;
753 }
754
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200755 wl->nvs_len = fw->size;
756
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757out:
758 release_firmware(fw);
759
760 return ret;
761}
762
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200763static void wl1271_recovery_work(struct work_struct *work)
764{
765 struct wl1271 *wl =
766 container_of(work, struct wl1271, recovery_work);
767
768 mutex_lock(&wl->mutex);
769
770 if (wl->state != WL1271_STATE_ON)
771 goto out;
772
773 wl1271_info("Hardware recovery in progress.");
774
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200775 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
776 ieee80211_connection_loss(wl->vif);
777
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200778 /* reboot the chipset */
779 __wl1271_op_remove_interface(wl);
780 ieee80211_restart_hw(wl->hw);
781
782out:
783 mutex_unlock(&wl->mutex);
784}
785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786static void wl1271_fw_wakeup(struct wl1271 *wl)
787{
788 u32 elp_reg;
789
790 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300791 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792}
793
794static int wl1271_setup(struct wl1271 *wl)
795{
796 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
797 if (!wl->fw_status)
798 return -ENOMEM;
799
800 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
801 if (!wl->tx_res_if) {
802 kfree(wl->fw_status);
803 return -ENOMEM;
804 }
805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806 return 0;
807}
808
809static int wl1271_chip_wakeup(struct wl1271 *wl)
810{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300811 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812 int ret = 0;
813
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200814 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200815 ret = wl1271_power_on(wl);
816 if (ret < 0)
817 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200819 wl1271_io_reset(wl);
820 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821
822 /* We don't need a real memory partition here, because we only want
823 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300824 memset(&partition, 0, sizeof(partition));
825 partition.reg.start = REGISTERS_BASE;
826 partition.reg.size = REGISTERS_DOWN_SIZE;
827 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
829 /* ELP module wake up */
830 wl1271_fw_wakeup(wl);
831
832 /* whal_FwCtrl_BootSm() */
833
834 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200835 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
837 /* 1. check if chip id is valid */
838
839 switch (wl->chip.id) {
840 case CHIP_ID_1271_PG10:
841 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
842 wl->chip.id);
843
844 ret = wl1271_setup(wl);
845 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200846 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847 break;
848 case CHIP_ID_1271_PG20:
849 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
850 wl->chip.id);
851
852 ret = wl1271_setup(wl);
853 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200854 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300855 break;
856 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200857 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300858 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200859 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860 }
861
Arik Nemtsov166d5042010-10-16 21:44:57 +0200862 /* Make sure the firmware type matches the BSS type */
863 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864 ret = wl1271_fetch_firmware(wl);
865 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200866 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 }
868
869 /* No NVS from netlink, try to get it from the filesystem */
870 if (wl->nvs == NULL) {
871 ret = wl1271_fetch_nvs(wl);
872 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200873 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 }
875
876out:
877 return ret;
878}
879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880int wl1271_plt_start(struct wl1271 *wl)
881{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200882 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883 int ret;
884
885 mutex_lock(&wl->mutex);
886
887 wl1271_notice("power up");
888
889 if (wl->state != WL1271_STATE_OFF) {
890 wl1271_error("cannot go into PLT state because not "
891 "in off state: %d", wl->state);
892 ret = -EBUSY;
893 goto out;
894 }
895
Arik Nemtsov166d5042010-10-16 21:44:57 +0200896 wl->bss_type = BSS_TYPE_STA_BSS;
897
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200898 while (retries) {
899 retries--;
900 ret = wl1271_chip_wakeup(wl);
901 if (ret < 0)
902 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200904 ret = wl1271_boot(wl);
905 if (ret < 0)
906 goto power_off;
907
908 ret = wl1271_plt_init(wl);
909 if (ret < 0)
910 goto irq_disable;
911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 wl->state = WL1271_STATE_PLT;
913 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100914 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915 goto out;
916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200917irq_disable:
918 wl1271_disable_interrupts(wl);
919 mutex_unlock(&wl->mutex);
920 /* Unlocking the mutex in the middle of handling is
921 inherently unsafe. In this case we deem it safe to do,
922 because we need to let any possibly pending IRQ out of
923 the system (and while we are WL1271_STATE_OFF the IRQ
924 work function will not do anything.) Also, any other
925 possible concurrent operations will fail due to the
926 current state, hence the wl1271 struct should be safe. */
927 cancel_work_sync(&wl->irq_work);
928 mutex_lock(&wl->mutex);
929power_off:
930 wl1271_power_off(wl);
931 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200933 wl1271_error("firmware boot in PLT mode failed despite %d retries",
934 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935out:
936 mutex_unlock(&wl->mutex);
937
938 return ret;
939}
940
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100941int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942{
943 int ret = 0;
944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 wl1271_notice("power down");
946
947 if (wl->state != WL1271_STATE_PLT) {
948 wl1271_error("cannot power down because not in PLT "
949 "state: %d", wl->state);
950 ret = -EBUSY;
951 goto out;
952 }
953
954 wl1271_disable_interrupts(wl);
955 wl1271_power_off(wl);
956
957 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300958 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200961 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200962 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100963 mutex_lock(&wl->mutex);
964out:
965 return ret;
966}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200967
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100968int wl1271_plt_stop(struct wl1271 *wl)
969{
970 int ret;
971
972 mutex_lock(&wl->mutex);
973 ret = __wl1271_plt_stop(wl);
974 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975 return ret;
976}
977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
979{
980 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200981 struct ieee80211_conf *conf = &hw->conf;
982 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
983 struct ieee80211_sta *sta = txinfo->control.sta;
984 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200985 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986
Shahar Levi18357852010-10-13 16:09:41 +0200987 /*
988 * peek into the rates configured in the STA entry.
989 * The rates set after connection stage, The first block only BG sets:
990 * the compare is for bit 0-16 of sta_rate_set. The second block add
991 * HT rates in case of HT supported.
992 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200993 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200994 if (sta &&
995 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200996 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
997 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200998 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
999 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
1000 }
Shahar Levi18357852010-10-13 16:09:41 +02001001
Shahar Levi00d20102010-11-08 11:20:10 +00001002#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +02001003 if (sta &&
1004 sta->ht_cap.ht_supported &&
1005 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
1006 sta->ht_cap.mcs.rx_mask[0])) {
1007 /* Clean MCS bits before setting them */
1008 wl->sta_rate_set &= HW_BG_RATES_MASK;
1009 wl->sta_rate_set |=
1010 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
1011 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
1012 }
1013#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001014 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001015 spin_unlock_irqrestore(&wl->wl_lock, flags);
1016
1017 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001018 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1019 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020
1021 /*
1022 * The chip specific setup must run before the first TX packet -
1023 * before that, the tx_work will not be initialized!
1024 */
1025
Ido Yariva5225502010-10-12 14:49:10 +02001026 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1027 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028
1029 /*
1030 * The workqueue is slow to process the tx_queue and we need stop
1031 * the queue here, otherwise the queue will get too long.
1032 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001033 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001034 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001036 spin_lock_irqsave(&wl->wl_lock, flags);
1037 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001038 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001039 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
1042 return NETDEV_TX_OK;
1043}
1044
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001045static struct notifier_block wl1271_dev_notifier = {
1046 .notifier_call = wl1271_dev_notify,
1047};
1048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049static int wl1271_op_start(struct ieee80211_hw *hw)
1050{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001051 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1052
1053 /*
1054 * We have to delay the booting of the hardware because
1055 * we need to know the local MAC address before downloading and
1056 * initializing the firmware. The MAC address cannot be changed
1057 * after boot, and without the proper MAC address, the firmware
1058 * will not function properly.
1059 *
1060 * The MAC address is first known when the corresponding interface
1061 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001062 *
1063 * In addition, we currently have different firmwares for AP and managed
1064 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001065 */
1066
1067 return 0;
1068}
1069
1070static void wl1271_op_stop(struct ieee80211_hw *hw)
1071{
1072 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1073}
1074
1075static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1076 struct ieee80211_vif *vif)
1077{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001079 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001080 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001082 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001084 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1085 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086
1087 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001088 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001089 wl1271_debug(DEBUG_MAC80211,
1090 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001091 ret = -EBUSY;
1092 goto out;
1093 }
1094
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001095 switch (vif->type) {
1096 case NL80211_IFTYPE_STATION:
1097 wl->bss_type = BSS_TYPE_STA_BSS;
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;
1100 case NL80211_IFTYPE_ADHOC:
1101 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001102 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001103 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001104 case NL80211_IFTYPE_AP:
1105 wl->bss_type = BSS_TYPE_AP_BSS;
1106 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001107 default:
1108 ret = -EOPNOTSUPP;
1109 goto out;
1110 }
1111
1112 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113
1114 if (wl->state != WL1271_STATE_OFF) {
1115 wl1271_error("cannot start because not in off state: %d",
1116 wl->state);
1117 ret = -EBUSY;
1118 goto out;
1119 }
1120
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001121 while (retries) {
1122 retries--;
1123 ret = wl1271_chip_wakeup(wl);
1124 if (ret < 0)
1125 goto power_off;
1126
1127 ret = wl1271_boot(wl);
1128 if (ret < 0)
1129 goto power_off;
1130
1131 ret = wl1271_hw_init(wl);
1132 if (ret < 0)
1133 goto irq_disable;
1134
Eliad Peller71125ab2010-10-28 21:46:43 +02001135 booted = true;
1136 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001138irq_disable:
1139 wl1271_disable_interrupts(wl);
1140 mutex_unlock(&wl->mutex);
1141 /* Unlocking the mutex in the middle of handling is
1142 inherently unsafe. In this case we deem it safe to do,
1143 because we need to let any possibly pending IRQ out of
1144 the system (and while we are WL1271_STATE_OFF the IRQ
1145 work function will not do anything.) Also, any other
1146 possible concurrent operations will fail due to the
1147 current state, hence the wl1271 struct should be safe. */
1148 cancel_work_sync(&wl->irq_work);
1149 mutex_lock(&wl->mutex);
1150power_off:
1151 wl1271_power_off(wl);
1152 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153
Eliad Peller71125ab2010-10-28 21:46:43 +02001154 if (!booted) {
1155 wl1271_error("firmware boot failed despite %d retries",
1156 WL1271_BOOT_RETRIES);
1157 goto out;
1158 }
1159
1160 wl->vif = vif;
1161 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001162 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001163
1164 /* update hw/fw version info in wiphy struct */
1165 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001166 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001167 sizeof(wiphy->fw_version));
1168
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001169 /*
1170 * Now we know if 11a is supported (info from the NVS), so disable
1171 * 11a channels if not supported
1172 */
1173 if (!wl->enable_11a)
1174 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1175
1176 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1177 wl->enable_11a ? "" : "not ");
1178
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001179out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001180 mutex_unlock(&wl->mutex);
1181
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001182 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001183 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001184
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185 return ret;
1186}
1187
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001188static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001190 int i;
1191
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001192 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001194 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001196 list_del(&wl->list);
1197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 WARN_ON(wl->state != WL1271_STATE_ON);
1199
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001200 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001201 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001202 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001203
Luciano Coelho08688d62010-07-08 17:50:07 +03001204 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001205 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1206 kfree(wl->scan.scanned_ch);
1207 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001208 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001209 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210 }
1211
1212 wl->state = WL1271_STATE_OFF;
1213
1214 wl1271_disable_interrupts(wl);
1215
1216 mutex_unlock(&wl->mutex);
1217
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001218 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 cancel_work_sync(&wl->irq_work);
1220 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001221 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001222 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223
1224 mutex_lock(&wl->mutex);
1225
1226 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001227 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228 wl1271_power_off(wl);
1229
1230 memset(wl->bssid, 0, ETH_ALEN);
1231 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1232 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001233 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001234 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001235 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236
1237 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001238 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1240 wl->tx_blocks_available = 0;
1241 wl->tx_results_count = 0;
1242 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001243 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001244 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245 wl->time_offset = 0;
1246 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001247 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1248 wl->sta_rate_set = 0;
1249 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001250 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001251 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001252 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001253 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001254
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255 for (i = 0; i < NUM_TX_QUEUES; i++)
1256 wl->tx_blocks_freed[i] = 0;
1257
1258 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001259
1260 kfree(wl->fw_status);
1261 wl->fw_status = NULL;
1262 kfree(wl->tx_res_if);
1263 wl->tx_res_if = NULL;
1264 kfree(wl->target_mem_map);
1265 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001266}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001267
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001268static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1269 struct ieee80211_vif *vif)
1270{
1271 struct wl1271 *wl = hw->priv;
1272
1273 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001274 /*
1275 * wl->vif can be null here if someone shuts down the interface
1276 * just when hardware recovery has been started.
1277 */
1278 if (wl->vif) {
1279 WARN_ON(wl->vif != vif);
1280 __wl1271_op_remove_interface(wl);
1281 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001282
Juuso Oikarinen67353292010-11-18 15:19:02 +02001283 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001284 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285}
1286
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001287static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1288{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001289 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001290
1291 /* combine requested filters with current filter config */
1292 filters = wl->filters | filters;
1293
1294 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1295
1296 if (filters & FIF_PROMISC_IN_BSS) {
1297 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1298 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1299 wl->rx_config |= CFG_BSSID_FILTER_EN;
1300 }
1301 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1302 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1303 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1304 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1305 }
1306 if (filters & FIF_OTHER_BSS) {
1307 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1308 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1309 }
1310 if (filters & FIF_CONTROL) {
1311 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1312 wl->rx_filter |= CFG_RX_CTL_EN;
1313 }
1314 if (filters & FIF_FCSFAIL) {
1315 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1316 wl->rx_filter |= CFG_RX_FCS_ERROR;
1317 }
1318}
1319
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001320static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001321{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001322 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001323 /* we need to use a dummy BSSID for now */
1324 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1325 0xad, 0xbe, 0xef };
1326
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001327 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1328
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001329 /* pass through frames from all BSS */
1330 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1331
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001332 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001333 if (ret < 0)
1334 goto out;
1335
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001336 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001337
1338out:
1339 return ret;
1340}
1341
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001342static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001343{
1344 int ret;
1345
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001346 /*
1347 * One of the side effects of the JOIN command is that is clears
1348 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1349 * to a WPA/WPA2 access point will therefore kill the data-path.
1350 * Currently there is no supported scenario for JOIN during
1351 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1352 * must be handled somehow.
1353 *
1354 */
1355 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1356 wl1271_info("JOIN while associated.");
1357
1358 if (set_assoc)
1359 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1360
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001361 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1362 if (ret < 0)
1363 goto out;
1364
1365 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1366
1367 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1368 goto out;
1369
1370 /*
1371 * The join command disable the keep-alive mode, shut down its process,
1372 * and also clear the template config, so we need to reset it all after
1373 * the join. The acx_aid starts the keep-alive process, and the order
1374 * of the commands below is relevant.
1375 */
1376 ret = wl1271_acx_keep_alive_mode(wl, true);
1377 if (ret < 0)
1378 goto out;
1379
1380 ret = wl1271_acx_aid(wl, wl->aid);
1381 if (ret < 0)
1382 goto out;
1383
1384 ret = wl1271_cmd_build_klv_null_data(wl);
1385 if (ret < 0)
1386 goto out;
1387
1388 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1389 ACX_KEEP_ALIVE_TPL_VALID);
1390 if (ret < 0)
1391 goto out;
1392
1393out:
1394 return ret;
1395}
1396
1397static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001398{
1399 int ret;
1400
1401 /* to stop listening to a channel, we disconnect */
1402 ret = wl1271_cmd_disconnect(wl);
1403 if (ret < 0)
1404 goto out;
1405
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001406 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001407 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001408
1409 /* stop filterting packets based on bssid */
1410 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001411
1412out:
1413 return ret;
1414}
1415
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001416static void wl1271_set_band_rate(struct wl1271 *wl)
1417{
1418 if (wl->band == IEEE80211_BAND_2GHZ)
1419 wl->basic_rate_set = wl->conf.tx.basic_rate;
1420 else
1421 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1422}
1423
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001424static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001425{
1426 int ret;
1427
1428 if (idle) {
1429 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1430 ret = wl1271_unjoin(wl);
1431 if (ret < 0)
1432 goto out;
1433 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001434 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001435 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001436 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001437 if (ret < 0)
1438 goto out;
1439 ret = wl1271_acx_keep_alive_config(
1440 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1441 ACX_KEEP_ALIVE_TPL_INVALID);
1442 if (ret < 0)
1443 goto out;
1444 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1445 } else {
1446 /* increment the session counter */
1447 wl->session_counter++;
1448 if (wl->session_counter >= SESSION_COUNTER_MAX)
1449 wl->session_counter = 0;
1450 ret = wl1271_dummy_join(wl);
1451 if (ret < 0)
1452 goto out;
1453 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1454 }
1455
1456out:
1457 return ret;
1458}
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1461{
1462 struct wl1271 *wl = hw->priv;
1463 struct ieee80211_conf *conf = &hw->conf;
1464 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001465 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466
1467 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1468
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001469 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1470 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001471 channel,
1472 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001473 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001474 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1475 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001477 /*
1478 * mac80211 will go to idle nearly immediately after transmitting some
1479 * frames, such as the deauth. To make sure those frames reach the air,
1480 * wait here until the TX queue is fully flushed.
1481 */
1482 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1483 (conf->flags & IEEE80211_CONF_IDLE))
1484 wl1271_tx_flush(wl);
1485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 mutex_lock(&wl->mutex);
1487
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001488 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1489 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001490 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001491 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001492
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001493 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 ret = wl1271_ps_elp_wakeup(wl, false);
1496 if (ret < 0)
1497 goto out;
1498
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001499 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001500 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1501 ((wl->band != conf->channel->band) ||
1502 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001503 wl->band = conf->channel->band;
1504 wl->channel = channel;
1505
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001506 if (!is_ap) {
1507 /*
1508 * FIXME: the mac80211 should really provide a fixed
1509 * rate to use here. for now, just use the smallest
1510 * possible rate for the band as a fixed rate for
1511 * association frames and other control messages.
1512 */
1513 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1514 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001515
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001516 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1517 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001518 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001519 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001520 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001521
1522 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1523 ret = wl1271_join(wl, false);
1524 if (ret < 0)
1525 wl1271_warning("cmd join on channel "
1526 "failed %d", ret);
1527 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001528 }
1529 }
1530
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001531 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1532 ret = wl1271_sta_handle_idle(wl,
1533 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001534 if (ret < 0)
1535 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 }
1537
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001538 /*
1539 * if mac80211 changes the PSM mode, make sure the mode is not
1540 * incorrectly changed after the pspoll failure active window.
1541 */
1542 if (changed & IEEE80211_CONF_CHANGE_PS)
1543 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1544
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001545 if (conf->flags & IEEE80211_CONF_PS &&
1546 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1547 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548
1549 /*
1550 * We enter PSM only if we're already associated.
1551 * If we're not, we'll enter it when joining an SSID,
1552 * through the bss_info_changed() hook.
1553 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001554 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001555 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001556 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001557 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001558 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001560 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001561 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001563 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001564
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001565 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001566 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001567 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001568 }
1569
1570 if (conf->power_level != wl->power_level) {
1571 ret = wl1271_acx_tx_power(wl, conf->power_level);
1572 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001573 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
1575 wl->power_level = conf->power_level;
1576 }
1577
1578out_sleep:
1579 wl1271_ps_elp_sleep(wl);
1580
1581out:
1582 mutex_unlock(&wl->mutex);
1583
1584 return ret;
1585}
1586
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001587struct wl1271_filter_params {
1588 bool enabled;
1589 int mc_list_length;
1590 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1591};
1592
Jiri Pirko22bedad2010-04-01 21:22:57 +00001593static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1594 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001595{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001596 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001597 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001598 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001599
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001600 if (unlikely(wl->state == WL1271_STATE_OFF))
1601 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001602
Juuso Oikarinen74441132009-10-13 12:47:53 +03001603 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001604 if (!fp) {
1605 wl1271_error("Out of memory setting filters.");
1606 return 0;
1607 }
1608
1609 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001610 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001611 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1612 fp->enabled = false;
1613 } else {
1614 fp->enabled = true;
1615 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001616 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001617 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001618 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001619 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001620 }
1621
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001622 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001623}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001624
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001625#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1626 FIF_ALLMULTI | \
1627 FIF_FCSFAIL | \
1628 FIF_BCN_PRBRESP_PROMISC | \
1629 FIF_CONTROL | \
1630 FIF_OTHER_BSS)
1631
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001632static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1633 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001634 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001636 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001637 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001638 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001639
Arik Nemtsov7d057862010-10-16 19:25:35 +02001640 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1641 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001643 mutex_lock(&wl->mutex);
1644
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001645 *total &= WL1271_SUPPORTED_FILTERS;
1646 changed &= WL1271_SUPPORTED_FILTERS;
1647
1648 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001649 goto out;
1650
1651 ret = wl1271_ps_elp_wakeup(wl, false);
1652 if (ret < 0)
1653 goto out;
1654
Arik Nemtsov7d057862010-10-16 19:25:35 +02001655 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1656 if (*total & FIF_ALLMULTI)
1657 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1658 else if (fp)
1659 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1660 fp->mc_list,
1661 fp->mc_list_length);
1662 if (ret < 0)
1663 goto out_sleep;
1664 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001666 /* determine, whether supported filter values have changed */
1667 if (changed == 0)
1668 goto out_sleep;
1669
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001670 /* configure filters */
1671 wl->filters = *total;
1672 wl1271_configure_filters(wl, 0);
1673
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001674 /* apply configured filters */
1675 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1676 if (ret < 0)
1677 goto out_sleep;
1678
1679out_sleep:
1680 wl1271_ps_elp_sleep(wl);
1681
1682out:
1683 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001684 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685}
1686
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001687static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1688 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1689 u16 tx_seq_16)
1690{
1691 struct wl1271_ap_key *ap_key;
1692 int i;
1693
1694 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1695
1696 if (key_size > MAX_KEY_SIZE)
1697 return -EINVAL;
1698
1699 /*
1700 * Find next free entry in ap_keys. Also check we are not replacing
1701 * an existing key.
1702 */
1703 for (i = 0; i < MAX_NUM_KEYS; i++) {
1704 if (wl->recorded_ap_keys[i] == NULL)
1705 break;
1706
1707 if (wl->recorded_ap_keys[i]->id == id) {
1708 wl1271_warning("trying to record key replacement");
1709 return -EINVAL;
1710 }
1711 }
1712
1713 if (i == MAX_NUM_KEYS)
1714 return -EBUSY;
1715
1716 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1717 if (!ap_key)
1718 return -ENOMEM;
1719
1720 ap_key->id = id;
1721 ap_key->key_type = key_type;
1722 ap_key->key_size = key_size;
1723 memcpy(ap_key->key, key, key_size);
1724 ap_key->hlid = hlid;
1725 ap_key->tx_seq_32 = tx_seq_32;
1726 ap_key->tx_seq_16 = tx_seq_16;
1727
1728 wl->recorded_ap_keys[i] = ap_key;
1729 return 0;
1730}
1731
1732static void wl1271_free_ap_keys(struct wl1271 *wl)
1733{
1734 int i;
1735
1736 for (i = 0; i < MAX_NUM_KEYS; i++) {
1737 kfree(wl->recorded_ap_keys[i]);
1738 wl->recorded_ap_keys[i] = NULL;
1739 }
1740}
1741
1742static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1743{
1744 int i, ret = 0;
1745 struct wl1271_ap_key *key;
1746 bool wep_key_added = false;
1747
1748 for (i = 0; i < MAX_NUM_KEYS; i++) {
1749 if (wl->recorded_ap_keys[i] == NULL)
1750 break;
1751
1752 key = wl->recorded_ap_keys[i];
1753 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1754 key->id, key->key_type,
1755 key->key_size, key->key,
1756 key->hlid, key->tx_seq_32,
1757 key->tx_seq_16);
1758 if (ret < 0)
1759 goto out;
1760
1761 if (key->key_type == KEY_WEP)
1762 wep_key_added = true;
1763 }
1764
1765 if (wep_key_added) {
1766 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1767 if (ret < 0)
1768 goto out;
1769 }
1770
1771out:
1772 wl1271_free_ap_keys(wl);
1773 return ret;
1774}
1775
1776static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1777 u8 key_size, const u8 *key, u32 tx_seq_32,
1778 u16 tx_seq_16, struct ieee80211_sta *sta)
1779{
1780 int ret;
1781 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1782
1783 if (is_ap) {
1784 struct wl1271_station *wl_sta;
1785 u8 hlid;
1786
1787 if (sta) {
1788 wl_sta = (struct wl1271_station *)sta->drv_priv;
1789 hlid = wl_sta->hlid;
1790 } else {
1791 hlid = WL1271_AP_BROADCAST_HLID;
1792 }
1793
1794 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1795 /*
1796 * We do not support removing keys after AP shutdown.
1797 * Pretend we do to make mac80211 happy.
1798 */
1799 if (action != KEY_ADD_OR_REPLACE)
1800 return 0;
1801
1802 ret = wl1271_record_ap_key(wl, id,
1803 key_type, key_size,
1804 key, hlid, tx_seq_32,
1805 tx_seq_16);
1806 } else {
1807 ret = wl1271_cmd_set_ap_key(wl, action,
1808 id, key_type, key_size,
1809 key, hlid, tx_seq_32,
1810 tx_seq_16);
1811 }
1812
1813 if (ret < 0)
1814 return ret;
1815 } else {
1816 const u8 *addr;
1817 static const u8 bcast_addr[ETH_ALEN] = {
1818 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1819 };
1820
1821 addr = sta ? sta->addr : bcast_addr;
1822
1823 if (is_zero_ether_addr(addr)) {
1824 /* We dont support TX only encryption */
1825 return -EOPNOTSUPP;
1826 }
1827
1828 /* The wl1271 does not allow to remove unicast keys - they
1829 will be cleared automatically on next CMD_JOIN. Ignore the
1830 request silently, as we dont want the mac80211 to emit
1831 an error message. */
1832 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1833 return 0;
1834
1835 ret = wl1271_cmd_set_sta_key(wl, action,
1836 id, key_type, key_size,
1837 key, addr, tx_seq_32,
1838 tx_seq_16);
1839 if (ret < 0)
1840 return ret;
1841
1842 /* the default WEP key needs to be configured at least once */
1843 if (key_type == KEY_WEP) {
1844 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1845 wl->default_key);
1846 if (ret < 0)
1847 return ret;
1848 }
1849 }
1850
1851 return 0;
1852}
1853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1855 struct ieee80211_vif *vif,
1856 struct ieee80211_sta *sta,
1857 struct ieee80211_key_conf *key_conf)
1858{
1859 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001861 u32 tx_seq_32 = 0;
1862 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 u8 key_type;
1864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1866
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001867 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001869 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870 key_conf->keylen, key_conf->flags);
1871 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873 mutex_lock(&wl->mutex);
1874
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001875 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1876 ret = -EAGAIN;
1877 goto out_unlock;
1878 }
1879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880 ret = wl1271_ps_elp_wakeup(wl, false);
1881 if (ret < 0)
1882 goto out_unlock;
1883
Johannes Berg97359d12010-08-10 09:46:38 +02001884 switch (key_conf->cipher) {
1885 case WLAN_CIPHER_SUITE_WEP40:
1886 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887 key_type = KEY_WEP;
1888
1889 key_conf->hw_key_idx = key_conf->keyidx;
1890 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001891 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001892 key_type = KEY_TKIP;
1893
1894 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001895 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1896 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001898 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001899 key_type = KEY_AES;
1900
1901 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001902 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1903 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001904 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001905 case WL1271_CIPHER_SUITE_GEM:
1906 key_type = KEY_GEM;
1907 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1908 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1909 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001911 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912
1913 ret = -EOPNOTSUPP;
1914 goto out_sleep;
1915 }
1916
1917 switch (cmd) {
1918 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001919 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1920 key_conf->keyidx, key_type,
1921 key_conf->keylen, key_conf->key,
1922 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 if (ret < 0) {
1924 wl1271_error("Could not add or replace key");
1925 goto out_sleep;
1926 }
1927 break;
1928
1929 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001930 ret = wl1271_set_key(wl, KEY_REMOVE,
1931 key_conf->keyidx, key_type,
1932 key_conf->keylen, key_conf->key,
1933 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 if (ret < 0) {
1935 wl1271_error("Could not remove key");
1936 goto out_sleep;
1937 }
1938 break;
1939
1940 default:
1941 wl1271_error("Unsupported key cmd 0x%x", cmd);
1942 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 break;
1944 }
1945
1946out_sleep:
1947 wl1271_ps_elp_sleep(wl);
1948
1949out_unlock:
1950 mutex_unlock(&wl->mutex);
1951
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 return ret;
1953}
1954
1955static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001956 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957 struct cfg80211_scan_request *req)
1958{
1959 struct wl1271 *wl = hw->priv;
1960 int ret;
1961 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001962 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963
1964 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1965
1966 if (req->n_ssids) {
1967 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001968 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969 }
1970
1971 mutex_lock(&wl->mutex);
1972
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001973 if (wl->state == WL1271_STATE_OFF) {
1974 /*
1975 * We cannot return -EBUSY here because cfg80211 will expect
1976 * a call to ieee80211_scan_completed if we do - in this case
1977 * there won't be any call.
1978 */
1979 ret = -EAGAIN;
1980 goto out;
1981 }
1982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983 ret = wl1271_ps_elp_wakeup(wl, false);
1984 if (ret < 0)
1985 goto out;
1986
Luciano Coelho5924f892010-08-04 03:46:22 +03001987 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988
1989 wl1271_ps_elp_sleep(wl);
1990
1991out:
1992 mutex_unlock(&wl->mutex);
1993
1994 return ret;
1995}
1996
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001997static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1998{
1999 struct wl1271 *wl = hw->priv;
2000 int ret = 0;
2001
2002 mutex_lock(&wl->mutex);
2003
2004 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2005 ret = -EAGAIN;
2006 goto out;
2007 }
2008
2009 ret = wl1271_ps_elp_wakeup(wl, false);
2010 if (ret < 0)
2011 goto out;
2012
2013 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2014 if (ret < 0)
2015 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2016
2017 wl1271_ps_elp_sleep(wl);
2018
2019out:
2020 mutex_unlock(&wl->mutex);
2021
2022 return ret;
2023}
2024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2026{
2027 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002028 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029
2030 mutex_lock(&wl->mutex);
2031
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002032 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2033 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002034 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002035 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037 ret = wl1271_ps_elp_wakeup(wl, false);
2038 if (ret < 0)
2039 goto out;
2040
2041 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2042 if (ret < 0)
2043 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2044
2045 wl1271_ps_elp_sleep(wl);
2046
2047out:
2048 mutex_unlock(&wl->mutex);
2049
2050 return ret;
2051}
2052
Arik Nemtsove78a2872010-10-16 19:07:21 +02002053static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002054 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002055{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002056 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002057
2058 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002059 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002060 if (ptr[0] == WLAN_EID_SSID) {
2061 wl->ssid_len = ptr[1];
2062 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002063 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002064 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002065 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002066 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002067
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002068 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002069 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002070}
2071
Arik Nemtsove78a2872010-10-16 19:07:21 +02002072static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2073 struct ieee80211_bss_conf *bss_conf,
2074 u32 changed)
2075{
2076 int ret = 0;
2077
2078 if (changed & BSS_CHANGED_ERP_SLOT) {
2079 if (bss_conf->use_short_slot)
2080 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2081 else
2082 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2083 if (ret < 0) {
2084 wl1271_warning("Set slot time failed %d", ret);
2085 goto out;
2086 }
2087 }
2088
2089 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2090 if (bss_conf->use_short_preamble)
2091 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2092 else
2093 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2094 }
2095
2096 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2097 if (bss_conf->use_cts_prot)
2098 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2099 else
2100 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2101 if (ret < 0) {
2102 wl1271_warning("Set ctsprotect failed %d", ret);
2103 goto out;
2104 }
2105 }
2106
2107out:
2108 return ret;
2109}
2110
2111static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2112 struct ieee80211_vif *vif,
2113 struct ieee80211_bss_conf *bss_conf,
2114 u32 changed)
2115{
2116 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2117 int ret = 0;
2118
2119 if ((changed & BSS_CHANGED_BEACON_INT)) {
2120 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2121 bss_conf->beacon_int);
2122
2123 wl->beacon_int = bss_conf->beacon_int;
2124 }
2125
2126 if ((changed & BSS_CHANGED_BEACON)) {
2127 struct ieee80211_hdr *hdr;
2128 int ieoffset = offsetof(struct ieee80211_mgmt,
2129 u.beacon.variable);
2130 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2131 u16 tmpl_id;
2132
2133 if (!beacon)
2134 goto out;
2135
2136 wl1271_debug(DEBUG_MASTER, "beacon updated");
2137
2138 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2139 if (ret < 0) {
2140 dev_kfree_skb(beacon);
2141 goto out;
2142 }
2143 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2144 CMD_TEMPL_BEACON;
2145 ret = wl1271_cmd_template_set(wl, tmpl_id,
2146 beacon->data,
2147 beacon->len, 0,
2148 wl1271_tx_min_rate_get(wl));
2149 if (ret < 0) {
2150 dev_kfree_skb(beacon);
2151 goto out;
2152 }
2153
2154 hdr = (struct ieee80211_hdr *) beacon->data;
2155 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2156 IEEE80211_STYPE_PROBE_RESP);
2157
2158 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2159 CMD_TEMPL_PROBE_RESPONSE;
2160 ret = wl1271_cmd_template_set(wl,
2161 tmpl_id,
2162 beacon->data,
2163 beacon->len, 0,
2164 wl1271_tx_min_rate_get(wl));
2165 dev_kfree_skb(beacon);
2166 if (ret < 0)
2167 goto out;
2168 }
2169
2170out:
2171 return ret;
2172}
2173
2174/* AP mode changes */
2175static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176 struct ieee80211_vif *vif,
2177 struct ieee80211_bss_conf *bss_conf,
2178 u32 changed)
2179{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002180 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Arik Nemtsove78a2872010-10-16 19:07:21 +02002182 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2183 u32 rates = bss_conf->basic_rates;
2184 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185
Arik Nemtsove78a2872010-10-16 19:07:21 +02002186 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2187 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2188 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2189 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190
Arik Nemtsove78a2872010-10-16 19:07:21 +02002191 /* update the AP management rate policy with the new rates */
2192 mgmt_rc.enabled_rates = wl->basic_rate_set;
2193 mgmt_rc.long_retry_limit = 10;
2194 mgmt_rc.short_retry_limit = 10;
2195 mgmt_rc.aflags = 0;
2196 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2197 ACX_TX_AP_MODE_MGMT_RATE);
2198 if (ret < 0) {
2199 wl1271_error("AP mgmt policy change failed %d", ret);
2200 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002201 }
2202 }
2203
Arik Nemtsove78a2872010-10-16 19:07:21 +02002204 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2205 if (ret < 0)
2206 goto out;
2207
2208 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2209 if (bss_conf->enable_beacon) {
2210 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2211 ret = wl1271_cmd_start_bss(wl);
2212 if (ret < 0)
2213 goto out;
2214
2215 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2216 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002217
2218 ret = wl1271_ap_init_hwenc(wl);
2219 if (ret < 0)
2220 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002221 }
2222 } else {
2223 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2224 ret = wl1271_cmd_stop_bss(wl);
2225 if (ret < 0)
2226 goto out;
2227
2228 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2229 wl1271_debug(DEBUG_AP, "stopped AP");
2230 }
2231 }
2232 }
2233
2234 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2235 if (ret < 0)
2236 goto out;
2237out:
2238 return;
2239}
2240
2241/* STA/IBSS mode changes */
2242static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2243 struct ieee80211_vif *vif,
2244 struct ieee80211_bss_conf *bss_conf,
2245 u32 changed)
2246{
2247 bool do_join = false, set_assoc = false;
2248 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2249 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002250 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002251
2252 if (is_ibss) {
2253 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2254 changed);
2255 if (ret < 0)
2256 goto out;
2257 }
2258
2259 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2260 do_join = true;
2261
2262 /* Need to update the SSID (for filtering etc) */
2263 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2264 do_join = true;
2265
2266 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002267 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2268 bss_conf->enable_beacon ? "enabled" : "disabled");
2269
2270 if (bss_conf->enable_beacon)
2271 wl->set_bss_type = BSS_TYPE_IBSS;
2272 else
2273 wl->set_bss_type = BSS_TYPE_STA_BSS;
2274 do_join = true;
2275 }
2276
Arik Nemtsove78a2872010-10-16 19:07:21 +02002277 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002278 bool enable = false;
2279 if (bss_conf->cqm_rssi_thold)
2280 enable = true;
2281 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2282 bss_conf->cqm_rssi_thold,
2283 bss_conf->cqm_rssi_hyst);
2284 if (ret < 0)
2285 goto out;
2286 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2287 }
2288
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002289 if ((changed & BSS_CHANGED_BSSID) &&
2290 /*
2291 * Now we know the correct bssid, so we send a new join command
2292 * and enable the BSSID filter
2293 */
2294 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002295 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002296
Eliad Pellerfa287b82010-12-26 09:27:50 +01002297 if (!is_zero_ether_addr(wl->bssid)) {
2298 ret = wl1271_cmd_build_null_data(wl);
2299 if (ret < 0)
2300 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002301
Eliad Pellerfa287b82010-12-26 09:27:50 +01002302 ret = wl1271_build_qos_null_data(wl);
2303 if (ret < 0)
2304 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002305
Eliad Pellerfa287b82010-12-26 09:27:50 +01002306 /* filter out all packets not from this BSSID */
2307 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002308
Eliad Pellerfa287b82010-12-26 09:27:50 +01002309 /* Need to update the BSSID (for filtering etc) */
2310 do_join = true;
2311 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002312 }
2313
Arik Nemtsove78a2872010-10-16 19:07:21 +02002314 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002315 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002316 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002317 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002319 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002321 wl->ps_poll_failures = 0;
2322
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002323 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002324 * use basic rates from AP, and determine lowest rate
2325 * to use with control frames.
2326 */
2327 rates = bss_conf->basic_rates;
2328 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2329 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002330 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002331 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002332 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002333 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002334
2335 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002336 * with wl1271, we don't need to update the
2337 * beacon_int and dtim_period, because the firmware
2338 * updates it by itself when the first beacon is
2339 * received after a join.
2340 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2342 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002343 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002344
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002345 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002346 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002347 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002348 dev_kfree_skb(wl->probereq);
2349 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2350 ieoffset = offsetof(struct ieee80211_mgmt,
2351 u.probe_req.variable);
2352 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002353
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002354 /* enable the connection monitoring feature */
2355 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002357 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358
2359 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002360 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2361 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002362 enum wl1271_cmd_ps_mode mode;
2363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002365 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002366 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002367 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002369 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002371 } else {
2372 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002373 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002374 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002375 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002376
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002377 /* free probe-request template */
2378 dev_kfree_skb(wl->probereq);
2379 wl->probereq = NULL;
2380
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002381 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002382 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002383
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002384 /* revert back to minimum rates for the current band */
2385 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002386 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002387 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002388 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002389 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002390
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002391 /* disable connection monitor features */
2392 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002393
2394 /* Disable the keep-alive feature */
2395 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002396 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002397 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002398
2399 /* restore the bssid filter and go to dummy bssid */
2400 wl1271_unjoin(wl);
2401 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402 }
2403 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002404
Arik Nemtsove78a2872010-10-16 19:07:21 +02002405 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2406 if (ret < 0)
2407 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002408
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002409 rcu_read_lock();
2410 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2411 if (sta) {
2412 /* handle new association with HT and HT information change */
2413 if ((changed & BSS_CHANGED_HT) &&
2414 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2415 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2416 true);
2417 if (ret < 0) {
2418 wl1271_warning("Set ht cap true failed %d",
2419 ret);
2420 rcu_read_unlock();
2421 goto out;
2422 }
Shahar Levi18357852010-10-13 16:09:41 +02002423 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002424 bss_conf->ht_operation_mode);
2425 if (ret < 0) {
2426 wl1271_warning("Set ht information failed %d",
2427 ret);
2428 rcu_read_unlock();
2429 goto out;
2430 }
2431 }
2432 /* handle new association without HT and disassociation */
2433 else if (changed & BSS_CHANGED_ASSOC) {
2434 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2435 false);
2436 if (ret < 0) {
2437 wl1271_warning("Set ht cap false failed %d",
2438 ret);
2439 rcu_read_unlock();
2440 goto out;
2441 }
Shahar Levi18357852010-10-13 16:09:41 +02002442 }
2443 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002444 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002445
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002446 if (changed & BSS_CHANGED_ARP_FILTER) {
2447 __be32 addr = bss_conf->arp_addr_list[0];
2448 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2449
Eliad Pellerc5312772010-12-09 11:31:27 +02002450 if (bss_conf->arp_addr_cnt == 1 &&
2451 bss_conf->arp_filter_enabled) {
2452 /*
2453 * The template should have been configured only upon
2454 * association. however, it seems that the correct ip
2455 * isn't being set (when sending), so we have to
2456 * reconfigure the template upon every ip change.
2457 */
2458 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2459 if (ret < 0) {
2460 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002461 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002462 }
2463
2464 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002465 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002466 addr);
2467 } else
2468 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002469
2470 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002471 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002472 }
2473
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002474 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002475 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002476 if (ret < 0) {
2477 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002478 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002479 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002480 }
2481
Arik Nemtsove78a2872010-10-16 19:07:21 +02002482out:
2483 return;
2484}
2485
2486static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2487 struct ieee80211_vif *vif,
2488 struct ieee80211_bss_conf *bss_conf,
2489 u32 changed)
2490{
2491 struct wl1271 *wl = hw->priv;
2492 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2493 int ret;
2494
2495 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2496 (int)changed);
2497
2498 mutex_lock(&wl->mutex);
2499
2500 if (unlikely(wl->state == WL1271_STATE_OFF))
2501 goto out;
2502
2503 ret = wl1271_ps_elp_wakeup(wl, false);
2504 if (ret < 0)
2505 goto out;
2506
2507 if (is_ap)
2508 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2509 else
2510 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512 wl1271_ps_elp_sleep(wl);
2513
2514out:
2515 mutex_unlock(&wl->mutex);
2516}
2517
Kalle Valoc6999d82010-02-18 13:25:41 +02002518static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2519 const struct ieee80211_tx_queue_params *params)
2520{
2521 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002522 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002523 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002524
2525 mutex_lock(&wl->mutex);
2526
2527 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2528
Kalle Valo4695dc92010-03-18 12:26:38 +02002529 if (params->uapsd)
2530 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2531 else
2532 ps_scheme = CONF_PS_SCHEME_LEGACY;
2533
Arik Nemtsov488fc542010-10-16 20:33:45 +02002534 if (wl->state == WL1271_STATE_OFF) {
2535 /*
2536 * If the state is off, the parameters will be recorded and
2537 * configured on init. This happens in AP-mode.
2538 */
2539 struct conf_tx_ac_category *conf_ac =
2540 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2541 struct conf_tx_tid *conf_tid =
2542 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2543
2544 conf_ac->ac = wl1271_tx_get_queue(queue);
2545 conf_ac->cw_min = (u8)params->cw_min;
2546 conf_ac->cw_max = params->cw_max;
2547 conf_ac->aifsn = params->aifs;
2548 conf_ac->tx_op_limit = params->txop << 5;
2549
2550 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2551 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2552 conf_tid->tsid = wl1271_tx_get_queue(queue);
2553 conf_tid->ps_scheme = ps_scheme;
2554 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2555 conf_tid->apsd_conf[0] = 0;
2556 conf_tid->apsd_conf[1] = 0;
2557 } else {
2558 ret = wl1271_ps_elp_wakeup(wl, false);
2559 if (ret < 0)
2560 goto out;
2561
2562 /*
2563 * the txop is confed in units of 32us by the mac80211,
2564 * we need us
2565 */
2566 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2567 params->cw_min, params->cw_max,
2568 params->aifs, params->txop << 5);
2569 if (ret < 0)
2570 goto out_sleep;
2571
2572 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2573 CONF_CHANNEL_TYPE_EDCF,
2574 wl1271_tx_get_queue(queue),
2575 ps_scheme, CONF_ACK_POLICY_LEGACY,
2576 0, 0);
2577 if (ret < 0)
2578 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002579
2580out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002581 wl1271_ps_elp_sleep(wl);
2582 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002583
2584out:
2585 mutex_unlock(&wl->mutex);
2586
2587 return ret;
2588}
2589
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002590static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2591{
2592
2593 struct wl1271 *wl = hw->priv;
2594 u64 mactime = ULLONG_MAX;
2595 int ret;
2596
2597 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2598
2599 mutex_lock(&wl->mutex);
2600
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002601 if (unlikely(wl->state == WL1271_STATE_OFF))
2602 goto out;
2603
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002604 ret = wl1271_ps_elp_wakeup(wl, false);
2605 if (ret < 0)
2606 goto out;
2607
2608 ret = wl1271_acx_tsf_info(wl, &mactime);
2609 if (ret < 0)
2610 goto out_sleep;
2611
2612out_sleep:
2613 wl1271_ps_elp_sleep(wl);
2614
2615out:
2616 mutex_unlock(&wl->mutex);
2617 return mactime;
2618}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002619
John W. Linvilleece550d2010-07-28 16:41:06 -04002620static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2621 struct survey_info *survey)
2622{
2623 struct wl1271 *wl = hw->priv;
2624 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002625
John W. Linvilleece550d2010-07-28 16:41:06 -04002626 if (idx != 0)
2627 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002628
John W. Linvilleece550d2010-07-28 16:41:06 -04002629 survey->channel = conf->channel;
2630 survey->filled = SURVEY_INFO_NOISE_DBM;
2631 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002632
John W. Linvilleece550d2010-07-28 16:41:06 -04002633 return 0;
2634}
2635
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002636static int wl1271_allocate_hlid(struct wl1271 *wl,
2637 struct ieee80211_sta *sta,
2638 u8 *hlid)
2639{
2640 struct wl1271_station *wl_sta;
2641 int id;
2642
2643 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2644 if (id >= AP_MAX_STATIONS) {
2645 wl1271_warning("could not allocate HLID - too much stations");
2646 return -EBUSY;
2647 }
2648
2649 wl_sta = (struct wl1271_station *)sta->drv_priv;
2650
2651 __set_bit(id, wl->ap_hlid_map);
2652 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2653 *hlid = wl_sta->hlid;
2654 return 0;
2655}
2656
2657static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2658{
2659 int id = hlid - WL1271_AP_STA_HLID_START;
2660
2661 __clear_bit(id, wl->ap_hlid_map);
2662}
2663
2664static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2665 struct ieee80211_vif *vif,
2666 struct ieee80211_sta *sta)
2667{
2668 struct wl1271 *wl = hw->priv;
2669 int ret = 0;
2670 u8 hlid;
2671
2672 mutex_lock(&wl->mutex);
2673
2674 if (unlikely(wl->state == WL1271_STATE_OFF))
2675 goto out;
2676
2677 if (wl->bss_type != BSS_TYPE_AP_BSS)
2678 goto out;
2679
2680 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2681
2682 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2683 if (ret < 0)
2684 goto out;
2685
2686 ret = wl1271_ps_elp_wakeup(wl, false);
2687 if (ret < 0)
2688 goto out;
2689
2690 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2691 if (ret < 0)
2692 goto out_sleep;
2693
2694out_sleep:
2695 wl1271_ps_elp_sleep(wl);
2696
2697out:
2698 mutex_unlock(&wl->mutex);
2699 return ret;
2700}
2701
2702static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2703 struct ieee80211_vif *vif,
2704 struct ieee80211_sta *sta)
2705{
2706 struct wl1271 *wl = hw->priv;
2707 struct wl1271_station *wl_sta;
2708 int ret = 0, id;
2709
2710 mutex_lock(&wl->mutex);
2711
2712 if (unlikely(wl->state == WL1271_STATE_OFF))
2713 goto out;
2714
2715 if (wl->bss_type != BSS_TYPE_AP_BSS)
2716 goto out;
2717
2718 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2719
2720 wl_sta = (struct wl1271_station *)sta->drv_priv;
2721 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2722 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2723 goto out;
2724
2725 ret = wl1271_ps_elp_wakeup(wl, false);
2726 if (ret < 0)
2727 goto out;
2728
2729 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2730 if (ret < 0)
2731 goto out_sleep;
2732
2733 wl1271_free_hlid(wl, wl_sta->hlid);
2734
2735out_sleep:
2736 wl1271_ps_elp_sleep(wl);
2737
2738out:
2739 mutex_unlock(&wl->mutex);
2740 return ret;
2741}
2742
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002743int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002744 enum ieee80211_ampdu_mlme_action action,
2745 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2746 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002747{
2748 struct wl1271 *wl = hw->priv;
2749 int ret;
2750
2751 mutex_lock(&wl->mutex);
2752
2753 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2754 ret = -EAGAIN;
2755 goto out;
2756 }
2757
2758 ret = wl1271_ps_elp_wakeup(wl, false);
2759 if (ret < 0)
2760 goto out;
2761
2762 switch (action) {
2763 case IEEE80211_AMPDU_RX_START:
2764 if (wl->ba_support) {
2765 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2766 true);
2767 if (!ret)
2768 wl->ba_rx_bitmap |= BIT(tid);
2769 } else {
2770 ret = -ENOTSUPP;
2771 }
2772 break;
2773
2774 case IEEE80211_AMPDU_RX_STOP:
2775 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2776 if (!ret)
2777 wl->ba_rx_bitmap &= ~BIT(tid);
2778 break;
2779
2780 /*
2781 * The BA initiator session management in FW independently.
2782 * Falling break here on purpose for all TX APDU commands.
2783 */
2784 case IEEE80211_AMPDU_TX_START:
2785 case IEEE80211_AMPDU_TX_STOP:
2786 case IEEE80211_AMPDU_TX_OPERATIONAL:
2787 ret = -EINVAL;
2788 break;
2789
2790 default:
2791 wl1271_error("Incorrect ampdu action id=%x\n", action);
2792 ret = -EINVAL;
2793 }
2794
2795 wl1271_ps_elp_sleep(wl);
2796
2797out:
2798 mutex_unlock(&wl->mutex);
2799
2800 return ret;
2801}
2802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002803/* can't be const, mac80211 writes to this */
2804static struct ieee80211_rate wl1271_rates[] = {
2805 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002806 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2807 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002809 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2810 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2812 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002813 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2814 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2816 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002817 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2818 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2820 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002821 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2822 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002823 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002824 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2825 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002827 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2828 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002829 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002830 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2831 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002832 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002833 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2834 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002835 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002836 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2837 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002838 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002839 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2840 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002842 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2843 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002844};
2845
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002846/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002847static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002848 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002849 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002850 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2851 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2852 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002853 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002854 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2855 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2856 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002857 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002858 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2859 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2860 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002861 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002862};
2863
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002864/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002865static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002866 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002867 7, /* CONF_HW_RXTX_RATE_MCS7 */
2868 6, /* CONF_HW_RXTX_RATE_MCS6 */
2869 5, /* CONF_HW_RXTX_RATE_MCS5 */
2870 4, /* CONF_HW_RXTX_RATE_MCS4 */
2871 3, /* CONF_HW_RXTX_RATE_MCS3 */
2872 2, /* CONF_HW_RXTX_RATE_MCS2 */
2873 1, /* CONF_HW_RXTX_RATE_MCS1 */
2874 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002875
2876 11, /* CONF_HW_RXTX_RATE_54 */
2877 10, /* CONF_HW_RXTX_RATE_48 */
2878 9, /* CONF_HW_RXTX_RATE_36 */
2879 8, /* CONF_HW_RXTX_RATE_24 */
2880
2881 /* TI-specific rate */
2882 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2883
2884 7, /* CONF_HW_RXTX_RATE_18 */
2885 6, /* CONF_HW_RXTX_RATE_12 */
2886 3, /* CONF_HW_RXTX_RATE_11 */
2887 5, /* CONF_HW_RXTX_RATE_9 */
2888 4, /* CONF_HW_RXTX_RATE_6 */
2889 2, /* CONF_HW_RXTX_RATE_5_5 */
2890 1, /* CONF_HW_RXTX_RATE_2 */
2891 0 /* CONF_HW_RXTX_RATE_1 */
2892};
2893
Shahar Levie8b03a22010-10-13 16:09:39 +02002894/* 11n STA capabilities */
2895#define HW_RX_HIGHEST_RATE 72
2896
Shahar Levi00d20102010-11-08 11:20:10 +00002897#ifdef CONFIG_WL12XX_HT
2898#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002899 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2900 .ht_supported = true, \
2901 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2902 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2903 .mcs = { \
2904 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2905 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2906 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2907 }, \
2908}
Shahar Levi18357852010-10-13 16:09:41 +02002909#else
Shahar Levi00d20102010-11-08 11:20:10 +00002910#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002911 .ht_supported = false, \
2912}
2913#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002915/* can't be const, mac80211 writes to this */
2916static struct ieee80211_supported_band wl1271_band_2ghz = {
2917 .channels = wl1271_channels,
2918 .n_channels = ARRAY_SIZE(wl1271_channels),
2919 .bitrates = wl1271_rates,
2920 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002921 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002922};
2923
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002924/* 5 GHz data rates for WL1273 */
2925static struct ieee80211_rate wl1271_rates_5ghz[] = {
2926 { .bitrate = 60,
2927 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2928 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2929 { .bitrate = 90,
2930 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2931 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2932 { .bitrate = 120,
2933 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2934 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2935 { .bitrate = 180,
2936 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2937 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2938 { .bitrate = 240,
2939 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2940 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2941 { .bitrate = 360,
2942 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2943 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2944 { .bitrate = 480,
2945 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2946 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2947 { .bitrate = 540,
2948 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2949 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2950};
2951
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002952/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002953static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002954 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002955 { .hw_value = 8, .center_freq = 5040},
2956 { .hw_value = 9, .center_freq = 5045},
2957 { .hw_value = 11, .center_freq = 5055},
2958 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002959 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002960 { .hw_value = 34, .center_freq = 5170},
2961 { .hw_value = 36, .center_freq = 5180},
2962 { .hw_value = 38, .center_freq = 5190},
2963 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002964 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002965 { .hw_value = 44, .center_freq = 5220},
2966 { .hw_value = 46, .center_freq = 5230},
2967 { .hw_value = 48, .center_freq = 5240},
2968 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002969 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002970 { .hw_value = 60, .center_freq = 5300},
2971 { .hw_value = 64, .center_freq = 5320},
2972 { .hw_value = 100, .center_freq = 5500},
2973 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002974 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002975 { .hw_value = 112, .center_freq = 5560},
2976 { .hw_value = 116, .center_freq = 5580},
2977 { .hw_value = 120, .center_freq = 5600},
2978 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002979 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002980 { .hw_value = 132, .center_freq = 5660},
2981 { .hw_value = 136, .center_freq = 5680},
2982 { .hw_value = 140, .center_freq = 5700},
2983 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002984 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002985 { .hw_value = 157, .center_freq = 5785},
2986 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002987 { .hw_value = 165, .center_freq = 5825},
2988};
2989
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002990/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002991static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002992 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002993 7, /* CONF_HW_RXTX_RATE_MCS7 */
2994 6, /* CONF_HW_RXTX_RATE_MCS6 */
2995 5, /* CONF_HW_RXTX_RATE_MCS5 */
2996 4, /* CONF_HW_RXTX_RATE_MCS4 */
2997 3, /* CONF_HW_RXTX_RATE_MCS3 */
2998 2, /* CONF_HW_RXTX_RATE_MCS2 */
2999 1, /* CONF_HW_RXTX_RATE_MCS1 */
3000 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003001
3002 7, /* CONF_HW_RXTX_RATE_54 */
3003 6, /* CONF_HW_RXTX_RATE_48 */
3004 5, /* CONF_HW_RXTX_RATE_36 */
3005 4, /* CONF_HW_RXTX_RATE_24 */
3006
3007 /* TI-specific rate */
3008 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3009
3010 3, /* CONF_HW_RXTX_RATE_18 */
3011 2, /* CONF_HW_RXTX_RATE_12 */
3012 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3013 1, /* CONF_HW_RXTX_RATE_9 */
3014 0, /* CONF_HW_RXTX_RATE_6 */
3015 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3016 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3017 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3018};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003019
3020static struct ieee80211_supported_band wl1271_band_5ghz = {
3021 .channels = wl1271_channels_5ghz,
3022 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3023 .bitrates = wl1271_rates_5ghz,
3024 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003025 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003026};
3027
Tobias Klausera0ea9492010-05-20 10:38:11 +02003028static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003029 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3030 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3031};
3032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033static const struct ieee80211_ops wl1271_ops = {
3034 .start = wl1271_op_start,
3035 .stop = wl1271_op_stop,
3036 .add_interface = wl1271_op_add_interface,
3037 .remove_interface = wl1271_op_remove_interface,
3038 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003039 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040 .configure_filter = wl1271_op_configure_filter,
3041 .tx = wl1271_op_tx,
3042 .set_key = wl1271_op_set_key,
3043 .hw_scan = wl1271_op_hw_scan,
3044 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003045 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003047 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003048 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003049 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003050 .sta_add = wl1271_op_sta_add,
3051 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003052 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003053 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003054};
3055
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003056
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003057u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003058{
3059 u8 idx;
3060
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003061 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003062
3063 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3064 wl1271_error("Illegal RX rate from HW: %d", rate);
3065 return 0;
3066 }
3067
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003068 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003069 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3070 wl1271_error("Unsupported RX rate from HW: %d", rate);
3071 return 0;
3072 }
3073
3074 return idx;
3075}
3076
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003077static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3078 struct device_attribute *attr,
3079 char *buf)
3080{
3081 struct wl1271 *wl = dev_get_drvdata(dev);
3082 ssize_t len;
3083
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003084 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003085
3086 mutex_lock(&wl->mutex);
3087 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3088 wl->sg_enabled);
3089 mutex_unlock(&wl->mutex);
3090
3091 return len;
3092
3093}
3094
3095static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3096 struct device_attribute *attr,
3097 const char *buf, size_t count)
3098{
3099 struct wl1271 *wl = dev_get_drvdata(dev);
3100 unsigned long res;
3101 int ret;
3102
3103 ret = strict_strtoul(buf, 10, &res);
3104
3105 if (ret < 0) {
3106 wl1271_warning("incorrect value written to bt_coex_mode");
3107 return count;
3108 }
3109
3110 mutex_lock(&wl->mutex);
3111
3112 res = !!res;
3113
3114 if (res == wl->sg_enabled)
3115 goto out;
3116
3117 wl->sg_enabled = res;
3118
3119 if (wl->state == WL1271_STATE_OFF)
3120 goto out;
3121
3122 ret = wl1271_ps_elp_wakeup(wl, false);
3123 if (ret < 0)
3124 goto out;
3125
3126 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3127 wl1271_ps_elp_sleep(wl);
3128
3129 out:
3130 mutex_unlock(&wl->mutex);
3131 return count;
3132}
3133
3134static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3135 wl1271_sysfs_show_bt_coex_state,
3136 wl1271_sysfs_store_bt_coex_state);
3137
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003138static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3139 struct device_attribute *attr,
3140 char *buf)
3141{
3142 struct wl1271 *wl = dev_get_drvdata(dev);
3143 ssize_t len;
3144
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003145 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003146
3147 mutex_lock(&wl->mutex);
3148 if (wl->hw_pg_ver >= 0)
3149 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3150 else
3151 len = snprintf(buf, len, "n/a\n");
3152 mutex_unlock(&wl->mutex);
3153
3154 return len;
3155}
3156
3157static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3158 wl1271_sysfs_show_hw_pg_ver, NULL);
3159
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003160int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003161{
3162 int ret;
3163
3164 if (wl->mac80211_registered)
3165 return 0;
3166
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003167 ret = wl1271_fetch_nvs(wl);
3168 if (ret == 0) {
3169 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3170
3171 wl->mac_addr[0] = nvs_ptr[11];
3172 wl->mac_addr[1] = nvs_ptr[10];
3173 wl->mac_addr[2] = nvs_ptr[6];
3174 wl->mac_addr[3] = nvs_ptr[5];
3175 wl->mac_addr[4] = nvs_ptr[4];
3176 wl->mac_addr[5] = nvs_ptr[3];
3177 }
3178
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003179 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3180
3181 ret = ieee80211_register_hw(wl->hw);
3182 if (ret < 0) {
3183 wl1271_error("unable to register mac80211 hw: %d", ret);
3184 return ret;
3185 }
3186
3187 wl->mac80211_registered = true;
3188
Eliad Pellerd60080a2010-11-24 12:53:16 +02003189 wl1271_debugfs_init(wl);
3190
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003191 register_netdevice_notifier(&wl1271_dev_notifier);
3192
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003193 wl1271_notice("loaded");
3194
3195 return 0;
3196}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003197EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003199void wl1271_unregister_hw(struct wl1271 *wl)
3200{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003201 if (wl->state == WL1271_STATE_PLT)
3202 __wl1271_plt_stop(wl);
3203
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003204 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003205 ieee80211_unregister_hw(wl->hw);
3206 wl->mac80211_registered = false;
3207
3208}
3209EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3210
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003211int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003213 static const u32 cipher_suites[] = {
3214 WLAN_CIPHER_SUITE_WEP40,
3215 WLAN_CIPHER_SUITE_WEP104,
3216 WLAN_CIPHER_SUITE_TKIP,
3217 WLAN_CIPHER_SUITE_CCMP,
3218 WL1271_CIPHER_SUITE_GEM,
3219 };
3220
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003221 /* The tx descriptor buffer and the TKIP space. */
3222 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3223 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003224
3225 /* unit us */
3226 /* FIXME: find a proper value */
3227 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003228 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003229
3230 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003231 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003232 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003233 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003234 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003235 IEEE80211_HW_CONNECTION_MONITOR |
3236 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003237
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003238 wl->hw->wiphy->cipher_suites = cipher_suites;
3239 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3240
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003241 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003242 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003244 /*
3245 * Maximum length of elements in scanning probe request templates
3246 * should be the maximum length possible for a template, without
3247 * the IEEE80211 header of the template
3248 */
3249 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3250 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003251
3252 /*
3253 * We keep local copies of the band structs because we need to
3254 * modify them on a per-device basis.
3255 */
3256 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3257 sizeof(wl1271_band_2ghz));
3258 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3259 sizeof(wl1271_band_5ghz));
3260
3261 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3262 &wl->bands[IEEE80211_BAND_2GHZ];
3263 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3264 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003265
Kalle Valo12bd8942010-03-18 12:26:33 +02003266 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003267 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003268
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003269 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3270
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003271 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003272
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003273 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3274
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003275 wl->hw->max_rx_aggregation_subframes = 8;
3276
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003277 return 0;
3278}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003279EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003280
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003281#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003282
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003283struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003284{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003285 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003286 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003287 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003288 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003289 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003290
3291 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3292 if (!hw) {
3293 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003294 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003295 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003296 }
3297
Julia Lawall929ebd32010-05-15 23:16:39 +02003298 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003299 if (!plat_dev) {
3300 wl1271_error("could not allocate platform_device");
3301 ret = -ENOMEM;
3302 goto err_plat_alloc;
3303 }
3304
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 wl = hw->priv;
3306 memset(wl, 0, sizeof(*wl));
3307
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003308 INIT_LIST_HEAD(&wl->list);
3309
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003311 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003312
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003313 for (i = 0; i < NUM_TX_QUEUES; i++)
3314 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003315
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003316 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003317 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003318 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3319 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3320 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3321 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003322 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003323 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003326 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3327 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003328 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003329 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003330 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003331 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003332 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3333 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003334 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003335 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003336 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003337 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003338 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003339 wl->bss_type = MAX_BSS_TYPE;
3340 wl->set_bss_type = MAX_BSS_TYPE;
3341 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003342
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003343 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003344 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003345 wl->tx_frames[i] = NULL;
3346
3347 spin_lock_init(&wl->wl_lock);
3348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003349 wl->state = WL1271_STATE_OFF;
3350 mutex_init(&wl->mutex);
3351
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003352 /* Apply default driver configuration. */
3353 wl1271_conf_init(wl);
3354
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003355 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3356 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3357 if (!wl->aggr_buf) {
3358 ret = -ENOMEM;
3359 goto err_hw;
3360 }
3361
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003362 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003363 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003364 if (ret) {
3365 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003366 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003367 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003368 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003369
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003370 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003371 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003372 if (ret < 0) {
3373 wl1271_error("failed to create sysfs file bt_coex_state");
3374 goto err_platform;
3375 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003376
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003377 /* Create sysfs file to get HW PG version */
3378 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3379 if (ret < 0) {
3380 wl1271_error("failed to create sysfs file hw_pg_ver");
3381 goto err_bt_coex_state;
3382 }
3383
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003384 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003385
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003386err_bt_coex_state:
3387 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3388
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003389err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003390 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003391
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003392err_aggr:
3393 free_pages((unsigned long)wl->aggr_buf, order);
3394
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003395err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003396 wl1271_debugfs_exit(wl);
3397 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003398
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003399err_plat_alloc:
3400 ieee80211_free_hw(hw);
3401
3402err_hw_alloc:
3403
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003404 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003405}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003406EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003407
3408int wl1271_free_hw(struct wl1271 *wl)
3409{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003410 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003411 free_pages((unsigned long)wl->aggr_buf,
3412 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003413 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003414
3415 wl1271_debugfs_exit(wl);
3416
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003417 vfree(wl->fw);
3418 wl->fw = NULL;
3419 kfree(wl->nvs);
3420 wl->nvs = NULL;
3421
3422 kfree(wl->fw_status);
3423 kfree(wl->tx_res_if);
3424
3425 ieee80211_free_hw(wl->hw);
3426
3427 return 0;
3428}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003429EXPORT_SYMBOL_GPL(wl1271_free_hw);
3430
Guy Eilam491bbd62011-01-12 10:33:29 +01003431u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003432EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003433module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003434MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3435
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003436MODULE_LICENSE("GPL");
3437MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3438MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");