blob: 732fd21beafb5e3545af9465e3dd03a346111cba [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>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020054 .params = {
55 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
104 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300105 },
106 .rx = {
107 .rx_msdu_life_time = 512000,
108 .packet_detection_threshold = 0,
109 .ps_poll_timeout = 15,
110 .upsd_timeout = 15,
111 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200112 .rx_cca_threshold = 0,
113 .irq_blk_threshold = 0xFFFF,
114 .irq_pkt_threshold = 0,
115 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300116 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
117 },
118 .tx = {
119 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200120 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300121 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300122 .short_retry_limit = 10,
123 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200124 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300125 },
126 .ac_conf_count = 4,
127 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200128 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300129 .ac = CONF_TX_AC_BE,
130 .cw_min = 15,
131 .cw_max = 63,
132 .aifsn = 3,
133 .tx_op_limit = 0,
134 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200135 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300136 .ac = CONF_TX_AC_BK,
137 .cw_min = 15,
138 .cw_max = 63,
139 .aifsn = 7,
140 .tx_op_limit = 0,
141 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200142 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300143 .ac = CONF_TX_AC_VI,
144 .cw_min = 15,
145 .cw_max = 63,
146 .aifsn = CONF_TX_AIFS_PIFS,
147 .tx_op_limit = 3008,
148 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200149 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300150 .ac = CONF_TX_AC_VO,
151 .cw_min = 15,
152 .cw_max = 63,
153 .aifsn = CONF_TX_AIFS_PIFS,
154 .tx_op_limit = 1504,
155 },
156 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200157 .ap_rc_conf = {
158 [0] = {
159 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
160 .short_retry_limit = 10,
161 .long_retry_limit = 10,
162 .aflags = 0,
163 },
164 [1] = {
165 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
166 .short_retry_limit = 10,
167 .long_retry_limit = 10,
168 .aflags = 0,
169 },
170 [2] = {
171 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
172 .short_retry_limit = 10,
173 .long_retry_limit = 10,
174 .aflags = 0,
175 },
176 [3] = {
177 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
178 .short_retry_limit = 10,
179 .long_retry_limit = 10,
180 .aflags = 0,
181 },
182 },
183 .ap_mgmt_conf = {
184 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
185 .short_retry_limit = 10,
186 .long_retry_limit = 10,
187 .aflags = 0,
188 },
189 .ap_bcst_conf = {
190 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
191 .short_retry_limit = 10,
192 .long_retry_limit = 10,
193 .aflags = 0,
194 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200195 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200196 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300197 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_BE] = {
199 .queue_id = CONF_TX_AC_BE,
200 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200206 [CONF_TX_AC_BK] = {
207 .queue_id = CONF_TX_AC_BK,
208 .channel_type = CONF_CHANNEL_TYPE_EDCF,
209 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200214 [CONF_TX_AC_VI] = {
215 .queue_id = CONF_TX_AC_VI,
216 .channel_type = CONF_CHANNEL_TYPE_EDCF,
217 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .ps_scheme = CONF_PS_SCHEME_LEGACY,
219 .ack_policy = CONF_ACK_POLICY_LEGACY,
220 .apsd_conf = {0, 0},
221 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200222 [CONF_TX_AC_VO] = {
223 .queue_id = CONF_TX_AC_VO,
224 .channel_type = CONF_CHANNEL_TYPE_EDCF,
225 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 .ps_scheme = CONF_PS_SCHEME_LEGACY,
227 .ack_policy = CONF_ACK_POLICY_LEGACY,
228 .apsd_conf = {0, 0},
229 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300230 },
231 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300233 .tx_compl_threshold = 4,
234 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
235 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200236 .tmpl_short_retry_limit = 10,
237 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300238 },
239 .conn = {
240 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300241 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300242 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
243 .bcn_filt_ie_count = 1,
244 .bcn_filt_ie = {
245 [0] = {
246 .ie = WLAN_EID_CHANNEL_SWITCH,
247 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
248 }
249 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200250 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300251 .bss_lose_timeout = 100,
252 .beacon_rx_timeout = 10000,
253 .broadcast_timeout = 20000,
254 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300255 .ps_poll_threshold = 10,
256 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300257 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200258 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200259 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200260 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200261 .psm_entry_nullfunc_retries = 3,
262 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300263 .keep_alive_interval = 55000,
264 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300265 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200266 .itrim = {
267 .enable = false,
268 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200269 },
270 .pm_config = {
271 .host_clk_settling_time = 5000,
272 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300273 },
274 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300275 .trigger_pacing = 1,
276 .avg_weight_rssi_beacon = 20,
277 .avg_weight_rssi_data = 10,
278 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100279 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200280 },
281 .scan = {
282 .min_dwell_time_active = 7500,
283 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100284 .min_dwell_time_passive = 100000,
285 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200286 .num_probe_reqs = 2,
287 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200288 .rf = {
289 .tx_per_channel_power_compensation_2 = {
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 },
292 .tx_per_channel_power_compensation_5 = {
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 },
297 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100298 .ht = {
299 .tx_ba_win_size = 64,
300 .inactivity_timeout = 10000,
301 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200303 .num_stations = 1,
304 .ssid_profiles = 1,
305 .rx_block_num = 70,
306 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200307 .dynamic_memory = 0,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200308 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200309 .min_req_rx_blocks = 22,
310 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200311 },
312 .mem_wl128x = {
313 .num_stations = 1,
314 .ssid_profiles = 1,
315 .rx_block_num = 40,
316 .tx_min_block_num = 40,
317 .dynamic_memory = 1,
318 .min_req_tx_blocks = 45,
319 .min_req_rx_blocks = 22,
320 .tx_min = 27,
321 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300322 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300323};
324
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200325static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200326static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200327
328
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200329static void wl1271_device_release(struct device *dev)
330{
331
332}
333
334static struct platform_device wl1271_device = {
335 .name = "wl1271",
336 .id = -1,
337
338 /* device model insists to have a release function */
339 .dev = {
340 .release = wl1271_device_release,
341 },
342};
343
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200344static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300345static LIST_HEAD(wl_list);
346
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300347static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
348 void *arg)
349{
350 struct net_device *dev = arg;
351 struct wireless_dev *wdev;
352 struct wiphy *wiphy;
353 struct ieee80211_hw *hw;
354 struct wl1271 *wl;
355 struct wl1271 *wl_temp;
356 int ret = 0;
357
358 /* Check that this notification is for us. */
359 if (what != NETDEV_CHANGE)
360 return NOTIFY_DONE;
361
362 wdev = dev->ieee80211_ptr;
363 if (wdev == NULL)
364 return NOTIFY_DONE;
365
366 wiphy = wdev->wiphy;
367 if (wiphy == NULL)
368 return NOTIFY_DONE;
369
370 hw = wiphy_priv(wiphy);
371 if (hw == NULL)
372 return NOTIFY_DONE;
373
374 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200375 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300376 list_for_each_entry(wl, &wl_list, list) {
377 if (wl == wl_temp)
378 break;
379 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200380 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300381 if (wl != wl_temp)
382 return NOTIFY_DONE;
383
384 mutex_lock(&wl->mutex);
385
386 if (wl->state == WL1271_STATE_OFF)
387 goto out;
388
389 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
390 goto out;
391
Ido Yariva6208652011-03-01 15:14:41 +0200392 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300393 if (ret < 0)
394 goto out;
395
396 if ((dev->operstate == IF_OPER_UP) &&
397 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
398 wl1271_cmd_set_sta_state(wl);
399 wl1271_info("Association completed.");
400 }
401
402 wl1271_ps_elp_sleep(wl);
403
404out:
405 mutex_unlock(&wl->mutex);
406
407 return NOTIFY_OK;
408}
409
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100410static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200411 struct regulatory_request *request)
412{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100413 struct ieee80211_supported_band *band;
414 struct ieee80211_channel *ch;
415 int i;
416
417 band = wiphy->bands[IEEE80211_BAND_5GHZ];
418 for (i = 0; i < band->n_channels; i++) {
419 ch = &band->channels[i];
420 if (ch->flags & IEEE80211_CHAN_DISABLED)
421 continue;
422
423 if (ch->flags & IEEE80211_CHAN_RADAR)
424 ch->flags |= IEEE80211_CHAN_NO_IBSS |
425 IEEE80211_CHAN_PASSIVE_SCAN;
426
427 }
428
429 return 0;
430}
431
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300432static void wl1271_conf_init(struct wl1271 *wl)
433{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300434
435 /*
436 * This function applies the default configuration to the driver. This
437 * function is invoked upon driver load (spi probe.)
438 *
439 * The configuration is stored in a run-time structure in order to
440 * facilitate for run-time adjustment of any of the parameters. Making
441 * changes to the configuration structure will apply the new values on
442 * the next interface up (wl1271_op_start.)
443 */
444
445 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300446 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300447}
448
449
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450static int wl1271_plt_init(struct wl1271 *wl)
451{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200452 struct conf_tx_ac_category *conf_ac;
453 struct conf_tx_tid *conf_tid;
454 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455
Shahar Levi49d750ca2011-03-06 16:32:09 +0200456 if (wl->chip.id == CHIP_ID_1283_PG20)
457 ret = wl128x_cmd_general_parms(wl);
458 else
459 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200460 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200461 return ret;
462
Shahar Levi49d750ca2011-03-06 16:32:09 +0200463 if (wl->chip.id == CHIP_ID_1283_PG20)
464 ret = wl128x_cmd_radio_parms(wl);
465 else
466 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200467 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200468 return ret;
469
Shahar Levi49d750ca2011-03-06 16:32:09 +0200470 if (wl->chip.id != CHIP_ID_1283_PG20) {
471 ret = wl1271_cmd_ext_radio_parms(wl);
472 if (ret < 0)
473 return ret;
474 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200475 if (ret < 0)
476 return ret;
477
Shahar Levi48a61472011-03-06 16:32:08 +0200478 /* Chip-specific initializations */
479 ret = wl1271_chip_specific_init(wl);
480 if (ret < 0)
481 return ret;
482
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200483 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200484 if (ret < 0)
485 return ret;
486
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487 ret = wl1271_acx_init_mem_config(wl);
488 if (ret < 0)
489 return ret;
490
Luciano Coelho12419cc2010-02-18 13:25:44 +0200491 /* PHY layer config */
492 ret = wl1271_init_phy_config(wl);
493 if (ret < 0)
494 goto out_free_memmap;
495
496 ret = wl1271_acx_dco_itrim_params(wl);
497 if (ret < 0)
498 goto out_free_memmap;
499
500 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200501 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200502 if (ret < 0)
503 goto out_free_memmap;
504
505 /* Bluetooth WLAN coexistence */
506 ret = wl1271_init_pta(wl);
507 if (ret < 0)
508 goto out_free_memmap;
509
510 /* Energy detection */
511 ret = wl1271_init_energy_detection(wl);
512 if (ret < 0)
513 goto out_free_memmap;
514
Gery Kahn1ec610e2011-02-01 03:03:08 -0600515 ret = wl1271_acx_sta_mem_cfg(wl);
516 if (ret < 0)
517 goto out_free_memmap;
518
Luciano Coelho12419cc2010-02-18 13:25:44 +0200519 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100520 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200521 if (ret < 0)
522 goto out_free_memmap;
523
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200524 /* Default TID/AC configuration */
525 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200526 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200527 conf_ac = &wl->conf.tx.ac_conf[i];
528 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
529 conf_ac->cw_max, conf_ac->aifsn,
530 conf_ac->tx_op_limit);
531 if (ret < 0)
532 goto out_free_memmap;
533
Luciano Coelho12419cc2010-02-18 13:25:44 +0200534 conf_tid = &wl->conf.tx.tid_conf[i];
535 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
536 conf_tid->channel_type,
537 conf_tid->tsid,
538 conf_tid->ps_scheme,
539 conf_tid->ack_policy,
540 conf_tid->apsd_conf[0],
541 conf_tid->apsd_conf[1]);
542 if (ret < 0)
543 goto out_free_memmap;
544 }
545
Luciano Coelho12419cc2010-02-18 13:25:44 +0200546 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200547 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300548 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200549 goto out_free_memmap;
550
551 /* Configure for CAM power saving (ie. always active) */
552 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
553 if (ret < 0)
554 goto out_free_memmap;
555
556 /* configure PM */
557 ret = wl1271_acx_pm_config(wl);
558 if (ret < 0)
559 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560
561 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200562
563 out_free_memmap:
564 kfree(wl->target_mem_map);
565 wl->target_mem_map = NULL;
566
567 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300568}
569
Arik Nemtsovb622d992011-02-23 00:22:31 +0200570static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
571{
572 bool fw_ps;
573
574 /* only regulate station links */
575 if (hlid < WL1271_AP_STA_HLID_START)
576 return;
577
578 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
579
580 /*
581 * Wake up from high level PS if the STA is asleep with too little
582 * blocks in FW or if the STA is awake.
583 */
584 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
585 wl1271_ps_link_end(wl, hlid);
586
587 /* Start high-level PS if the STA is asleep with enough blocks in FW */
588 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
589 wl1271_ps_link_start(wl, hlid, true);
590}
591
592static void wl1271_irq_update_links_status(struct wl1271 *wl,
593 struct wl1271_fw_ap_status *status)
594{
595 u32 cur_fw_ps_map;
596 u8 hlid;
597
598 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
599 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
600 wl1271_debug(DEBUG_PSM,
601 "link ps prev 0x%x cur 0x%x changed 0x%x",
602 wl->ap_fw_ps_map, cur_fw_ps_map,
603 wl->ap_fw_ps_map ^ cur_fw_ps_map);
604
605 wl->ap_fw_ps_map = cur_fw_ps_map;
606 }
607
608 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
609 u8 cnt = status->tx_lnk_free_blks[hlid] -
610 wl->links[hlid].prev_freed_blks;
611
612 wl->links[hlid].prev_freed_blks =
613 status->tx_lnk_free_blks[hlid];
614 wl->links[hlid].allocated_blks -= cnt;
615
616 wl1271_irq_ps_regulate_link(wl, hlid,
617 wl->links[hlid].allocated_blks);
618 }
619}
620
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300621static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200622 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200624 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200625 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200626 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200627 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628 int i;
629
Shahar Levi13b107d2011-03-06 16:32:12 +0200630 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200631 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
632 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200633 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200634 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
635 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200636 }
637
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300638 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
639 "drv_rx_counter = %d, tx_results_counter = %d)",
640 status->intr,
641 status->fw_rx_counter,
642 status->drv_rx_counter,
643 status->tx_results_counter);
644
645 /* update number of available TX blocks */
646 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200647 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
648 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300649
650 wl->tx_blocks_freed[i] =
651 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200652 }
653
Ido Yarivd2f4d472011-03-31 10:07:00 +0200654 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200655
Ido Yarivd2f4d472011-03-31 10:07:00 +0200656 if (wl->bss_type == BSS_TYPE_AP_BSS) {
657 /* Update num of allocated TX blocks per link and ps status */
658 wl1271_irq_update_links_status(wl, &full_status->ap);
659 wl->tx_blocks_available += freed_blocks;
660 } else {
661 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
662
663 /*
664 * The FW might change the total number of TX memblocks before
665 * we get a notification about blocks being released. Thus, the
666 * available blocks calculation might yield a temporary result
667 * which is lower than the actual available blocks. Keeping in
668 * mind that only blocks that were allocated can be moved from
669 * TX to RX, tx_blocks_available should never decrease here.
670 */
671 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
672 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
Ido Yariva5225502010-10-12 14:49:10 +0200675 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200676 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200677 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678
679 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200680 getnstimeofday(&ts);
681 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
682 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683}
684
Ido Yariva6208652011-03-01 15:14:41 +0200685static void wl1271_flush_deferred_work(struct wl1271 *wl)
686{
687 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200688
Ido Yariva6208652011-03-01 15:14:41 +0200689 /* Pass all received frames to the network stack */
690 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
691 ieee80211_rx_ni(wl->hw, skb);
692
693 /* Return sent skbs to the network stack */
694 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
695 ieee80211_tx_status(wl->hw, skb);
696}
697
698static void wl1271_netstack_work(struct work_struct *work)
699{
700 struct wl1271 *wl =
701 container_of(work, struct wl1271, netstack_work);
702
703 do {
704 wl1271_flush_deferred_work(wl);
705 } while (skb_queue_len(&wl->deferred_rx_queue));
706}
707
708#define WL1271_IRQ_MAX_LOOPS 256
709
710irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300713 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200714 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200715 struct wl1271 *wl = (struct wl1271 *)cookie;
716 bool done = false;
717 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200718 unsigned long flags;
719
720 /* TX might be handled here, avoid redundant work */
721 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
722 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723
Ido Yariv341b7cd2011-03-31 10:07:01 +0200724 /*
725 * In case edge triggered interrupt must be used, we cannot iterate
726 * more than once without introducing race conditions with the hardirq.
727 */
728 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
729 loopcount = 1;
730
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731 mutex_lock(&wl->mutex);
732
733 wl1271_debug(DEBUG_IRQ, "IRQ work");
734
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200735 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736 goto out;
737
Ido Yariva6208652011-03-01 15:14:41 +0200738 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739 if (ret < 0)
740 goto out;
741
Ido Yariva6208652011-03-01 15:14:41 +0200742 while (!done && loopcount--) {
743 /*
744 * In order to avoid a race with the hardirq, clear the flag
745 * before acknowledging the chip. Since the mutex is held,
746 * wl1271_ps_elp_wakeup cannot be called concurrently.
747 */
748 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
749 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200750
751 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200752 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200753 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200754 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200755 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200756 continue;
757 }
758
Eliad Pellerccc83b02010-10-27 14:09:57 +0200759 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
760 wl1271_error("watchdog interrupt received! "
761 "starting recovery.");
762 ieee80211_queue_work(wl->hw, &wl->recovery_work);
763
764 /* restarting the chip. ignore any other interrupt. */
765 goto out;
766 }
767
Ido Yariva6208652011-03-01 15:14:41 +0200768 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200769 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
770
Ido Yariv8aad2462011-03-01 15:14:38 +0200771 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200772
Ido Yariva5225502010-10-12 14:49:10 +0200773 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200774 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200775 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200776 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200777 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200778 /*
779 * In order to avoid starvation of the TX path,
780 * call the work function directly.
781 */
782 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200783 } else {
784 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200785 }
786
Ido Yariv8aad2462011-03-01 15:14:38 +0200787 /* check for tx results */
788 if (wl->fw_status->common.tx_results_counter !=
789 (wl->tx_results_count & 0xff))
790 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200791
792 /* Make sure the deferred queues don't get too long */
793 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
794 skb_queue_len(&wl->deferred_rx_queue);
795 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
796 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200797 }
798
799 if (intr & WL1271_ACX_INTR_EVENT_A) {
800 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
801 wl1271_event_handle(wl, 0);
802 }
803
804 if (intr & WL1271_ACX_INTR_EVENT_B) {
805 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
806 wl1271_event_handle(wl, 1);
807 }
808
809 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
810 wl1271_debug(DEBUG_IRQ,
811 "WL1271_ACX_INTR_INIT_COMPLETE");
812
813 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
814 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 }
816
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817 wl1271_ps_elp_sleep(wl);
818
819out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200820 spin_lock_irqsave(&wl->wl_lock, flags);
821 /* In case TX was not handled here, queue TX work */
822 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
823 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
824 wl->tx_queue_count)
825 ieee80211_queue_work(wl->hw, &wl->tx_work);
826 spin_unlock_irqrestore(&wl->wl_lock, flags);
827
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200829
830 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831}
Ido Yariva6208652011-03-01 15:14:41 +0200832EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834static int wl1271_fetch_firmware(struct wl1271 *wl)
835{
836 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200837 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838 int ret;
839
Arik Nemtsov166d5042010-10-16 21:44:57 +0200840 switch (wl->bss_type) {
841 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200842 if (wl->chip.id == CHIP_ID_1283_PG20)
843 fw_name = WL128X_AP_FW_NAME;
844 else
845 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200846 break;
847 case BSS_TYPE_IBSS:
848 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200849 if (wl->chip.id == CHIP_ID_1283_PG20)
850 fw_name = WL128X_FW_NAME;
851 else
852 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200853 break;
854 default:
855 wl1271_error("no compatible firmware for bss_type %d",
856 wl->bss_type);
857 return -EINVAL;
858 }
859
860 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
861
862 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863
864 if (ret < 0) {
865 wl1271_error("could not get firmware: %d", ret);
866 return ret;
867 }
868
869 if (fw->size % 4) {
870 wl1271_error("firmware size is not multiple of 32 bits: %zu",
871 fw->size);
872 ret = -EILSEQ;
873 goto out;
874 }
875
Arik Nemtsov166d5042010-10-16 21:44:57 +0200876 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300878 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879
880 if (!wl->fw) {
881 wl1271_error("could not allocate memory for the firmware");
882 ret = -ENOMEM;
883 goto out;
884 }
885
886 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200887 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888 ret = 0;
889
890out:
891 release_firmware(fw);
892
893 return ret;
894}
895
896static int wl1271_fetch_nvs(struct wl1271 *wl)
897{
898 const struct firmware *fw;
899 int ret;
900
Shahar Levi5aa42342011-03-06 16:32:07 +0200901 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 if (ret < 0) {
904 wl1271_error("could not get nvs file: %d", ret);
905 return ret;
906 }
907
Shahar Levibc765bf2011-03-06 16:32:10 +0200908 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909
910 if (!wl->nvs) {
911 wl1271_error("could not allocate memory for the nvs file");
912 ret = -ENOMEM;
913 goto out;
914 }
915
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200916 wl->nvs_len = fw->size;
917
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918out:
919 release_firmware(fw);
920
921 return ret;
922}
923
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200924static void wl1271_recovery_work(struct work_struct *work)
925{
926 struct wl1271 *wl =
927 container_of(work, struct wl1271, recovery_work);
928
929 mutex_lock(&wl->mutex);
930
931 if (wl->state != WL1271_STATE_ON)
932 goto out;
933
934 wl1271_info("Hardware recovery in progress.");
935
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200936 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
937 ieee80211_connection_loss(wl->vif);
938
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200939 /* reboot the chipset */
940 __wl1271_op_remove_interface(wl);
941 ieee80211_restart_hw(wl->hw);
942
943out:
944 mutex_unlock(&wl->mutex);
945}
946
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947static void wl1271_fw_wakeup(struct wl1271 *wl)
948{
949 u32 elp_reg;
950
951 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300952 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953}
954
955static int wl1271_setup(struct wl1271 *wl)
956{
957 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
958 if (!wl->fw_status)
959 return -ENOMEM;
960
961 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
962 if (!wl->tx_res_if) {
963 kfree(wl->fw_status);
964 return -ENOMEM;
965 }
966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967 return 0;
968}
969
970static int wl1271_chip_wakeup(struct wl1271 *wl)
971{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300972 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 int ret = 0;
974
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200975 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200976 ret = wl1271_power_on(wl);
977 if (ret < 0)
978 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200980 wl1271_io_reset(wl);
981 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982
983 /* We don't need a real memory partition here, because we only want
984 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300985 memset(&partition, 0, sizeof(partition));
986 partition.reg.start = REGISTERS_BASE;
987 partition.reg.size = REGISTERS_DOWN_SIZE;
988 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989
990 /* ELP module wake up */
991 wl1271_fw_wakeup(wl);
992
993 /* whal_FwCtrl_BootSm() */
994
995 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200996 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997
998 /* 1. check if chip id is valid */
999
1000 switch (wl->chip.id) {
1001 case CHIP_ID_1271_PG10:
1002 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1003 wl->chip.id);
1004
1005 ret = wl1271_setup(wl);
1006 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001007 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008 break;
1009 case CHIP_ID_1271_PG20:
1010 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1011 wl->chip.id);
1012
1013 ret = wl1271_setup(wl);
1014 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001015 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001017 case CHIP_ID_1283_PG20:
1018 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1019 wl->chip.id);
1020
1021 ret = wl1271_setup(wl);
1022 if (ret < 0)
1023 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001024 if (wl1271_set_block_size(wl))
1025 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001026 break;
1027 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001029 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001031 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032 }
1033
Arik Nemtsov166d5042010-10-16 21:44:57 +02001034 /* Make sure the firmware type matches the BSS type */
1035 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 ret = wl1271_fetch_firmware(wl);
1037 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001038 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 }
1040
1041 /* No NVS from netlink, try to get it from the filesystem */
1042 if (wl->nvs == NULL) {
1043 ret = wl1271_fetch_nvs(wl);
1044 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001045 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 }
1047
1048out:
1049 return ret;
1050}
1051
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001052static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1053{
1054 unsigned int quirks = 0;
1055 unsigned int *fw_ver = wl->chip.fw_ver;
1056
1057 /* Only for wl127x */
1058 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1059 /* Check STA version */
1060 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1061 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1062 /* Check AP version */
1063 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1064 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1065 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1066
1067 return quirks;
1068}
1069
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070int wl1271_plt_start(struct wl1271 *wl)
1071{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001072 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073 int ret;
1074
1075 mutex_lock(&wl->mutex);
1076
1077 wl1271_notice("power up");
1078
1079 if (wl->state != WL1271_STATE_OFF) {
1080 wl1271_error("cannot go into PLT state because not "
1081 "in off state: %d", wl->state);
1082 ret = -EBUSY;
1083 goto out;
1084 }
1085
Arik Nemtsov166d5042010-10-16 21:44:57 +02001086 wl->bss_type = BSS_TYPE_STA_BSS;
1087
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001088 while (retries) {
1089 retries--;
1090 ret = wl1271_chip_wakeup(wl);
1091 if (ret < 0)
1092 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001094 ret = wl1271_boot(wl);
1095 if (ret < 0)
1096 goto power_off;
1097
1098 ret = wl1271_plt_init(wl);
1099 if (ret < 0)
1100 goto irq_disable;
1101
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001102 wl->state = WL1271_STATE_PLT;
1103 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001104 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001105
1106 /* Check if any quirks are needed with older fw versions */
1107 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001108 goto out;
1109
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001110irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001111 mutex_unlock(&wl->mutex);
1112 /* Unlocking the mutex in the middle of handling is
1113 inherently unsafe. In this case we deem it safe to do,
1114 because we need to let any possibly pending IRQ out of
1115 the system (and while we are WL1271_STATE_OFF the IRQ
1116 work function will not do anything.) Also, any other
1117 possible concurrent operations will fail due to the
1118 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001119 wl1271_disable_interrupts(wl);
1120 wl1271_flush_deferred_work(wl);
1121 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001122 mutex_lock(&wl->mutex);
1123power_off:
1124 wl1271_power_off(wl);
1125 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001127 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1128 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129out:
1130 mutex_unlock(&wl->mutex);
1131
1132 return ret;
1133}
1134
Luciano Coelho4623ec72011-03-21 19:26:41 +02001135static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136{
1137 int ret = 0;
1138
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139 wl1271_notice("power down");
1140
1141 if (wl->state != WL1271_STATE_PLT) {
1142 wl1271_error("cannot power down because not in PLT "
1143 "state: %d", wl->state);
1144 ret = -EBUSY;
1145 goto out;
1146 }
1147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001148 wl1271_power_off(wl);
1149
1150 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001151 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001152
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001154 wl1271_disable_interrupts(wl);
1155 wl1271_flush_deferred_work(wl);
1156 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001158 mutex_lock(&wl->mutex);
1159out:
1160 return ret;
1161}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001162
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001163int wl1271_plt_stop(struct wl1271 *wl)
1164{
1165 int ret;
1166
1167 mutex_lock(&wl->mutex);
1168 ret = __wl1271_plt_stop(wl);
1169 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170 return ret;
1171}
1172
Johannes Berg7bb45682011-02-24 14:42:06 +01001173static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174{
1175 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001176 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001177 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001178 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179
Ido Yarivb07d4032011-03-01 15:14:43 +02001180 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1181
1182 if (wl->bss_type == BSS_TYPE_AP_BSS)
1183 hlid = wl1271_tx_get_hlid(skb);
1184
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001185 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001186
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001187 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001188
1189 /*
1190 * The workqueue is slow to process the tx_queue and we need stop
1191 * the queue here, otherwise the queue will get too long.
1192 */
1193 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1194 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1195 ieee80211_stop_queues(wl->hw);
1196 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1197 }
1198
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001199 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001200 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001201 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1202 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1203 } else {
1204 skb_queue_tail(&wl->tx_queue[q], skb);
1205 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206
1207 /*
1208 * The chip specific setup must run before the first TX packet -
1209 * before that, the tx_work will not be initialized!
1210 */
1211
Ido Yarivb07d4032011-03-01 15:14:43 +02001212 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1213 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001214 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001215
1216 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217}
1218
Shahar Leviae47c452011-03-06 16:32:14 +02001219int wl1271_tx_dummy_packet(struct wl1271 *wl)
1220{
Ido Yariv990f5de2011-03-31 10:06:59 +02001221 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001222
Ido Yariv990f5de2011-03-31 10:06:59 +02001223 spin_lock_irqsave(&wl->wl_lock, flags);
1224 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1225 wl->tx_queue_count++;
1226 spin_unlock_irqrestore(&wl->wl_lock, flags);
1227
1228 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1229 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1230 wl1271_tx_work_locked(wl);
1231
1232 /*
1233 * If the FW TX is busy, TX work will be scheduled by the threaded
1234 * interrupt handler function
1235 */
1236 return 0;
1237}
1238
1239/*
1240 * The size of the dummy packet should be at least 1400 bytes. However, in
1241 * order to minimize the number of bus transactions, aligning it to 512 bytes
1242 * boundaries could be beneficial, performance wise
1243 */
1244#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1245
1246struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
1247{
1248 struct sk_buff *skb;
1249 struct ieee80211_hdr_3addr *hdr;
1250 unsigned int dummy_packet_size;
1251
1252 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1253 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1254
1255 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001256 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001257 wl1271_warning("Failed to allocate a dummy packet skb");
1258 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001259 }
1260
1261 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1262
1263 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1264 memset(hdr, 0, sizeof(*hdr));
1265 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001266 IEEE80211_STYPE_NULLFUNC |
1267 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001268
Ido Yariv990f5de2011-03-31 10:06:59 +02001269 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001270
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001271 /* Dummy packets require the TID to be management */
1272 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001273
1274 /* Initialize all fields that might be used */
Shahar Leviae47c452011-03-06 16:32:14 +02001275 skb->queue_mapping = 0;
Ido Yariv990f5de2011-03-31 10:06:59 +02001276 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001277
Ido Yariv990f5de2011-03-31 10:06:59 +02001278 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001279}
1280
Ido Yariv990f5de2011-03-31 10:06:59 +02001281
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001282static struct notifier_block wl1271_dev_notifier = {
1283 .notifier_call = wl1271_dev_notify,
1284};
1285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286static int wl1271_op_start(struct ieee80211_hw *hw)
1287{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001288 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1289
1290 /*
1291 * We have to delay the booting of the hardware because
1292 * we need to know the local MAC address before downloading and
1293 * initializing the firmware. The MAC address cannot be changed
1294 * after boot, and without the proper MAC address, the firmware
1295 * will not function properly.
1296 *
1297 * The MAC address is first known when the corresponding interface
1298 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001299 *
1300 * In addition, we currently have different firmwares for AP and managed
1301 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001302 */
1303
1304 return 0;
1305}
1306
1307static void wl1271_op_stop(struct ieee80211_hw *hw)
1308{
1309 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1310}
1311
1312static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1313 struct ieee80211_vif *vif)
1314{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001316 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001317 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001319 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001321 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1322 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
1324 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001325 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001326 wl1271_debug(DEBUG_MAC80211,
1327 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001328 ret = -EBUSY;
1329 goto out;
1330 }
1331
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001332 /*
1333 * in some very corner case HW recovery scenarios its possible to
1334 * get here before __wl1271_op_remove_interface is complete, so
1335 * opt out if that is the case.
1336 */
1337 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1338 ret = -EBUSY;
1339 goto out;
1340 }
1341
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001342 switch (vif->type) {
1343 case NL80211_IFTYPE_STATION:
1344 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001345 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001346 break;
1347 case NL80211_IFTYPE_ADHOC:
1348 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001349 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001350 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001351 case NL80211_IFTYPE_AP:
1352 wl->bss_type = BSS_TYPE_AP_BSS;
1353 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001354 default:
1355 ret = -EOPNOTSUPP;
1356 goto out;
1357 }
1358
1359 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360
1361 if (wl->state != WL1271_STATE_OFF) {
1362 wl1271_error("cannot start because not in off state: %d",
1363 wl->state);
1364 ret = -EBUSY;
1365 goto out;
1366 }
1367
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001368 while (retries) {
1369 retries--;
1370 ret = wl1271_chip_wakeup(wl);
1371 if (ret < 0)
1372 goto power_off;
1373
1374 ret = wl1271_boot(wl);
1375 if (ret < 0)
1376 goto power_off;
1377
1378 ret = wl1271_hw_init(wl);
1379 if (ret < 0)
1380 goto irq_disable;
1381
Eliad Peller71125ab2010-10-28 21:46:43 +02001382 booted = true;
1383 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386 mutex_unlock(&wl->mutex);
1387 /* Unlocking the mutex in the middle of handling is
1388 inherently unsafe. In this case we deem it safe to do,
1389 because we need to let any possibly pending IRQ out of
1390 the system (and while we are WL1271_STATE_OFF the IRQ
1391 work function will not do anything.) Also, any other
1392 possible concurrent operations will fail due to the
1393 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001394 wl1271_disable_interrupts(wl);
1395 wl1271_flush_deferred_work(wl);
1396 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 mutex_lock(&wl->mutex);
1398power_off:
1399 wl1271_power_off(wl);
1400 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401
Eliad Peller71125ab2010-10-28 21:46:43 +02001402 if (!booted) {
1403 wl1271_error("firmware boot failed despite %d retries",
1404 WL1271_BOOT_RETRIES);
1405 goto out;
1406 }
1407
1408 wl->vif = vif;
1409 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001410 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001411 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001412
1413 /* update hw/fw version info in wiphy struct */
1414 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001415 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001416 sizeof(wiphy->fw_version));
1417
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001418 /* Check if any quirks are needed with older fw versions */
1419 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1420
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001421 /*
1422 * Now we know if 11a is supported (info from the NVS), so disable
1423 * 11a channels if not supported
1424 */
1425 if (!wl->enable_11a)
1426 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1427
1428 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1429 wl->enable_11a ? "" : "not ");
1430
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001431out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 mutex_unlock(&wl->mutex);
1433
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001434 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001435 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001436 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001437 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 return ret;
1440}
1441
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001442static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 int i;
1445
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001446 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001448 /* because of hardware recovery, we may get here twice */
1449 if (wl->state != WL1271_STATE_ON)
1450 return;
1451
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001452 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001454 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001455 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001456 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001457
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001458 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001459 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001460 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001461
Luciano Coelho08688d62010-07-08 17:50:07 +03001462 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001463 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001464 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001465 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001466 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 }
1468
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001469 /*
1470 * this must be before the cancel_work calls below, so that the work
1471 * functions don't perform further work.
1472 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473 wl->state = WL1271_STATE_OFF;
1474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 mutex_unlock(&wl->mutex);
1476
Ido Yariva6208652011-03-01 15:14:41 +02001477 wl1271_disable_interrupts(wl);
1478 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001479 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001480 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001482 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001483 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484
1485 mutex_lock(&wl->mutex);
1486
1487 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001488 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489 wl1271_power_off(wl);
1490
1491 memset(wl->bssid, 0, ETH_ALEN);
1492 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1493 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001495 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001496 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497
1498 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001499 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1501 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001502 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 wl->tx_results_count = 0;
1504 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001505 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001506 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 wl->time_offset = 0;
1508 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001509 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001510 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001511 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001512 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001513 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001514 wl->ap_fw_ps_map = 0;
1515 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001516
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001517 /*
1518 * this is performed after the cancel_work calls and the associated
1519 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1520 * get executed before all these vars have been reset.
1521 */
1522 wl->flags = 0;
1523
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524 for (i = 0; i < NUM_TX_QUEUES; i++)
1525 wl->tx_blocks_freed[i] = 0;
1526
1527 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001528
1529 kfree(wl->fw_status);
1530 wl->fw_status = NULL;
1531 kfree(wl->tx_res_if);
1532 wl->tx_res_if = NULL;
1533 kfree(wl->target_mem_map);
1534 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001535}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001536
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001537static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1538 struct ieee80211_vif *vif)
1539{
1540 struct wl1271 *wl = hw->priv;
1541
1542 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001543 /*
1544 * wl->vif can be null here if someone shuts down the interface
1545 * just when hardware recovery has been started.
1546 */
1547 if (wl->vif) {
1548 WARN_ON(wl->vif != vif);
1549 __wl1271_op_remove_interface(wl);
1550 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001551
Juuso Oikarinen67353292010-11-18 15:19:02 +02001552 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001553 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554}
1555
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001556void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001557{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001558 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001559
1560 /* combine requested filters with current filter config */
1561 filters = wl->filters | filters;
1562
1563 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1564
1565 if (filters & FIF_PROMISC_IN_BSS) {
1566 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1567 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1568 wl->rx_config |= CFG_BSSID_FILTER_EN;
1569 }
1570 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1571 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1572 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1573 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1574 }
1575 if (filters & FIF_OTHER_BSS) {
1576 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1577 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1578 }
1579 if (filters & FIF_CONTROL) {
1580 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1581 wl->rx_filter |= CFG_RX_CTL_EN;
1582 }
1583 if (filters & FIF_FCSFAIL) {
1584 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1585 wl->rx_filter |= CFG_RX_FCS_ERROR;
1586 }
1587}
1588
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001589static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001590{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001591 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001592 /* we need to use a dummy BSSID for now */
1593 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1594 0xad, 0xbe, 0xef };
1595
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001596 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1597
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001598 /* pass through frames from all BSS */
1599 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1600
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001601 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001602 if (ret < 0)
1603 goto out;
1604
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001605 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001606
1607out:
1608 return ret;
1609}
1610
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001611static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001612{
1613 int ret;
1614
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001615 /*
1616 * One of the side effects of the JOIN command is that is clears
1617 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1618 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001619 * Currently the only valid scenario for JOIN during association
1620 * is on roaming, in which case we will also be given new keys.
1621 * Keep the below message for now, unless it starts bothering
1622 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001623 */
1624 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1625 wl1271_info("JOIN while associated.");
1626
1627 if (set_assoc)
1628 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1629
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001630 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1631 if (ret < 0)
1632 goto out;
1633
1634 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1635
1636 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1637 goto out;
1638
1639 /*
1640 * The join command disable the keep-alive mode, shut down its process,
1641 * and also clear the template config, so we need to reset it all after
1642 * the join. The acx_aid starts the keep-alive process, and the order
1643 * of the commands below is relevant.
1644 */
1645 ret = wl1271_acx_keep_alive_mode(wl, true);
1646 if (ret < 0)
1647 goto out;
1648
1649 ret = wl1271_acx_aid(wl, wl->aid);
1650 if (ret < 0)
1651 goto out;
1652
1653 ret = wl1271_cmd_build_klv_null_data(wl);
1654 if (ret < 0)
1655 goto out;
1656
1657 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1658 ACX_KEEP_ALIVE_TPL_VALID);
1659 if (ret < 0)
1660 goto out;
1661
1662out:
1663 return ret;
1664}
1665
1666static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001667{
1668 int ret;
1669
1670 /* to stop listening to a channel, we disconnect */
1671 ret = wl1271_cmd_disconnect(wl);
1672 if (ret < 0)
1673 goto out;
1674
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001675 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001676 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001677
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001678 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001679 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001680
1681out:
1682 return ret;
1683}
1684
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001685static void wl1271_set_band_rate(struct wl1271 *wl)
1686{
1687 if (wl->band == IEEE80211_BAND_2GHZ)
1688 wl->basic_rate_set = wl->conf.tx.basic_rate;
1689 else
1690 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1691}
1692
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001693static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001694{
1695 int ret;
1696
1697 if (idle) {
1698 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1699 ret = wl1271_unjoin(wl);
1700 if (ret < 0)
1701 goto out;
1702 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001703 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001704 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001705 if (ret < 0)
1706 goto out;
1707 ret = wl1271_acx_keep_alive_config(
1708 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1709 ACX_KEEP_ALIVE_TPL_INVALID);
1710 if (ret < 0)
1711 goto out;
1712 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1713 } else {
1714 /* increment the session counter */
1715 wl->session_counter++;
1716 if (wl->session_counter >= SESSION_COUNTER_MAX)
1717 wl->session_counter = 0;
1718 ret = wl1271_dummy_join(wl);
1719 if (ret < 0)
1720 goto out;
1721 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1722 }
1723
1724out:
1725 return ret;
1726}
1727
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1729{
1730 struct wl1271 *wl = hw->priv;
1731 struct ieee80211_conf *conf = &hw->conf;
1732 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001733 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734
1735 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1736
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001737 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1738 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739 channel,
1740 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001741 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001742 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1743 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001744
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001745 /*
1746 * mac80211 will go to idle nearly immediately after transmitting some
1747 * frames, such as the deauth. To make sure those frames reach the air,
1748 * wait here until the TX queue is fully flushed.
1749 */
1750 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1751 (conf->flags & IEEE80211_CONF_IDLE))
1752 wl1271_tx_flush(wl);
1753
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001754 mutex_lock(&wl->mutex);
1755
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001756 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001757 /* we support configuring the channel and band while off */
1758 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1759 wl->band = conf->channel->band;
1760 wl->channel = channel;
1761 }
1762
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001763 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001764 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001765
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001766 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1767
Ido Yariva6208652011-03-01 15:14:41 +02001768 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769 if (ret < 0)
1770 goto out;
1771
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001772 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001773 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1774 ((wl->band != conf->channel->band) ||
1775 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001776 wl->band = conf->channel->band;
1777 wl->channel = channel;
1778
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001779 if (!is_ap) {
1780 /*
1781 * FIXME: the mac80211 should really provide a fixed
1782 * rate to use here. for now, just use the smallest
1783 * possible rate for the band as a fixed rate for
1784 * association frames and other control messages.
1785 */
1786 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1787 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001788
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001789 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1790 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001791 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001792 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001793 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001794
1795 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1796 ret = wl1271_join(wl, false);
1797 if (ret < 0)
1798 wl1271_warning("cmd join on channel "
1799 "failed %d", ret);
1800 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001801 }
1802 }
1803
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001804 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1805 ret = wl1271_sta_handle_idle(wl,
1806 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001807 if (ret < 0)
1808 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001809 }
1810
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001811 /*
1812 * if mac80211 changes the PSM mode, make sure the mode is not
1813 * incorrectly changed after the pspoll failure active window.
1814 */
1815 if (changed & IEEE80211_CONF_CHANGE_PS)
1816 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1817
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001818 if (conf->flags & IEEE80211_CONF_PS &&
1819 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1820 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821
1822 /*
1823 * We enter PSM only if we're already associated.
1824 * If we're not, we'll enter it when joining an SSID,
1825 * through the bss_info_changed() hook.
1826 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001827 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001828 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001829 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001830 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001831 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001833 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001834 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001836 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001838 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001839 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001840 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 }
1842
1843 if (conf->power_level != wl->power_level) {
1844 ret = wl1271_acx_tx_power(wl, conf->power_level);
1845 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001846 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847
1848 wl->power_level = conf->power_level;
1849 }
1850
1851out_sleep:
1852 wl1271_ps_elp_sleep(wl);
1853
1854out:
1855 mutex_unlock(&wl->mutex);
1856
1857 return ret;
1858}
1859
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001860struct wl1271_filter_params {
1861 bool enabled;
1862 int mc_list_length;
1863 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1864};
1865
Jiri Pirko22bedad2010-04-01 21:22:57 +00001866static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1867 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001868{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001869 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001870 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001871 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001872
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001873 if (unlikely(wl->state == WL1271_STATE_OFF))
1874 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001875
Juuso Oikarinen74441132009-10-13 12:47:53 +03001876 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001877 if (!fp) {
1878 wl1271_error("Out of memory setting filters.");
1879 return 0;
1880 }
1881
1882 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001883 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001884 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1885 fp->enabled = false;
1886 } else {
1887 fp->enabled = true;
1888 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001889 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001890 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001891 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001892 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001893 }
1894
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001895 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001896}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001898#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1899 FIF_ALLMULTI | \
1900 FIF_FCSFAIL | \
1901 FIF_BCN_PRBRESP_PROMISC | \
1902 FIF_CONTROL | \
1903 FIF_OTHER_BSS)
1904
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001905static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1906 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001907 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001909 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001911 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912
Arik Nemtsov7d057862010-10-16 19:25:35 +02001913 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1914 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001916 mutex_lock(&wl->mutex);
1917
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001918 *total &= WL1271_SUPPORTED_FILTERS;
1919 changed &= WL1271_SUPPORTED_FILTERS;
1920
1921 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001922 goto out;
1923
Ido Yariva6208652011-03-01 15:14:41 +02001924 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001925 if (ret < 0)
1926 goto out;
1927
Arik Nemtsov7d057862010-10-16 19:25:35 +02001928 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1929 if (*total & FIF_ALLMULTI)
1930 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1931 else if (fp)
1932 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1933 fp->mc_list,
1934 fp->mc_list_length);
1935 if (ret < 0)
1936 goto out_sleep;
1937 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001939 /* determine, whether supported filter values have changed */
1940 if (changed == 0)
1941 goto out_sleep;
1942
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001943 /* configure filters */
1944 wl->filters = *total;
1945 wl1271_configure_filters(wl, 0);
1946
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001947 /* apply configured filters */
1948 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1949 if (ret < 0)
1950 goto out_sleep;
1951
1952out_sleep:
1953 wl1271_ps_elp_sleep(wl);
1954
1955out:
1956 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001957 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958}
1959
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001960static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1961 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1962 u16 tx_seq_16)
1963{
1964 struct wl1271_ap_key *ap_key;
1965 int i;
1966
1967 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1968
1969 if (key_size > MAX_KEY_SIZE)
1970 return -EINVAL;
1971
1972 /*
1973 * Find next free entry in ap_keys. Also check we are not replacing
1974 * an existing key.
1975 */
1976 for (i = 0; i < MAX_NUM_KEYS; i++) {
1977 if (wl->recorded_ap_keys[i] == NULL)
1978 break;
1979
1980 if (wl->recorded_ap_keys[i]->id == id) {
1981 wl1271_warning("trying to record key replacement");
1982 return -EINVAL;
1983 }
1984 }
1985
1986 if (i == MAX_NUM_KEYS)
1987 return -EBUSY;
1988
1989 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1990 if (!ap_key)
1991 return -ENOMEM;
1992
1993 ap_key->id = id;
1994 ap_key->key_type = key_type;
1995 ap_key->key_size = key_size;
1996 memcpy(ap_key->key, key, key_size);
1997 ap_key->hlid = hlid;
1998 ap_key->tx_seq_32 = tx_seq_32;
1999 ap_key->tx_seq_16 = tx_seq_16;
2000
2001 wl->recorded_ap_keys[i] = ap_key;
2002 return 0;
2003}
2004
2005static void wl1271_free_ap_keys(struct wl1271 *wl)
2006{
2007 int i;
2008
2009 for (i = 0; i < MAX_NUM_KEYS; i++) {
2010 kfree(wl->recorded_ap_keys[i]);
2011 wl->recorded_ap_keys[i] = NULL;
2012 }
2013}
2014
2015static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2016{
2017 int i, ret = 0;
2018 struct wl1271_ap_key *key;
2019 bool wep_key_added = false;
2020
2021 for (i = 0; i < MAX_NUM_KEYS; i++) {
2022 if (wl->recorded_ap_keys[i] == NULL)
2023 break;
2024
2025 key = wl->recorded_ap_keys[i];
2026 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2027 key->id, key->key_type,
2028 key->key_size, key->key,
2029 key->hlid, key->tx_seq_32,
2030 key->tx_seq_16);
2031 if (ret < 0)
2032 goto out;
2033
2034 if (key->key_type == KEY_WEP)
2035 wep_key_added = true;
2036 }
2037
2038 if (wep_key_added) {
2039 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2040 if (ret < 0)
2041 goto out;
2042 }
2043
2044out:
2045 wl1271_free_ap_keys(wl);
2046 return ret;
2047}
2048
2049static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2050 u8 key_size, const u8 *key, u32 tx_seq_32,
2051 u16 tx_seq_16, struct ieee80211_sta *sta)
2052{
2053 int ret;
2054 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2055
2056 if (is_ap) {
2057 struct wl1271_station *wl_sta;
2058 u8 hlid;
2059
2060 if (sta) {
2061 wl_sta = (struct wl1271_station *)sta->drv_priv;
2062 hlid = wl_sta->hlid;
2063 } else {
2064 hlid = WL1271_AP_BROADCAST_HLID;
2065 }
2066
2067 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2068 /*
2069 * We do not support removing keys after AP shutdown.
2070 * Pretend we do to make mac80211 happy.
2071 */
2072 if (action != KEY_ADD_OR_REPLACE)
2073 return 0;
2074
2075 ret = wl1271_record_ap_key(wl, id,
2076 key_type, key_size,
2077 key, hlid, tx_seq_32,
2078 tx_seq_16);
2079 } else {
2080 ret = wl1271_cmd_set_ap_key(wl, action,
2081 id, key_type, key_size,
2082 key, hlid, tx_seq_32,
2083 tx_seq_16);
2084 }
2085
2086 if (ret < 0)
2087 return ret;
2088 } else {
2089 const u8 *addr;
2090 static const u8 bcast_addr[ETH_ALEN] = {
2091 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2092 };
2093
2094 addr = sta ? sta->addr : bcast_addr;
2095
2096 if (is_zero_ether_addr(addr)) {
2097 /* We dont support TX only encryption */
2098 return -EOPNOTSUPP;
2099 }
2100
2101 /* The wl1271 does not allow to remove unicast keys - they
2102 will be cleared automatically on next CMD_JOIN. Ignore the
2103 request silently, as we dont want the mac80211 to emit
2104 an error message. */
2105 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2106 return 0;
2107
2108 ret = wl1271_cmd_set_sta_key(wl, action,
2109 id, key_type, key_size,
2110 key, addr, tx_seq_32,
2111 tx_seq_16);
2112 if (ret < 0)
2113 return ret;
2114
2115 /* the default WEP key needs to be configured at least once */
2116 if (key_type == KEY_WEP) {
2117 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2118 wl->default_key);
2119 if (ret < 0)
2120 return ret;
2121 }
2122 }
2123
2124 return 0;
2125}
2126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2128 struct ieee80211_vif *vif,
2129 struct ieee80211_sta *sta,
2130 struct ieee80211_key_conf *key_conf)
2131{
2132 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002134 u32 tx_seq_32 = 0;
2135 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002136 u8 key_type;
2137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2139
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002140 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002142 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 key_conf->keylen, key_conf->flags);
2144 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2145
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146 mutex_lock(&wl->mutex);
2147
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002148 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2149 ret = -EAGAIN;
2150 goto out_unlock;
2151 }
2152
Ido Yariva6208652011-03-01 15:14:41 +02002153 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154 if (ret < 0)
2155 goto out_unlock;
2156
Johannes Berg97359d12010-08-10 09:46:38 +02002157 switch (key_conf->cipher) {
2158 case WLAN_CIPHER_SUITE_WEP40:
2159 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 key_type = KEY_WEP;
2161
2162 key_conf->hw_key_idx = key_conf->keyidx;
2163 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002164 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 key_type = KEY_TKIP;
2166
2167 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002168 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2169 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002171 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 key_type = KEY_AES;
2173
2174 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002175 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2176 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002178 case WL1271_CIPHER_SUITE_GEM:
2179 key_type = KEY_GEM;
2180 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2181 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2182 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002184 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185
2186 ret = -EOPNOTSUPP;
2187 goto out_sleep;
2188 }
2189
2190 switch (cmd) {
2191 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002192 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2193 key_conf->keyidx, key_type,
2194 key_conf->keylen, key_conf->key,
2195 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002196 if (ret < 0) {
2197 wl1271_error("Could not add or replace key");
2198 goto out_sleep;
2199 }
2200 break;
2201
2202 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002203 ret = wl1271_set_key(wl, KEY_REMOVE,
2204 key_conf->keyidx, key_type,
2205 key_conf->keylen, key_conf->key,
2206 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207 if (ret < 0) {
2208 wl1271_error("Could not remove key");
2209 goto out_sleep;
2210 }
2211 break;
2212
2213 default:
2214 wl1271_error("Unsupported key cmd 0x%x", cmd);
2215 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216 break;
2217 }
2218
2219out_sleep:
2220 wl1271_ps_elp_sleep(wl);
2221
2222out_unlock:
2223 mutex_unlock(&wl->mutex);
2224
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002225 return ret;
2226}
2227
2228static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002229 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002230 struct cfg80211_scan_request *req)
2231{
2232 struct wl1271 *wl = hw->priv;
2233 int ret;
2234 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002235 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236
2237 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2238
2239 if (req->n_ssids) {
2240 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002241 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002242 }
2243
2244 mutex_lock(&wl->mutex);
2245
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002246 if (wl->state == WL1271_STATE_OFF) {
2247 /*
2248 * We cannot return -EBUSY here because cfg80211 will expect
2249 * a call to ieee80211_scan_completed if we do - in this case
2250 * there won't be any call.
2251 */
2252 ret = -EAGAIN;
2253 goto out;
2254 }
2255
Ido Yariva6208652011-03-01 15:14:41 +02002256 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257 if (ret < 0)
2258 goto out;
2259
Luciano Coelho5924f892010-08-04 03:46:22 +03002260 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261
2262 wl1271_ps_elp_sleep(wl);
2263
2264out:
2265 mutex_unlock(&wl->mutex);
2266
2267 return ret;
2268}
2269
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002270static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2271{
2272 struct wl1271 *wl = hw->priv;
2273 int ret = 0;
2274
2275 mutex_lock(&wl->mutex);
2276
2277 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2278 ret = -EAGAIN;
2279 goto out;
2280 }
2281
Ido Yariva6208652011-03-01 15:14:41 +02002282 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002283 if (ret < 0)
2284 goto out;
2285
2286 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2287 if (ret < 0)
2288 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2289
2290 wl1271_ps_elp_sleep(wl);
2291
2292out:
2293 mutex_unlock(&wl->mutex);
2294
2295 return ret;
2296}
2297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2299{
2300 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002301 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302
2303 mutex_lock(&wl->mutex);
2304
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002305 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2306 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002307 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002308 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002309
Ido Yariva6208652011-03-01 15:14:41 +02002310 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 if (ret < 0)
2312 goto out;
2313
2314 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2315 if (ret < 0)
2316 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2317
2318 wl1271_ps_elp_sleep(wl);
2319
2320out:
2321 mutex_unlock(&wl->mutex);
2322
2323 return ret;
2324}
2325
Arik Nemtsove78a2872010-10-16 19:07:21 +02002326static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002327 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002328{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002329 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002330
2331 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002332 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002333 if (ptr[0] == WLAN_EID_SSID) {
2334 wl->ssid_len = ptr[1];
2335 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002336 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002337 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002338 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002339 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002340
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002341 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002342 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002343}
2344
Arik Nemtsove78a2872010-10-16 19:07:21 +02002345static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2346 struct ieee80211_bss_conf *bss_conf,
2347 u32 changed)
2348{
2349 int ret = 0;
2350
2351 if (changed & BSS_CHANGED_ERP_SLOT) {
2352 if (bss_conf->use_short_slot)
2353 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2354 else
2355 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2356 if (ret < 0) {
2357 wl1271_warning("Set slot time failed %d", ret);
2358 goto out;
2359 }
2360 }
2361
2362 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2363 if (bss_conf->use_short_preamble)
2364 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2365 else
2366 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2367 }
2368
2369 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2370 if (bss_conf->use_cts_prot)
2371 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2372 else
2373 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2374 if (ret < 0) {
2375 wl1271_warning("Set ctsprotect failed %d", ret);
2376 goto out;
2377 }
2378 }
2379
2380out:
2381 return ret;
2382}
2383
2384static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2385 struct ieee80211_vif *vif,
2386 struct ieee80211_bss_conf *bss_conf,
2387 u32 changed)
2388{
2389 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2390 int ret = 0;
2391
2392 if ((changed & BSS_CHANGED_BEACON_INT)) {
2393 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2394 bss_conf->beacon_int);
2395
2396 wl->beacon_int = bss_conf->beacon_int;
2397 }
2398
2399 if ((changed & BSS_CHANGED_BEACON)) {
2400 struct ieee80211_hdr *hdr;
2401 int ieoffset = offsetof(struct ieee80211_mgmt,
2402 u.beacon.variable);
2403 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2404 u16 tmpl_id;
2405
2406 if (!beacon)
2407 goto out;
2408
2409 wl1271_debug(DEBUG_MASTER, "beacon updated");
2410
2411 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2412 if (ret < 0) {
2413 dev_kfree_skb(beacon);
2414 goto out;
2415 }
2416 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2417 CMD_TEMPL_BEACON;
2418 ret = wl1271_cmd_template_set(wl, tmpl_id,
2419 beacon->data,
2420 beacon->len, 0,
2421 wl1271_tx_min_rate_get(wl));
2422 if (ret < 0) {
2423 dev_kfree_skb(beacon);
2424 goto out;
2425 }
2426
2427 hdr = (struct ieee80211_hdr *) beacon->data;
2428 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2429 IEEE80211_STYPE_PROBE_RESP);
2430
2431 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2432 CMD_TEMPL_PROBE_RESPONSE;
2433 ret = wl1271_cmd_template_set(wl,
2434 tmpl_id,
2435 beacon->data,
2436 beacon->len, 0,
2437 wl1271_tx_min_rate_get(wl));
2438 dev_kfree_skb(beacon);
2439 if (ret < 0)
2440 goto out;
2441 }
2442
2443out:
2444 return ret;
2445}
2446
2447/* AP mode changes */
2448static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449 struct ieee80211_vif *vif,
2450 struct ieee80211_bss_conf *bss_conf,
2451 u32 changed)
2452{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002453 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454
Arik Nemtsove78a2872010-10-16 19:07:21 +02002455 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2456 u32 rates = bss_conf->basic_rates;
2457 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
Arik Nemtsove78a2872010-10-16 19:07:21 +02002459 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2460 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2461 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2462 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463
Arik Nemtsove78a2872010-10-16 19:07:21 +02002464 /* update the AP management rate policy with the new rates */
2465 mgmt_rc.enabled_rates = wl->basic_rate_set;
2466 mgmt_rc.long_retry_limit = 10;
2467 mgmt_rc.short_retry_limit = 10;
2468 mgmt_rc.aflags = 0;
2469 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2470 ACX_TX_AP_MODE_MGMT_RATE);
2471 if (ret < 0) {
2472 wl1271_error("AP mgmt policy change failed %d", ret);
2473 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002474 }
2475 }
2476
Arik Nemtsove78a2872010-10-16 19:07:21 +02002477 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2478 if (ret < 0)
2479 goto out;
2480
2481 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2482 if (bss_conf->enable_beacon) {
2483 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2484 ret = wl1271_cmd_start_bss(wl);
2485 if (ret < 0)
2486 goto out;
2487
2488 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2489 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002490
2491 ret = wl1271_ap_init_hwenc(wl);
2492 if (ret < 0)
2493 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002494 }
2495 } else {
2496 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2497 ret = wl1271_cmd_stop_bss(wl);
2498 if (ret < 0)
2499 goto out;
2500
2501 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2502 wl1271_debug(DEBUG_AP, "stopped AP");
2503 }
2504 }
2505 }
2506
2507 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2508 if (ret < 0)
2509 goto out;
2510out:
2511 return;
2512}
2513
2514/* STA/IBSS mode changes */
2515static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2516 struct ieee80211_vif *vif,
2517 struct ieee80211_bss_conf *bss_conf,
2518 u32 changed)
2519{
2520 bool do_join = false, set_assoc = false;
2521 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002522 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002523 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002524 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002525 bool sta_exists = false;
2526 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002527
2528 if (is_ibss) {
2529 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2530 changed);
2531 if (ret < 0)
2532 goto out;
2533 }
2534
2535 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2536 do_join = true;
2537
2538 /* Need to update the SSID (for filtering etc) */
2539 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2540 do_join = true;
2541
2542 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002543 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2544 bss_conf->enable_beacon ? "enabled" : "disabled");
2545
2546 if (bss_conf->enable_beacon)
2547 wl->set_bss_type = BSS_TYPE_IBSS;
2548 else
2549 wl->set_bss_type = BSS_TYPE_STA_BSS;
2550 do_join = true;
2551 }
2552
Arik Nemtsove78a2872010-10-16 19:07:21 +02002553 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002554 bool enable = false;
2555 if (bss_conf->cqm_rssi_thold)
2556 enable = true;
2557 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2558 bss_conf->cqm_rssi_thold,
2559 bss_conf->cqm_rssi_hyst);
2560 if (ret < 0)
2561 goto out;
2562 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2563 }
2564
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002565 if ((changed & BSS_CHANGED_BSSID) &&
2566 /*
2567 * Now we know the correct bssid, so we send a new join command
2568 * and enable the BSSID filter
2569 */
2570 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002571 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002572
Eliad Pellerfa287b82010-12-26 09:27:50 +01002573 if (!is_zero_ether_addr(wl->bssid)) {
2574 ret = wl1271_cmd_build_null_data(wl);
2575 if (ret < 0)
2576 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002577
Eliad Pellerfa287b82010-12-26 09:27:50 +01002578 ret = wl1271_build_qos_null_data(wl);
2579 if (ret < 0)
2580 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002581
Eliad Pellerfa287b82010-12-26 09:27:50 +01002582 /* filter out all packets not from this BSSID */
2583 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002584
Eliad Pellerfa287b82010-12-26 09:27:50 +01002585 /* Need to update the BSSID (for filtering etc) */
2586 do_join = true;
2587 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002588 }
2589
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002590 rcu_read_lock();
2591 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2592 if (sta) {
2593 /* save the supp_rates of the ap */
2594 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2595 if (sta->ht_cap.ht_supported)
2596 sta_rate_set |=
2597 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002598 sta_ht_cap = sta->ht_cap;
2599 sta_exists = true;
2600 }
2601 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002602
Arik Nemtsova1008852011-02-12 23:24:20 +02002603 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002604 /* handle new association with HT and HT information change */
2605 if ((changed & BSS_CHANGED_HT) &&
2606 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002607 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002608 true);
2609 if (ret < 0) {
2610 wl1271_warning("Set ht cap true failed %d",
2611 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002612 goto out;
2613 }
2614 ret = wl1271_acx_set_ht_information(wl,
2615 bss_conf->ht_operation_mode);
2616 if (ret < 0) {
2617 wl1271_warning("Set ht information failed %d",
2618 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002619 goto out;
2620 }
2621 }
2622 /* handle new association without HT and disassociation */
2623 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002624 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002625 false);
2626 if (ret < 0) {
2627 wl1271_warning("Set ht cap false failed %d",
2628 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002629 goto out;
2630 }
2631 }
2632 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002633
Arik Nemtsove78a2872010-10-16 19:07:21 +02002634 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002635 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002636 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002637 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002638 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002639 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002641 wl->ps_poll_failures = 0;
2642
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002643 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002644 * use basic rates from AP, and determine lowest rate
2645 * to use with control frames.
2646 */
2647 rates = bss_conf->basic_rates;
2648 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2649 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002650 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002651 if (sta_rate_set)
2652 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2653 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002654 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002655 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002656 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002657
2658 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002659 * with wl1271, we don't need to update the
2660 * beacon_int and dtim_period, because the firmware
2661 * updates it by itself when the first beacon is
2662 * received after a join.
2663 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002664 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2665 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002668 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002669 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002670 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002671 dev_kfree_skb(wl->probereq);
2672 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2673 ieoffset = offsetof(struct ieee80211_mgmt,
2674 u.probe_req.variable);
2675 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002676
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002677 /* enable the connection monitoring feature */
2678 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002680 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681
2682 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002683 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2684 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002685 enum wl1271_cmd_ps_mode mode;
2686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002688 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002689 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002690 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002691 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002692 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002694 } else {
2695 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002696 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002697 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002698 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002699
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002700 /* free probe-request template */
2701 dev_kfree_skb(wl->probereq);
2702 wl->probereq = NULL;
2703
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002704 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002705 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002706
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002707 /* revert back to minimum rates for the current band */
2708 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002709 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002710 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002711 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002712 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002713
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002714 /* disable connection monitor features */
2715 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002716
2717 /* Disable the keep-alive feature */
2718 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002719 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002720 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002721
2722 /* restore the bssid filter and go to dummy bssid */
2723 wl1271_unjoin(wl);
2724 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002725 }
2726 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002727
Arik Nemtsove78a2872010-10-16 19:07:21 +02002728 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2729 if (ret < 0)
2730 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002732 if (changed & BSS_CHANGED_ARP_FILTER) {
2733 __be32 addr = bss_conf->arp_addr_list[0];
2734 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2735
Eliad Pellerc5312772010-12-09 11:31:27 +02002736 if (bss_conf->arp_addr_cnt == 1 &&
2737 bss_conf->arp_filter_enabled) {
2738 /*
2739 * The template should have been configured only upon
2740 * association. however, it seems that the correct ip
2741 * isn't being set (when sending), so we have to
2742 * reconfigure the template upon every ip change.
2743 */
2744 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2745 if (ret < 0) {
2746 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002747 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002748 }
2749
2750 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002751 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002752 addr);
2753 } else
2754 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002755
2756 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002757 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002758 }
2759
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002760 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002761 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002762 if (ret < 0) {
2763 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002764 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002765 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002766 }
2767
Arik Nemtsove78a2872010-10-16 19:07:21 +02002768out:
2769 return;
2770}
2771
2772static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2773 struct ieee80211_vif *vif,
2774 struct ieee80211_bss_conf *bss_conf,
2775 u32 changed)
2776{
2777 struct wl1271 *wl = hw->priv;
2778 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2779 int ret;
2780
2781 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2782 (int)changed);
2783
2784 mutex_lock(&wl->mutex);
2785
2786 if (unlikely(wl->state == WL1271_STATE_OFF))
2787 goto out;
2788
Ido Yariva6208652011-03-01 15:14:41 +02002789 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002790 if (ret < 0)
2791 goto out;
2792
2793 if (is_ap)
2794 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2795 else
2796 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2797
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 wl1271_ps_elp_sleep(wl);
2799
2800out:
2801 mutex_unlock(&wl->mutex);
2802}
2803
Kalle Valoc6999d82010-02-18 13:25:41 +02002804static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2805 const struct ieee80211_tx_queue_params *params)
2806{
2807 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002808 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002809 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002810
2811 mutex_lock(&wl->mutex);
2812
2813 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2814
Kalle Valo4695dc92010-03-18 12:26:38 +02002815 if (params->uapsd)
2816 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2817 else
2818 ps_scheme = CONF_PS_SCHEME_LEGACY;
2819
Arik Nemtsov488fc542010-10-16 20:33:45 +02002820 if (wl->state == WL1271_STATE_OFF) {
2821 /*
2822 * If the state is off, the parameters will be recorded and
2823 * configured on init. This happens in AP-mode.
2824 */
2825 struct conf_tx_ac_category *conf_ac =
2826 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2827 struct conf_tx_tid *conf_tid =
2828 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2829
2830 conf_ac->ac = wl1271_tx_get_queue(queue);
2831 conf_ac->cw_min = (u8)params->cw_min;
2832 conf_ac->cw_max = params->cw_max;
2833 conf_ac->aifsn = params->aifs;
2834 conf_ac->tx_op_limit = params->txop << 5;
2835
2836 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2837 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2838 conf_tid->tsid = wl1271_tx_get_queue(queue);
2839 conf_tid->ps_scheme = ps_scheme;
2840 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2841 conf_tid->apsd_conf[0] = 0;
2842 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002843 goto out;
2844 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002845
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002846 ret = wl1271_ps_elp_wakeup(wl);
2847 if (ret < 0)
2848 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002849
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002850 /*
2851 * the txop is confed in units of 32us by the mac80211,
2852 * we need us
2853 */
2854 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2855 params->cw_min, params->cw_max,
2856 params->aifs, params->txop << 5);
2857 if (ret < 0)
2858 goto out_sleep;
2859
2860 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2861 CONF_CHANNEL_TYPE_EDCF,
2862 wl1271_tx_get_queue(queue),
2863 ps_scheme, CONF_ACK_POLICY_LEGACY,
2864 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002865
2866out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002867 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002868
2869out:
2870 mutex_unlock(&wl->mutex);
2871
2872 return ret;
2873}
2874
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002875static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2876{
2877
2878 struct wl1271 *wl = hw->priv;
2879 u64 mactime = ULLONG_MAX;
2880 int ret;
2881
2882 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2883
2884 mutex_lock(&wl->mutex);
2885
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002886 if (unlikely(wl->state == WL1271_STATE_OFF))
2887 goto out;
2888
Ido Yariva6208652011-03-01 15:14:41 +02002889 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002890 if (ret < 0)
2891 goto out;
2892
2893 ret = wl1271_acx_tsf_info(wl, &mactime);
2894 if (ret < 0)
2895 goto out_sleep;
2896
2897out_sleep:
2898 wl1271_ps_elp_sleep(wl);
2899
2900out:
2901 mutex_unlock(&wl->mutex);
2902 return mactime;
2903}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904
John W. Linvilleece550d2010-07-28 16:41:06 -04002905static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2906 struct survey_info *survey)
2907{
2908 struct wl1271 *wl = hw->priv;
2909 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002910
John W. Linvilleece550d2010-07-28 16:41:06 -04002911 if (idx != 0)
2912 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002913
John W. Linvilleece550d2010-07-28 16:41:06 -04002914 survey->channel = conf->channel;
2915 survey->filled = SURVEY_INFO_NOISE_DBM;
2916 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002917
John W. Linvilleece550d2010-07-28 16:41:06 -04002918 return 0;
2919}
2920
Arik Nemtsov409622e2011-02-23 00:22:29 +02002921static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002922 struct ieee80211_sta *sta,
2923 u8 *hlid)
2924{
2925 struct wl1271_station *wl_sta;
2926 int id;
2927
2928 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2929 if (id >= AP_MAX_STATIONS) {
2930 wl1271_warning("could not allocate HLID - too much stations");
2931 return -EBUSY;
2932 }
2933
2934 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002935 __set_bit(id, wl->ap_hlid_map);
2936 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2937 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002938 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002939 return 0;
2940}
2941
Arik Nemtsov409622e2011-02-23 00:22:29 +02002942static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002943{
2944 int id = hlid - WL1271_AP_STA_HLID_START;
2945
Arik Nemtsov409622e2011-02-23 00:22:29 +02002946 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2947 return;
2948
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002949 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002950 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002951 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002952 __clear_bit(hlid, &wl->ap_ps_map);
2953 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002954}
2955
2956static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2957 struct ieee80211_vif *vif,
2958 struct ieee80211_sta *sta)
2959{
2960 struct wl1271 *wl = hw->priv;
2961 int ret = 0;
2962 u8 hlid;
2963
2964 mutex_lock(&wl->mutex);
2965
2966 if (unlikely(wl->state == WL1271_STATE_OFF))
2967 goto out;
2968
2969 if (wl->bss_type != BSS_TYPE_AP_BSS)
2970 goto out;
2971
2972 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2973
Arik Nemtsov409622e2011-02-23 00:22:29 +02002974 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002975 if (ret < 0)
2976 goto out;
2977
Ido Yariva6208652011-03-01 15:14:41 +02002978 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002979 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002980 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002981
2982 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2983 if (ret < 0)
2984 goto out_sleep;
2985
2986out_sleep:
2987 wl1271_ps_elp_sleep(wl);
2988
Arik Nemtsov409622e2011-02-23 00:22:29 +02002989out_free_sta:
2990 if (ret < 0)
2991 wl1271_free_sta(wl, hlid);
2992
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002993out:
2994 mutex_unlock(&wl->mutex);
2995 return ret;
2996}
2997
2998static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2999 struct ieee80211_vif *vif,
3000 struct ieee80211_sta *sta)
3001{
3002 struct wl1271 *wl = hw->priv;
3003 struct wl1271_station *wl_sta;
3004 int ret = 0, id;
3005
3006 mutex_lock(&wl->mutex);
3007
3008 if (unlikely(wl->state == WL1271_STATE_OFF))
3009 goto out;
3010
3011 if (wl->bss_type != BSS_TYPE_AP_BSS)
3012 goto out;
3013
3014 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3015
3016 wl_sta = (struct wl1271_station *)sta->drv_priv;
3017 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3018 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3019 goto out;
3020
Ido Yariva6208652011-03-01 15:14:41 +02003021 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003022 if (ret < 0)
3023 goto out;
3024
3025 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3026 if (ret < 0)
3027 goto out_sleep;
3028
Arik Nemtsov409622e2011-02-23 00:22:29 +02003029 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003030
3031out_sleep:
3032 wl1271_ps_elp_sleep(wl);
3033
3034out:
3035 mutex_unlock(&wl->mutex);
3036 return ret;
3037}
3038
Luciano Coelho4623ec72011-03-21 19:26:41 +02003039static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3040 struct ieee80211_vif *vif,
3041 enum ieee80211_ampdu_mlme_action action,
3042 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3043 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003044{
3045 struct wl1271 *wl = hw->priv;
3046 int ret;
3047
3048 mutex_lock(&wl->mutex);
3049
3050 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3051 ret = -EAGAIN;
3052 goto out;
3053 }
3054
Ido Yariva6208652011-03-01 15:14:41 +02003055 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003056 if (ret < 0)
3057 goto out;
3058
3059 switch (action) {
3060 case IEEE80211_AMPDU_RX_START:
3061 if (wl->ba_support) {
3062 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3063 true);
3064 if (!ret)
3065 wl->ba_rx_bitmap |= BIT(tid);
3066 } else {
3067 ret = -ENOTSUPP;
3068 }
3069 break;
3070
3071 case IEEE80211_AMPDU_RX_STOP:
3072 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3073 if (!ret)
3074 wl->ba_rx_bitmap &= ~BIT(tid);
3075 break;
3076
3077 /*
3078 * The BA initiator session management in FW independently.
3079 * Falling break here on purpose for all TX APDU commands.
3080 */
3081 case IEEE80211_AMPDU_TX_START:
3082 case IEEE80211_AMPDU_TX_STOP:
3083 case IEEE80211_AMPDU_TX_OPERATIONAL:
3084 ret = -EINVAL;
3085 break;
3086
3087 default:
3088 wl1271_error("Incorrect ampdu action id=%x\n", action);
3089 ret = -EINVAL;
3090 }
3091
3092 wl1271_ps_elp_sleep(wl);
3093
3094out:
3095 mutex_unlock(&wl->mutex);
3096
3097 return ret;
3098}
3099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003100/* can't be const, mac80211 writes to this */
3101static struct ieee80211_rate wl1271_rates[] = {
3102 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003103 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3104 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003105 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003106 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3107 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003108 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3109 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003110 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3111 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3113 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003114 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3115 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003116 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3117 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003118 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3119 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003120 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003121 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3122 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003124 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3125 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003126 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003127 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3128 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003129 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003130 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3131 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003132 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003133 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3134 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003135 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003136 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3137 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003138 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003139 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003141};
3142
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003143/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003144static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003145 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003146 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003147 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3148 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3149 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003150 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003151 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3152 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3153 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003154 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003155 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3156 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3157 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003158 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159};
3160
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003161/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003162static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003163 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003164 7, /* CONF_HW_RXTX_RATE_MCS7 */
3165 6, /* CONF_HW_RXTX_RATE_MCS6 */
3166 5, /* CONF_HW_RXTX_RATE_MCS5 */
3167 4, /* CONF_HW_RXTX_RATE_MCS4 */
3168 3, /* CONF_HW_RXTX_RATE_MCS3 */
3169 2, /* CONF_HW_RXTX_RATE_MCS2 */
3170 1, /* CONF_HW_RXTX_RATE_MCS1 */
3171 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003172
3173 11, /* CONF_HW_RXTX_RATE_54 */
3174 10, /* CONF_HW_RXTX_RATE_48 */
3175 9, /* CONF_HW_RXTX_RATE_36 */
3176 8, /* CONF_HW_RXTX_RATE_24 */
3177
3178 /* TI-specific rate */
3179 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3180
3181 7, /* CONF_HW_RXTX_RATE_18 */
3182 6, /* CONF_HW_RXTX_RATE_12 */
3183 3, /* CONF_HW_RXTX_RATE_11 */
3184 5, /* CONF_HW_RXTX_RATE_9 */
3185 4, /* CONF_HW_RXTX_RATE_6 */
3186 2, /* CONF_HW_RXTX_RATE_5_5 */
3187 1, /* CONF_HW_RXTX_RATE_2 */
3188 0 /* CONF_HW_RXTX_RATE_1 */
3189};
3190
Shahar Levie8b03a22010-10-13 16:09:39 +02003191/* 11n STA capabilities */
3192#define HW_RX_HIGHEST_RATE 72
3193
Shahar Levi00d20102010-11-08 11:20:10 +00003194#ifdef CONFIG_WL12XX_HT
3195#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003196 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3197 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003198 .ht_supported = true, \
3199 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3200 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3201 .mcs = { \
3202 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3203 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3204 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3205 }, \
3206}
Shahar Levi18357852010-10-13 16:09:41 +02003207#else
Shahar Levi00d20102010-11-08 11:20:10 +00003208#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003209 .ht_supported = false, \
3210}
3211#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003212
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213/* can't be const, mac80211 writes to this */
3214static struct ieee80211_supported_band wl1271_band_2ghz = {
3215 .channels = wl1271_channels,
3216 .n_channels = ARRAY_SIZE(wl1271_channels),
3217 .bitrates = wl1271_rates,
3218 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003219 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220};
3221
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003222/* 5 GHz data rates for WL1273 */
3223static struct ieee80211_rate wl1271_rates_5ghz[] = {
3224 { .bitrate = 60,
3225 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3226 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3227 { .bitrate = 90,
3228 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3229 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3230 { .bitrate = 120,
3231 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3232 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3233 { .bitrate = 180,
3234 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3235 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3236 { .bitrate = 240,
3237 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3238 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3239 { .bitrate = 360,
3240 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3241 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3242 { .bitrate = 480,
3243 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3244 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3245 { .bitrate = 540,
3246 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3247 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3248};
3249
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003250/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003251static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003252 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003253 { .hw_value = 8, .center_freq = 5040},
3254 { .hw_value = 9, .center_freq = 5045},
3255 { .hw_value = 11, .center_freq = 5055},
3256 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003257 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003258 { .hw_value = 34, .center_freq = 5170},
3259 { .hw_value = 36, .center_freq = 5180},
3260 { .hw_value = 38, .center_freq = 5190},
3261 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003262 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003263 { .hw_value = 44, .center_freq = 5220},
3264 { .hw_value = 46, .center_freq = 5230},
3265 { .hw_value = 48, .center_freq = 5240},
3266 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003267 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003268 { .hw_value = 60, .center_freq = 5300},
3269 { .hw_value = 64, .center_freq = 5320},
3270 { .hw_value = 100, .center_freq = 5500},
3271 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003272 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003273 { .hw_value = 112, .center_freq = 5560},
3274 { .hw_value = 116, .center_freq = 5580},
3275 { .hw_value = 120, .center_freq = 5600},
3276 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003277 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003278 { .hw_value = 132, .center_freq = 5660},
3279 { .hw_value = 136, .center_freq = 5680},
3280 { .hw_value = 140, .center_freq = 5700},
3281 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003282 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003283 { .hw_value = 157, .center_freq = 5785},
3284 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003285 { .hw_value = 165, .center_freq = 5825},
3286};
3287
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003288/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003289static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003290 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003291 7, /* CONF_HW_RXTX_RATE_MCS7 */
3292 6, /* CONF_HW_RXTX_RATE_MCS6 */
3293 5, /* CONF_HW_RXTX_RATE_MCS5 */
3294 4, /* CONF_HW_RXTX_RATE_MCS4 */
3295 3, /* CONF_HW_RXTX_RATE_MCS3 */
3296 2, /* CONF_HW_RXTX_RATE_MCS2 */
3297 1, /* CONF_HW_RXTX_RATE_MCS1 */
3298 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003299
3300 7, /* CONF_HW_RXTX_RATE_54 */
3301 6, /* CONF_HW_RXTX_RATE_48 */
3302 5, /* CONF_HW_RXTX_RATE_36 */
3303 4, /* CONF_HW_RXTX_RATE_24 */
3304
3305 /* TI-specific rate */
3306 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3307
3308 3, /* CONF_HW_RXTX_RATE_18 */
3309 2, /* CONF_HW_RXTX_RATE_12 */
3310 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3311 1, /* CONF_HW_RXTX_RATE_9 */
3312 0, /* CONF_HW_RXTX_RATE_6 */
3313 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3314 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3315 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3316};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003317
3318static struct ieee80211_supported_band wl1271_band_5ghz = {
3319 .channels = wl1271_channels_5ghz,
3320 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3321 .bitrates = wl1271_rates_5ghz,
3322 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003323 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003324};
3325
Tobias Klausera0ea9492010-05-20 10:38:11 +02003326static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003327 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3328 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3329};
3330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331static const struct ieee80211_ops wl1271_ops = {
3332 .start = wl1271_op_start,
3333 .stop = wl1271_op_stop,
3334 .add_interface = wl1271_op_add_interface,
3335 .remove_interface = wl1271_op_remove_interface,
3336 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003337 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003338 .configure_filter = wl1271_op_configure_filter,
3339 .tx = wl1271_op_tx,
3340 .set_key = wl1271_op_set_key,
3341 .hw_scan = wl1271_op_hw_scan,
3342 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003343 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003344 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003345 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003346 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003347 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003348 .sta_add = wl1271_op_sta_add,
3349 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003350 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003351 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003352};
3353
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003354
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003355u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003356{
3357 u8 idx;
3358
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003359 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003360
3361 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3362 wl1271_error("Illegal RX rate from HW: %d", rate);
3363 return 0;
3364 }
3365
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003366 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003367 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3368 wl1271_error("Unsupported RX rate from HW: %d", rate);
3369 return 0;
3370 }
3371
3372 return idx;
3373}
3374
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003375static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3376 struct device_attribute *attr,
3377 char *buf)
3378{
3379 struct wl1271 *wl = dev_get_drvdata(dev);
3380 ssize_t len;
3381
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003382 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003383
3384 mutex_lock(&wl->mutex);
3385 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3386 wl->sg_enabled);
3387 mutex_unlock(&wl->mutex);
3388
3389 return len;
3390
3391}
3392
3393static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3394 struct device_attribute *attr,
3395 const char *buf, size_t count)
3396{
3397 struct wl1271 *wl = dev_get_drvdata(dev);
3398 unsigned long res;
3399 int ret;
3400
Luciano Coelho6277ed62011-04-01 17:49:54 +03003401 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003402 if (ret < 0) {
3403 wl1271_warning("incorrect value written to bt_coex_mode");
3404 return count;
3405 }
3406
3407 mutex_lock(&wl->mutex);
3408
3409 res = !!res;
3410
3411 if (res == wl->sg_enabled)
3412 goto out;
3413
3414 wl->sg_enabled = res;
3415
3416 if (wl->state == WL1271_STATE_OFF)
3417 goto out;
3418
Ido Yariva6208652011-03-01 15:14:41 +02003419 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003420 if (ret < 0)
3421 goto out;
3422
3423 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3424 wl1271_ps_elp_sleep(wl);
3425
3426 out:
3427 mutex_unlock(&wl->mutex);
3428 return count;
3429}
3430
3431static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3432 wl1271_sysfs_show_bt_coex_state,
3433 wl1271_sysfs_store_bt_coex_state);
3434
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003435static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3436 struct device_attribute *attr,
3437 char *buf)
3438{
3439 struct wl1271 *wl = dev_get_drvdata(dev);
3440 ssize_t len;
3441
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003442 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003443
3444 mutex_lock(&wl->mutex);
3445 if (wl->hw_pg_ver >= 0)
3446 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3447 else
3448 len = snprintf(buf, len, "n/a\n");
3449 mutex_unlock(&wl->mutex);
3450
3451 return len;
3452}
3453
3454static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3455 wl1271_sysfs_show_hw_pg_ver, NULL);
3456
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003457int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003458{
3459 int ret;
3460
3461 if (wl->mac80211_registered)
3462 return 0;
3463
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003464 ret = wl1271_fetch_nvs(wl);
3465 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003466 /* NOTE: The wl->nvs->nvs element must be first, in
3467 * order to simplify the casting, we assume it is at
3468 * the beginning of the wl->nvs structure.
3469 */
3470 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003471
3472 wl->mac_addr[0] = nvs_ptr[11];
3473 wl->mac_addr[1] = nvs_ptr[10];
3474 wl->mac_addr[2] = nvs_ptr[6];
3475 wl->mac_addr[3] = nvs_ptr[5];
3476 wl->mac_addr[4] = nvs_ptr[4];
3477 wl->mac_addr[5] = nvs_ptr[3];
3478 }
3479
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003480 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3481
3482 ret = ieee80211_register_hw(wl->hw);
3483 if (ret < 0) {
3484 wl1271_error("unable to register mac80211 hw: %d", ret);
3485 return ret;
3486 }
3487
3488 wl->mac80211_registered = true;
3489
Eliad Pellerd60080a2010-11-24 12:53:16 +02003490 wl1271_debugfs_init(wl);
3491
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003492 register_netdevice_notifier(&wl1271_dev_notifier);
3493
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003494 wl1271_notice("loaded");
3495
3496 return 0;
3497}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003498EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003500void wl1271_unregister_hw(struct wl1271 *wl)
3501{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003502 if (wl->state == WL1271_STATE_PLT)
3503 __wl1271_plt_stop(wl);
3504
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003505 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003506 ieee80211_unregister_hw(wl->hw);
3507 wl->mac80211_registered = false;
3508
3509}
3510EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3511
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003512int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003513{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003514 static const u32 cipher_suites[] = {
3515 WLAN_CIPHER_SUITE_WEP40,
3516 WLAN_CIPHER_SUITE_WEP104,
3517 WLAN_CIPHER_SUITE_TKIP,
3518 WLAN_CIPHER_SUITE_CCMP,
3519 WL1271_CIPHER_SUITE_GEM,
3520 };
3521
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003522 /* The tx descriptor buffer and the TKIP space. */
3523 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3524 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003525
3526 /* unit us */
3527 /* FIXME: find a proper value */
3528 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003529 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530
3531 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003532 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003533 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003534 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003535 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003536 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003537 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003538 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3539 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003541 wl->hw->wiphy->cipher_suites = cipher_suites;
3542 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3543
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003544 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003545 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003546 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003547 /*
3548 * Maximum length of elements in scanning probe request templates
3549 * should be the maximum length possible for a template, without
3550 * the IEEE80211 header of the template
3551 */
3552 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3553 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003554
Luciano Coelho4a31c112011-03-21 23:16:14 +02003555 /* make sure all our channels fit in the scanned_ch bitmask */
3556 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3557 ARRAY_SIZE(wl1271_channels_5ghz) >
3558 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003559 /*
3560 * We keep local copies of the band structs because we need to
3561 * modify them on a per-device basis.
3562 */
3563 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3564 sizeof(wl1271_band_2ghz));
3565 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3566 sizeof(wl1271_band_5ghz));
3567
3568 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3569 &wl->bands[IEEE80211_BAND_2GHZ];
3570 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3571 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003572
Kalle Valo12bd8942010-03-18 12:26:33 +02003573 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003574 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003575
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003576 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3577
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003578 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003579
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003580 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3581
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003582 wl->hw->max_rx_aggregation_subframes = 8;
3583
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003584 return 0;
3585}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003586EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003588#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003589
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003590struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003591{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003593 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003594 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003595 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003596 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597
3598 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3599 if (!hw) {
3600 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003601 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003602 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003603 }
3604
Julia Lawall929ebd32010-05-15 23:16:39 +02003605 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003606 if (!plat_dev) {
3607 wl1271_error("could not allocate platform_device");
3608 ret = -ENOMEM;
3609 goto err_plat_alloc;
3610 }
3611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003612 wl = hw->priv;
3613 memset(wl, 0, sizeof(*wl));
3614
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003615 INIT_LIST_HEAD(&wl->list);
3616
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003617 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003618 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003619
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003620 for (i = 0; i < NUM_TX_QUEUES; i++)
3621 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003622
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003623 for (i = 0; i < NUM_TX_QUEUES; i++)
3624 for (j = 0; j < AP_MAX_LINKS; j++)
3625 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3626
Ido Yariva6208652011-03-01 15:14:41 +02003627 skb_queue_head_init(&wl->deferred_rx_queue);
3628 skb_queue_head_init(&wl->deferred_tx_queue);
3629
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003630 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003631 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003632 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003633 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3634 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3635 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003636 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003637 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003638 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003639 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003640 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3641 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003642 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003643 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003644 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003645 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003646 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003647 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003648 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003649 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003650 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003651 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003652 wl->bss_type = MAX_BSS_TYPE;
3653 wl->set_bss_type = MAX_BSS_TYPE;
3654 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003655 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003656 wl->ap_ps_map = 0;
3657 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003658 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003659 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003660
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003661 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003662 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003663 wl->tx_frames[i] = NULL;
3664
3665 spin_lock_init(&wl->wl_lock);
3666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667 wl->state = WL1271_STATE_OFF;
3668 mutex_init(&wl->mutex);
3669
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003670 /* Apply default driver configuration. */
3671 wl1271_conf_init(wl);
3672
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003673 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3674 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3675 if (!wl->aggr_buf) {
3676 ret = -ENOMEM;
3677 goto err_hw;
3678 }
3679
Ido Yariv990f5de2011-03-31 10:06:59 +02003680 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3681 if (!wl->dummy_packet) {
3682 ret = -ENOMEM;
3683 goto err_aggr;
3684 }
3685
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003686 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003687 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003688 if (ret) {
3689 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003690 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003691 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003692 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003693
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003694 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003695 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003696 if (ret < 0) {
3697 wl1271_error("failed to create sysfs file bt_coex_state");
3698 goto err_platform;
3699 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003700
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003701 /* Create sysfs file to get HW PG version */
3702 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3703 if (ret < 0) {
3704 wl1271_error("failed to create sysfs file hw_pg_ver");
3705 goto err_bt_coex_state;
3706 }
3707
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003708 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003709
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003710err_bt_coex_state:
3711 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3712
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003713err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003714 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003715
Ido Yariv990f5de2011-03-31 10:06:59 +02003716err_dummy_packet:
3717 dev_kfree_skb(wl->dummy_packet);
3718
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003719err_aggr:
3720 free_pages((unsigned long)wl->aggr_buf, order);
3721
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003722err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003723 wl1271_debugfs_exit(wl);
3724 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003725
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003726err_plat_alloc:
3727 ieee80211_free_hw(hw);
3728
3729err_hw_alloc:
3730
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003731 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003732}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003733EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003734
3735int wl1271_free_hw(struct wl1271 *wl)
3736{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003737 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003738 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003739 free_pages((unsigned long)wl->aggr_buf,
3740 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003741 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003742
3743 wl1271_debugfs_exit(wl);
3744
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003745 vfree(wl->fw);
3746 wl->fw = NULL;
3747 kfree(wl->nvs);
3748 wl->nvs = NULL;
3749
3750 kfree(wl->fw_status);
3751 kfree(wl->tx_res_if);
3752
3753 ieee80211_free_hw(wl->hw);
3754
3755 return 0;
3756}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003757EXPORT_SYMBOL_GPL(wl1271_free_hw);
3758
Guy Eilam491bbd62011-01-12 10:33:29 +01003759u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003760EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003761module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003762MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3763
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003764MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003765MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003766MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");