blob: 7126506611c11b3db0adea7fa0661e0ff4d38351 [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-Cohen958b20e02011-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 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300322};
323
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200324static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200325static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200326
327
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200328static void wl1271_device_release(struct device *dev)
329{
330
331}
332
333static struct platform_device wl1271_device = {
334 .name = "wl1271",
335 .id = -1,
336
337 /* device model insists to have a release function */
338 .dev = {
339 .release = wl1271_device_release,
340 },
341};
342
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200343static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300344static LIST_HEAD(wl_list);
345
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300346static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
347 void *arg)
348{
349 struct net_device *dev = arg;
350 struct wireless_dev *wdev;
351 struct wiphy *wiphy;
352 struct ieee80211_hw *hw;
353 struct wl1271 *wl;
354 struct wl1271 *wl_temp;
355 int ret = 0;
356
357 /* Check that this notification is for us. */
358 if (what != NETDEV_CHANGE)
359 return NOTIFY_DONE;
360
361 wdev = dev->ieee80211_ptr;
362 if (wdev == NULL)
363 return NOTIFY_DONE;
364
365 wiphy = wdev->wiphy;
366 if (wiphy == NULL)
367 return NOTIFY_DONE;
368
369 hw = wiphy_priv(wiphy);
370 if (hw == NULL)
371 return NOTIFY_DONE;
372
373 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200374 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300375 list_for_each_entry(wl, &wl_list, list) {
376 if (wl == wl_temp)
377 break;
378 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200379 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300380 if (wl != wl_temp)
381 return NOTIFY_DONE;
382
383 mutex_lock(&wl->mutex);
384
385 if (wl->state == WL1271_STATE_OFF)
386 goto out;
387
388 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
389 goto out;
390
Ido Yariva6208652011-03-01 15:14:41 +0200391 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300392 if (ret < 0)
393 goto out;
394
395 if ((dev->operstate == IF_OPER_UP) &&
396 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
397 wl1271_cmd_set_sta_state(wl);
398 wl1271_info("Association completed.");
399 }
400
401 wl1271_ps_elp_sleep(wl);
402
403out:
404 mutex_unlock(&wl->mutex);
405
406 return NOTIFY_OK;
407}
408
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100409static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200410 struct regulatory_request *request)
411{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100412 struct ieee80211_supported_band *band;
413 struct ieee80211_channel *ch;
414 int i;
415
416 band = wiphy->bands[IEEE80211_BAND_5GHZ];
417 for (i = 0; i < band->n_channels; i++) {
418 ch = &band->channels[i];
419 if (ch->flags & IEEE80211_CHAN_DISABLED)
420 continue;
421
422 if (ch->flags & IEEE80211_CHAN_RADAR)
423 ch->flags |= IEEE80211_CHAN_NO_IBSS |
424 IEEE80211_CHAN_PASSIVE_SCAN;
425
426 }
427
428 return 0;
429}
430
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300431static void wl1271_conf_init(struct wl1271 *wl)
432{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300433
434 /*
435 * This function applies the default configuration to the driver. This
436 * function is invoked upon driver load (spi probe.)
437 *
438 * The configuration is stored in a run-time structure in order to
439 * facilitate for run-time adjustment of any of the parameters. Making
440 * changes to the configuration structure will apply the new values on
441 * the next interface up (wl1271_op_start.)
442 */
443
444 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300445 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300446}
447
448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449static int wl1271_plt_init(struct wl1271 *wl)
450{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200451 struct conf_tx_ac_category *conf_ac;
452 struct conf_tx_tid *conf_tid;
453 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454
Shahar Levi49d750ca2011-03-06 16:32:09 +0200455 if (wl->chip.id == CHIP_ID_1283_PG20)
456 ret = wl128x_cmd_general_parms(wl);
457 else
458 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200459 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200460 return ret;
461
Shahar Levi49d750ca2011-03-06 16:32:09 +0200462 if (wl->chip.id == CHIP_ID_1283_PG20)
463 ret = wl128x_cmd_radio_parms(wl);
464 else
465 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200466 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200467 return ret;
468
Shahar Levi49d750ca2011-03-06 16:32:09 +0200469 if (wl->chip.id != CHIP_ID_1283_PG20) {
470 ret = wl1271_cmd_ext_radio_parms(wl);
471 if (ret < 0)
472 return ret;
473 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200474 if (ret < 0)
475 return ret;
476
Shahar Levi48a61472011-03-06 16:32:08 +0200477 /* Chip-specific initializations */
478 ret = wl1271_chip_specific_init(wl);
479 if (ret < 0)
480 return ret;
481
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200482 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200483 if (ret < 0)
484 return ret;
485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486 ret = wl1271_acx_init_mem_config(wl);
487 if (ret < 0)
488 return ret;
489
Luciano Coelho12419cc2010-02-18 13:25:44 +0200490 /* PHY layer config */
491 ret = wl1271_init_phy_config(wl);
492 if (ret < 0)
493 goto out_free_memmap;
494
495 ret = wl1271_acx_dco_itrim_params(wl);
496 if (ret < 0)
497 goto out_free_memmap;
498
499 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200500 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200501 if (ret < 0)
502 goto out_free_memmap;
503
504 /* Bluetooth WLAN coexistence */
505 ret = wl1271_init_pta(wl);
506 if (ret < 0)
507 goto out_free_memmap;
508
509 /* Energy detection */
510 ret = wl1271_init_energy_detection(wl);
511 if (ret < 0)
512 goto out_free_memmap;
513
Gery Kahn1ec610e2011-02-01 03:03:08 -0600514 ret = wl1271_acx_sta_mem_cfg(wl);
515 if (ret < 0)
516 goto out_free_memmap;
517
Luciano Coelho12419cc2010-02-18 13:25:44 +0200518 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100519 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200520 if (ret < 0)
521 goto out_free_memmap;
522
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200523 /* Default TID/AC configuration */
524 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200525 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200526 conf_ac = &wl->conf.tx.ac_conf[i];
527 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
528 conf_ac->cw_max, conf_ac->aifsn,
529 conf_ac->tx_op_limit);
530 if (ret < 0)
531 goto out_free_memmap;
532
Luciano Coelho12419cc2010-02-18 13:25:44 +0200533 conf_tid = &wl->conf.tx.tid_conf[i];
534 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
535 conf_tid->channel_type,
536 conf_tid->tsid,
537 conf_tid->ps_scheme,
538 conf_tid->ack_policy,
539 conf_tid->apsd_conf[0],
540 conf_tid->apsd_conf[1]);
541 if (ret < 0)
542 goto out_free_memmap;
543 }
544
Luciano Coelho12419cc2010-02-18 13:25:44 +0200545 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200546 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300547 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200548 goto out_free_memmap;
549
550 /* Configure for CAM power saving (ie. always active) */
551 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
552 if (ret < 0)
553 goto out_free_memmap;
554
555 /* configure PM */
556 ret = wl1271_acx_pm_config(wl);
557 if (ret < 0)
558 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559
560 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200561
562 out_free_memmap:
563 kfree(wl->target_mem_map);
564 wl->target_mem_map = NULL;
565
566 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300567}
568
Arik Nemtsovb622d992011-02-23 00:22:31 +0200569static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
570{
571 bool fw_ps;
572
573 /* only regulate station links */
574 if (hlid < WL1271_AP_STA_HLID_START)
575 return;
576
577 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
578
579 /*
580 * Wake up from high level PS if the STA is asleep with too little
581 * blocks in FW or if the STA is awake.
582 */
583 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
584 wl1271_ps_link_end(wl, hlid);
585
586 /* Start high-level PS if the STA is asleep with enough blocks in FW */
587 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
588 wl1271_ps_link_start(wl, hlid, true);
589}
590
591static void wl1271_irq_update_links_status(struct wl1271 *wl,
592 struct wl1271_fw_ap_status *status)
593{
594 u32 cur_fw_ps_map;
595 u8 hlid;
596
597 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
598 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
599 wl1271_debug(DEBUG_PSM,
600 "link ps prev 0x%x cur 0x%x changed 0x%x",
601 wl->ap_fw_ps_map, cur_fw_ps_map,
602 wl->ap_fw_ps_map ^ cur_fw_ps_map);
603
604 wl->ap_fw_ps_map = cur_fw_ps_map;
605 }
606
607 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
608 u8 cnt = status->tx_lnk_free_blks[hlid] -
609 wl->links[hlid].prev_freed_blks;
610
611 wl->links[hlid].prev_freed_blks =
612 status->tx_lnk_free_blks[hlid];
613 wl->links[hlid].allocated_blks -= cnt;
614
615 wl1271_irq_ps_regulate_link(wl, hlid,
616 wl->links[hlid].allocated_blks);
617 }
618}
619
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300620static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200621 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200623 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200624 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200625 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200626 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627 int i;
628
Shahar Levi13b107d2011-03-06 16:32:12 +0200629 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200630 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
631 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200632 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200633 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
634 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200635 }
636
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
638 "drv_rx_counter = %d, tx_results_counter = %d)",
639 status->intr,
640 status->fw_rx_counter,
641 status->drv_rx_counter,
642 status->tx_results_counter);
643
644 /* update number of available TX blocks */
645 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200646 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
647 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300648
649 wl->tx_blocks_freed[i] =
650 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200651 }
652
Ido Yarivd2f4d472011-03-31 10:07:00 +0200653 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200654
Ido Yarivd2f4d472011-03-31 10:07:00 +0200655 if (wl->bss_type == BSS_TYPE_AP_BSS) {
656 /* Update num of allocated TX blocks per link and ps status */
657 wl1271_irq_update_links_status(wl, &full_status->ap);
658 wl->tx_blocks_available += freed_blocks;
659 } else {
660 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
661
662 /*
663 * The FW might change the total number of TX memblocks before
664 * we get a notification about blocks being released. Thus, the
665 * available blocks calculation might yield a temporary result
666 * which is lower than the actual available blocks. Keeping in
667 * mind that only blocks that were allocated can be moved from
668 * TX to RX, tx_blocks_available should never decrease here.
669 */
670 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
671 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 }
673
Ido Yariva5225502010-10-12 14:49:10 +0200674 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200675 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200676 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677
678 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200679 getnstimeofday(&ts);
680 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
681 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682}
683
Ido Yariva6208652011-03-01 15:14:41 +0200684static void wl1271_flush_deferred_work(struct wl1271 *wl)
685{
686 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200687
Ido Yariva6208652011-03-01 15:14:41 +0200688 /* Pass all received frames to the network stack */
689 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
690 ieee80211_rx_ni(wl->hw, skb);
691
692 /* Return sent skbs to the network stack */
693 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
694 ieee80211_tx_status(wl->hw, skb);
695}
696
697static void wl1271_netstack_work(struct work_struct *work)
698{
699 struct wl1271 *wl =
700 container_of(work, struct wl1271, netstack_work);
701
702 do {
703 wl1271_flush_deferred_work(wl);
704 } while (skb_queue_len(&wl->deferred_rx_queue));
705}
706
707#define WL1271_IRQ_MAX_LOOPS 256
708
709irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300712 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200713 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200714 struct wl1271 *wl = (struct wl1271 *)cookie;
715 bool done = false;
716 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200717 unsigned long flags;
718
719 /* TX might be handled here, avoid redundant work */
720 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
721 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722
Ido Yariv341b7cd2011-03-31 10:07:01 +0200723 /*
724 * In case edge triggered interrupt must be used, we cannot iterate
725 * more than once without introducing race conditions with the hardirq.
726 */
727 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
728 loopcount = 1;
729
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730 mutex_lock(&wl->mutex);
731
732 wl1271_debug(DEBUG_IRQ, "IRQ work");
733
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200734 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 goto out;
736
Ido Yariva6208652011-03-01 15:14:41 +0200737 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738 if (ret < 0)
739 goto out;
740
Ido Yariva6208652011-03-01 15:14:41 +0200741 while (!done && loopcount--) {
742 /*
743 * In order to avoid a race with the hardirq, clear the flag
744 * before acknowledging the chip. Since the mutex is held,
745 * wl1271_ps_elp_wakeup cannot be called concurrently.
746 */
747 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
748 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200749
750 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200751 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200752 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200753 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200754 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200755 continue;
756 }
757
Eliad Pellerccc83b02010-10-27 14:09:57 +0200758 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
759 wl1271_error("watchdog interrupt received! "
760 "starting recovery.");
761 ieee80211_queue_work(wl->hw, &wl->recovery_work);
762
763 /* restarting the chip. ignore any other interrupt. */
764 goto out;
765 }
766
Ido Yariva6208652011-03-01 15:14:41 +0200767 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200768 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
769
Ido Yariv8aad2462011-03-01 15:14:38 +0200770 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200771
Ido Yariva5225502010-10-12 14:49:10 +0200772 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200773 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200774 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200775 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200776 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200777 /*
778 * In order to avoid starvation of the TX path,
779 * call the work function directly.
780 */
781 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200782 } else {
783 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200784 }
785
Ido Yariv8aad2462011-03-01 15:14:38 +0200786 /* check for tx results */
787 if (wl->fw_status->common.tx_results_counter !=
788 (wl->tx_results_count & 0xff))
789 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200790
791 /* Make sure the deferred queues don't get too long */
792 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
793 skb_queue_len(&wl->deferred_rx_queue);
794 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
795 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200796 }
797
798 if (intr & WL1271_ACX_INTR_EVENT_A) {
799 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
800 wl1271_event_handle(wl, 0);
801 }
802
803 if (intr & WL1271_ACX_INTR_EVENT_B) {
804 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
805 wl1271_event_handle(wl, 1);
806 }
807
808 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
809 wl1271_debug(DEBUG_IRQ,
810 "WL1271_ACX_INTR_INIT_COMPLETE");
811
812 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
813 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814 }
815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 wl1271_ps_elp_sleep(wl);
817
818out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200819 spin_lock_irqsave(&wl->wl_lock, flags);
820 /* In case TX was not handled here, queue TX work */
821 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
822 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
823 wl->tx_queue_count)
824 ieee80211_queue_work(wl->hw, &wl->tx_work);
825 spin_unlock_irqrestore(&wl->wl_lock, flags);
826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200828
829 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830}
Ido Yariva6208652011-03-01 15:14:41 +0200831EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833static int wl1271_fetch_firmware(struct wl1271 *wl)
834{
835 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200836 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 int ret;
838
Arik Nemtsov166d5042010-10-16 21:44:57 +0200839 switch (wl->bss_type) {
840 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200841 if (wl->chip.id == CHIP_ID_1283_PG20)
842 fw_name = WL128X_AP_FW_NAME;
843 else
844 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200845 break;
846 case BSS_TYPE_IBSS:
847 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200848 if (wl->chip.id == CHIP_ID_1283_PG20)
849 fw_name = WL128X_FW_NAME;
850 else
851 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200852 break;
853 default:
854 wl1271_error("no compatible firmware for bss_type %d",
855 wl->bss_type);
856 return -EINVAL;
857 }
858
859 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
860
861 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862
863 if (ret < 0) {
864 wl1271_error("could not get firmware: %d", ret);
865 return ret;
866 }
867
868 if (fw->size % 4) {
869 wl1271_error("firmware size is not multiple of 32 bits: %zu",
870 fw->size);
871 ret = -EILSEQ;
872 goto out;
873 }
874
Arik Nemtsov166d5042010-10-16 21:44:57 +0200875 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300877 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
879 if (!wl->fw) {
880 wl1271_error("could not allocate memory for the firmware");
881 ret = -ENOMEM;
882 goto out;
883 }
884
885 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200886 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 ret = 0;
888
889out:
890 release_firmware(fw);
891
892 return ret;
893}
894
895static int wl1271_fetch_nvs(struct wl1271 *wl)
896{
897 const struct firmware *fw;
898 int ret;
899
Shahar Levi5aa42342011-03-06 16:32:07 +0200900 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901
902 if (ret < 0) {
903 wl1271_error("could not get nvs file: %d", ret);
904 return ret;
905 }
906
Shahar Levibc765bf2011-03-06 16:32:10 +0200907 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908
909 if (!wl->nvs) {
910 wl1271_error("could not allocate memory for the nvs file");
911 ret = -ENOMEM;
912 goto out;
913 }
914
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200915 wl->nvs_len = fw->size;
916
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917out:
918 release_firmware(fw);
919
920 return ret;
921}
922
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200923static void wl1271_recovery_work(struct work_struct *work)
924{
925 struct wl1271 *wl =
926 container_of(work, struct wl1271, recovery_work);
927
928 mutex_lock(&wl->mutex);
929
930 if (wl->state != WL1271_STATE_ON)
931 goto out;
932
933 wl1271_info("Hardware recovery in progress.");
934
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200935 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
936 ieee80211_connection_loss(wl->vif);
937
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200938 /* reboot the chipset */
939 __wl1271_op_remove_interface(wl);
940 ieee80211_restart_hw(wl->hw);
941
942out:
943 mutex_unlock(&wl->mutex);
944}
945
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946static void wl1271_fw_wakeup(struct wl1271 *wl)
947{
948 u32 elp_reg;
949
950 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300951 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952}
953
954static int wl1271_setup(struct wl1271 *wl)
955{
956 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
957 if (!wl->fw_status)
958 return -ENOMEM;
959
960 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
961 if (!wl->tx_res_if) {
962 kfree(wl->fw_status);
963 return -ENOMEM;
964 }
965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 return 0;
967}
968
969static int wl1271_chip_wakeup(struct wl1271 *wl)
970{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300971 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 int ret = 0;
973
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200974 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200975 ret = wl1271_power_on(wl);
976 if (ret < 0)
977 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200979 wl1271_io_reset(wl);
980 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981
982 /* We don't need a real memory partition here, because we only want
983 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300984 memset(&partition, 0, sizeof(partition));
985 partition.reg.start = REGISTERS_BASE;
986 partition.reg.size = REGISTERS_DOWN_SIZE;
987 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988
989 /* ELP module wake up */
990 wl1271_fw_wakeup(wl);
991
992 /* whal_FwCtrl_BootSm() */
993
994 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200995 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996
997 /* 1. check if chip id is valid */
998
999 switch (wl->chip.id) {
1000 case CHIP_ID_1271_PG10:
1001 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1002 wl->chip.id);
1003
1004 ret = wl1271_setup(wl);
1005 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001006 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 break;
1008 case CHIP_ID_1271_PG20:
1009 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1010 wl->chip.id);
1011
1012 ret = wl1271_setup(wl);
1013 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001014 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001016 case CHIP_ID_1283_PG20:
1017 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1018 wl->chip.id);
1019
1020 ret = wl1271_setup(wl);
1021 if (ret < 0)
1022 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001023 if (wl1271_set_block_size(wl))
1024 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001025 break;
1026 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001028 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001030 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 }
1032
Arik Nemtsov166d5042010-10-16 21:44:57 +02001033 /* Make sure the firmware type matches the BSS type */
1034 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 ret = wl1271_fetch_firmware(wl);
1036 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001037 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 }
1039
1040 /* No NVS from netlink, try to get it from the filesystem */
1041 if (wl->nvs == NULL) {
1042 ret = wl1271_fetch_nvs(wl);
1043 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001044 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 }
1046
1047out:
1048 return ret;
1049}
1050
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001051static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1052{
1053 unsigned int quirks = 0;
1054 unsigned int *fw_ver = wl->chip.fw_ver;
1055
1056 /* Only for wl127x */
1057 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1058 /* Check STA version */
1059 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1060 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1061 /* Check AP version */
1062 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1063 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1064 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1065
1066 return quirks;
1067}
1068
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069int wl1271_plt_start(struct wl1271 *wl)
1070{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001071 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 int ret;
1073
1074 mutex_lock(&wl->mutex);
1075
1076 wl1271_notice("power up");
1077
1078 if (wl->state != WL1271_STATE_OFF) {
1079 wl1271_error("cannot go into PLT state because not "
1080 "in off state: %d", wl->state);
1081 ret = -EBUSY;
1082 goto out;
1083 }
1084
Arik Nemtsov166d5042010-10-16 21:44:57 +02001085 wl->bss_type = BSS_TYPE_STA_BSS;
1086
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001087 while (retries) {
1088 retries--;
1089 ret = wl1271_chip_wakeup(wl);
1090 if (ret < 0)
1091 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001093 ret = wl1271_boot(wl);
1094 if (ret < 0)
1095 goto power_off;
1096
1097 ret = wl1271_plt_init(wl);
1098 if (ret < 0)
1099 goto irq_disable;
1100
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001101 wl->state = WL1271_STATE_PLT;
1102 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001103 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001104
1105 /* Check if any quirks are needed with older fw versions */
1106 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 goto out;
1108
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001109irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001110 mutex_unlock(&wl->mutex);
1111 /* Unlocking the mutex in the middle of handling is
1112 inherently unsafe. In this case we deem it safe to do,
1113 because we need to let any possibly pending IRQ out of
1114 the system (and while we are WL1271_STATE_OFF the IRQ
1115 work function will not do anything.) Also, any other
1116 possible concurrent operations will fail due to the
1117 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001118 wl1271_disable_interrupts(wl);
1119 wl1271_flush_deferred_work(wl);
1120 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001121 mutex_lock(&wl->mutex);
1122power_off:
1123 wl1271_power_off(wl);
1124 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001126 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1127 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128out:
1129 mutex_unlock(&wl->mutex);
1130
1131 return ret;
1132}
1133
Luciano Coelho4623ec72011-03-21 19:26:41 +02001134static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135{
1136 int ret = 0;
1137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138 wl1271_notice("power down");
1139
1140 if (wl->state != WL1271_STATE_PLT) {
1141 wl1271_error("cannot power down because not in PLT "
1142 "state: %d", wl->state);
1143 ret = -EBUSY;
1144 goto out;
1145 }
1146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147 wl1271_power_off(wl);
1148
1149 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001150 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001151
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001152 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001153 wl1271_disable_interrupts(wl);
1154 wl1271_flush_deferred_work(wl);
1155 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001156 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001157 mutex_lock(&wl->mutex);
1158out:
1159 return ret;
1160}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001161
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001162int wl1271_plt_stop(struct wl1271 *wl)
1163{
1164 int ret;
1165
1166 mutex_lock(&wl->mutex);
1167 ret = __wl1271_plt_stop(wl);
1168 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001169 return ret;
1170}
1171
Johannes Berg7bb45682011-02-24 14:42:06 +01001172static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173{
1174 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001175 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001176 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001177 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
Ido Yarivb07d4032011-03-01 15:14:43 +02001179 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1180
1181 if (wl->bss_type == BSS_TYPE_AP_BSS)
1182 hlid = wl1271_tx_get_hlid(skb);
1183
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001184 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001185
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001186 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001187
1188 /*
1189 * The workqueue is slow to process the tx_queue and we need stop
1190 * the queue here, otherwise the queue will get too long.
1191 */
1192 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1193 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1194 ieee80211_stop_queues(wl->hw);
1195 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1196 }
1197
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001198 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001199 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001200 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1201 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1202 } else {
1203 skb_queue_tail(&wl->tx_queue[q], skb);
1204 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205
1206 /*
1207 * The chip specific setup must run before the first TX packet -
1208 * before that, the tx_work will not be initialized!
1209 */
1210
Ido Yarivb07d4032011-03-01 15:14:43 +02001211 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1212 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001213 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001214
1215 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216}
1217
Shahar Leviae47c452011-03-06 16:32:14 +02001218int wl1271_tx_dummy_packet(struct wl1271 *wl)
1219{
Ido Yariv990f5de2011-03-31 10:06:59 +02001220 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001221
Ido Yariv990f5de2011-03-31 10:06:59 +02001222 spin_lock_irqsave(&wl->wl_lock, flags);
1223 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1224 wl->tx_queue_count++;
1225 spin_unlock_irqrestore(&wl->wl_lock, flags);
1226
1227 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1228 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1229 wl1271_tx_work_locked(wl);
1230
1231 /*
1232 * If the FW TX is busy, TX work will be scheduled by the threaded
1233 * interrupt handler function
1234 */
1235 return 0;
1236}
1237
1238/*
1239 * The size of the dummy packet should be at least 1400 bytes. However, in
1240 * order to minimize the number of bus transactions, aligning it to 512 bytes
1241 * boundaries could be beneficial, performance wise
1242 */
1243#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1244
1245struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
1246{
1247 struct sk_buff *skb;
1248 struct ieee80211_hdr_3addr *hdr;
1249 unsigned int dummy_packet_size;
1250
1251 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1252 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1253
1254 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001255 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001256 wl1271_warning("Failed to allocate a dummy packet skb");
1257 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001258 }
1259
1260 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1261
1262 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1263 memset(hdr, 0, sizeof(*hdr));
1264 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001265 IEEE80211_STYPE_NULLFUNC |
1266 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001267
Ido Yariv990f5de2011-03-31 10:06:59 +02001268 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001269
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001270 /* Dummy packets require the TID to be management */
1271 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001272
1273 /* Initialize all fields that might be used */
Shahar Leviae47c452011-03-06 16:32:14 +02001274 skb->queue_mapping = 0;
Ido Yariv990f5de2011-03-31 10:06:59 +02001275 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001276
Ido Yariv990f5de2011-03-31 10:06:59 +02001277 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001278}
1279
Ido Yariv990f5de2011-03-31 10:06:59 +02001280
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001281static struct notifier_block wl1271_dev_notifier = {
1282 .notifier_call = wl1271_dev_notify,
1283};
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285static int wl1271_op_start(struct ieee80211_hw *hw)
1286{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001287 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1288
1289 /*
1290 * We have to delay the booting of the hardware because
1291 * we need to know the local MAC address before downloading and
1292 * initializing the firmware. The MAC address cannot be changed
1293 * after boot, and without the proper MAC address, the firmware
1294 * will not function properly.
1295 *
1296 * The MAC address is first known when the corresponding interface
1297 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001298 *
1299 * In addition, we currently have different firmwares for AP and managed
1300 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001301 */
1302
1303 return 0;
1304}
1305
1306static void wl1271_op_stop(struct ieee80211_hw *hw)
1307{
1308 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1309}
1310
1311static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1312 struct ieee80211_vif *vif)
1313{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001315 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001316 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001318 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001320 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1321 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322
1323 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001324 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001325 wl1271_debug(DEBUG_MAC80211,
1326 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001327 ret = -EBUSY;
1328 goto out;
1329 }
1330
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001331 /*
1332 * in some very corner case HW recovery scenarios its possible to
1333 * get here before __wl1271_op_remove_interface is complete, so
1334 * opt out if that is the case.
1335 */
1336 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1337 ret = -EBUSY;
1338 goto out;
1339 }
1340
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001341 switch (vif->type) {
1342 case NL80211_IFTYPE_STATION:
1343 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001344 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001345 break;
1346 case NL80211_IFTYPE_ADHOC:
1347 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001348 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001349 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001350 case NL80211_IFTYPE_AP:
1351 wl->bss_type = BSS_TYPE_AP_BSS;
1352 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001353 default:
1354 ret = -EOPNOTSUPP;
1355 goto out;
1356 }
1357
1358 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359
1360 if (wl->state != WL1271_STATE_OFF) {
1361 wl1271_error("cannot start because not in off state: %d",
1362 wl->state);
1363 ret = -EBUSY;
1364 goto out;
1365 }
1366
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001367 while (retries) {
1368 retries--;
1369 ret = wl1271_chip_wakeup(wl);
1370 if (ret < 0)
1371 goto power_off;
1372
1373 ret = wl1271_boot(wl);
1374 if (ret < 0)
1375 goto power_off;
1376
1377 ret = wl1271_hw_init(wl);
1378 if (ret < 0)
1379 goto irq_disable;
1380
Eliad Peller71125ab2010-10-28 21:46:43 +02001381 booted = true;
1382 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001384irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001385 mutex_unlock(&wl->mutex);
1386 /* Unlocking the mutex in the middle of handling is
1387 inherently unsafe. In this case we deem it safe to do,
1388 because we need to let any possibly pending IRQ out of
1389 the system (and while we are WL1271_STATE_OFF the IRQ
1390 work function will not do anything.) Also, any other
1391 possible concurrent operations will fail due to the
1392 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001393 wl1271_disable_interrupts(wl);
1394 wl1271_flush_deferred_work(wl);
1395 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001396 mutex_lock(&wl->mutex);
1397power_off:
1398 wl1271_power_off(wl);
1399 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
Eliad Peller71125ab2010-10-28 21:46:43 +02001401 if (!booted) {
1402 wl1271_error("firmware boot failed despite %d retries",
1403 WL1271_BOOT_RETRIES);
1404 goto out;
1405 }
1406
1407 wl->vif = vif;
1408 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001409 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001410 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001411
1412 /* update hw/fw version info in wiphy struct */
1413 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001414 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001415 sizeof(wiphy->fw_version));
1416
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001417 /* Check if any quirks are needed with older fw versions */
1418 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1419
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001420 /*
1421 * Now we know if 11a is supported (info from the NVS), so disable
1422 * 11a channels if not supported
1423 */
1424 if (!wl->enable_11a)
1425 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1426
1427 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1428 wl->enable_11a ? "" : "not ");
1429
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001430out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 mutex_unlock(&wl->mutex);
1432
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001433 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001434 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001435 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001436 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001437
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438 return ret;
1439}
1440
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001441static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443 int i;
1444
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001445 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001447 /* because of hardware recovery, we may get here twice */
1448 if (wl->state != WL1271_STATE_ON)
1449 return;
1450
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001451 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001453 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001454 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001455 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001456
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001457 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001458 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001459 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001460
Luciano Coelho08688d62010-07-08 17:50:07 +03001461 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001462 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001463 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001464 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001465 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 }
1467
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001468 /*
1469 * this must be before the cancel_work calls below, so that the work
1470 * functions don't perform further work.
1471 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 wl->state = WL1271_STATE_OFF;
1473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 mutex_unlock(&wl->mutex);
1475
Ido Yariva6208652011-03-01 15:14:41 +02001476 wl1271_disable_interrupts(wl);
1477 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001478 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001479 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001481 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001482 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483
1484 mutex_lock(&wl->mutex);
1485
1486 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001487 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001488 wl1271_power_off(wl);
1489
1490 memset(wl->bssid, 0, ETH_ALEN);
1491 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1492 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001494 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001495 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496
1497 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001498 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1500 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001501 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502 wl->tx_results_count = 0;
1503 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001504 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001505 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 wl->time_offset = 0;
1507 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001508 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001509 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001510 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001511 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001512 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001513 wl->ap_fw_ps_map = 0;
1514 wl->ap_ps_map = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001515
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001516 /*
1517 * this is performed after the cancel_work calls and the associated
1518 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1519 * get executed before all these vars have been reset.
1520 */
1521 wl->flags = 0;
1522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 for (i = 0; i < NUM_TX_QUEUES; i++)
1524 wl->tx_blocks_freed[i] = 0;
1525
1526 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001527
1528 kfree(wl->fw_status);
1529 wl->fw_status = NULL;
1530 kfree(wl->tx_res_if);
1531 wl->tx_res_if = NULL;
1532 kfree(wl->target_mem_map);
1533 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001534}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001535
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001536static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1537 struct ieee80211_vif *vif)
1538{
1539 struct wl1271 *wl = hw->priv;
1540
1541 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001542 /*
1543 * wl->vif can be null here if someone shuts down the interface
1544 * just when hardware recovery has been started.
1545 */
1546 if (wl->vif) {
1547 WARN_ON(wl->vif != vif);
1548 __wl1271_op_remove_interface(wl);
1549 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001550
Juuso Oikarinen67353292010-11-18 15:19:02 +02001551 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001552 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553}
1554
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001555void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001556{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001557 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001558
1559 /* combine requested filters with current filter config */
1560 filters = wl->filters | filters;
1561
1562 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1563
1564 if (filters & FIF_PROMISC_IN_BSS) {
1565 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1566 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1567 wl->rx_config |= CFG_BSSID_FILTER_EN;
1568 }
1569 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1570 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1571 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1572 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1573 }
1574 if (filters & FIF_OTHER_BSS) {
1575 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1576 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1577 }
1578 if (filters & FIF_CONTROL) {
1579 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1580 wl->rx_filter |= CFG_RX_CTL_EN;
1581 }
1582 if (filters & FIF_FCSFAIL) {
1583 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1584 wl->rx_filter |= CFG_RX_FCS_ERROR;
1585 }
1586}
1587
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001588static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001589{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001590 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001591 /* we need to use a dummy BSSID for now */
1592 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1593 0xad, 0xbe, 0xef };
1594
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001595 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1596
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001597 /* pass through frames from all BSS */
1598 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1599
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001600 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001601 if (ret < 0)
1602 goto out;
1603
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001604 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001605
1606out:
1607 return ret;
1608}
1609
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001610static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001611{
1612 int ret;
1613
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001614 /*
1615 * One of the side effects of the JOIN command is that is clears
1616 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1617 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001618 * Currently the only valid scenario for JOIN during association
1619 * is on roaming, in which case we will also be given new keys.
1620 * Keep the below message for now, unless it starts bothering
1621 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001622 */
1623 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1624 wl1271_info("JOIN while associated.");
1625
1626 if (set_assoc)
1627 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1628
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001629 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1630 if (ret < 0)
1631 goto out;
1632
1633 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1634
1635 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1636 goto out;
1637
1638 /*
1639 * The join command disable the keep-alive mode, shut down its process,
1640 * and also clear the template config, so we need to reset it all after
1641 * the join. The acx_aid starts the keep-alive process, and the order
1642 * of the commands below is relevant.
1643 */
1644 ret = wl1271_acx_keep_alive_mode(wl, true);
1645 if (ret < 0)
1646 goto out;
1647
1648 ret = wl1271_acx_aid(wl, wl->aid);
1649 if (ret < 0)
1650 goto out;
1651
1652 ret = wl1271_cmd_build_klv_null_data(wl);
1653 if (ret < 0)
1654 goto out;
1655
1656 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1657 ACX_KEEP_ALIVE_TPL_VALID);
1658 if (ret < 0)
1659 goto out;
1660
1661out:
1662 return ret;
1663}
1664
1665static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001666{
1667 int ret;
1668
1669 /* to stop listening to a channel, we disconnect */
1670 ret = wl1271_cmd_disconnect(wl);
1671 if (ret < 0)
1672 goto out;
1673
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001674 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001675 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001676
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001677 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001678 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001679
1680out:
1681 return ret;
1682}
1683
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001684static void wl1271_set_band_rate(struct wl1271 *wl)
1685{
1686 if (wl->band == IEEE80211_BAND_2GHZ)
1687 wl->basic_rate_set = wl->conf.tx.basic_rate;
1688 else
1689 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1690}
1691
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001692static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001693{
1694 int ret;
1695
1696 if (idle) {
1697 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1698 ret = wl1271_unjoin(wl);
1699 if (ret < 0)
1700 goto out;
1701 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001702 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001703 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001704 if (ret < 0)
1705 goto out;
1706 ret = wl1271_acx_keep_alive_config(
1707 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1708 ACX_KEEP_ALIVE_TPL_INVALID);
1709 if (ret < 0)
1710 goto out;
1711 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1712 } else {
1713 /* increment the session counter */
1714 wl->session_counter++;
1715 if (wl->session_counter >= SESSION_COUNTER_MAX)
1716 wl->session_counter = 0;
1717 ret = wl1271_dummy_join(wl);
1718 if (ret < 0)
1719 goto out;
1720 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1721 }
1722
1723out:
1724 return ret;
1725}
1726
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1728{
1729 struct wl1271 *wl = hw->priv;
1730 struct ieee80211_conf *conf = &hw->conf;
1731 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001732 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001733
1734 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1735
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001736 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1737 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001738 channel,
1739 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001740 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001741 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1742 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001743
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001744 /*
1745 * mac80211 will go to idle nearly immediately after transmitting some
1746 * frames, such as the deauth. To make sure those frames reach the air,
1747 * wait here until the TX queue is fully flushed.
1748 */
1749 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1750 (conf->flags & IEEE80211_CONF_IDLE))
1751 wl1271_tx_flush(wl);
1752
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001753 mutex_lock(&wl->mutex);
1754
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001755 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001756 /* we support configuring the channel and band while off */
1757 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1758 wl->band = conf->channel->band;
1759 wl->channel = channel;
1760 }
1761
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001762 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001763 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001764
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001765 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1766
Ido Yariva6208652011-03-01 15:14:41 +02001767 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768 if (ret < 0)
1769 goto out;
1770
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001771 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001772 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1773 ((wl->band != conf->channel->band) ||
1774 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001775 wl->band = conf->channel->band;
1776 wl->channel = channel;
1777
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001778 if (!is_ap) {
1779 /*
1780 * FIXME: the mac80211 should really provide a fixed
1781 * rate to use here. for now, just use the smallest
1782 * possible rate for the band as a fixed rate for
1783 * association frames and other control messages.
1784 */
1785 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1786 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001787
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001788 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1789 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001790 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001791 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001792 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001793
1794 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1795 ret = wl1271_join(wl, false);
1796 if (ret < 0)
1797 wl1271_warning("cmd join on channel "
1798 "failed %d", ret);
1799 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001800 }
1801 }
1802
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001803 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1804 ret = wl1271_sta_handle_idle(wl,
1805 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001806 if (ret < 0)
1807 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 }
1809
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001810 /*
1811 * if mac80211 changes the PSM mode, make sure the mode is not
1812 * incorrectly changed after the pspoll failure active window.
1813 */
1814 if (changed & IEEE80211_CONF_CHANGE_PS)
1815 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1816
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001817 if (conf->flags & IEEE80211_CONF_PS &&
1818 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1819 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820
1821 /*
1822 * We enter PSM only if we're already associated.
1823 * If we're not, we'll enter it when joining an SSID,
1824 * through the bss_info_changed() hook.
1825 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001826 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001827 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001828 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001829 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001830 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001832 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001833 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001835 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001837 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001838 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001839 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 }
1841
1842 if (conf->power_level != wl->power_level) {
1843 ret = wl1271_acx_tx_power(wl, conf->power_level);
1844 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001845 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846
1847 wl->power_level = conf->power_level;
1848 }
1849
1850out_sleep:
1851 wl1271_ps_elp_sleep(wl);
1852
1853out:
1854 mutex_unlock(&wl->mutex);
1855
1856 return ret;
1857}
1858
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001859struct wl1271_filter_params {
1860 bool enabled;
1861 int mc_list_length;
1862 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1863};
1864
Jiri Pirko22bedad32010-04-01 21:22:57 +00001865static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1866 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001867{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001868 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001869 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001870 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001871
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001872 if (unlikely(wl->state == WL1271_STATE_OFF))
1873 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001874
Juuso Oikarinen74441132009-10-13 12:47:53 +03001875 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001876 if (!fp) {
1877 wl1271_error("Out of memory setting filters.");
1878 return 0;
1879 }
1880
1881 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001882 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001883 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1884 fp->enabled = false;
1885 } else {
1886 fp->enabled = true;
1887 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001888 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001889 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001890 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001891 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001892 }
1893
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001894 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001895}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001897#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1898 FIF_ALLMULTI | \
1899 FIF_FCSFAIL | \
1900 FIF_BCN_PRBRESP_PROMISC | \
1901 FIF_CONTROL | \
1902 FIF_OTHER_BSS)
1903
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001904static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1905 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001906 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001907{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001908 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001910 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001911
Arik Nemtsov7d057862010-10-16 19:25:35 +02001912 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1913 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001915 mutex_lock(&wl->mutex);
1916
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001917 *total &= WL1271_SUPPORTED_FILTERS;
1918 changed &= WL1271_SUPPORTED_FILTERS;
1919
1920 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001921 goto out;
1922
Ido Yariva6208652011-03-01 15:14:41 +02001923 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001924 if (ret < 0)
1925 goto out;
1926
Arik Nemtsov7d057862010-10-16 19:25:35 +02001927 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1928 if (*total & FIF_ALLMULTI)
1929 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1930 else if (fp)
1931 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1932 fp->mc_list,
1933 fp->mc_list_length);
1934 if (ret < 0)
1935 goto out_sleep;
1936 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001938 /* determine, whether supported filter values have changed */
1939 if (changed == 0)
1940 goto out_sleep;
1941
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001942 /* configure filters */
1943 wl->filters = *total;
1944 wl1271_configure_filters(wl, 0);
1945
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001946 /* apply configured filters */
1947 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1948 if (ret < 0)
1949 goto out_sleep;
1950
1951out_sleep:
1952 wl1271_ps_elp_sleep(wl);
1953
1954out:
1955 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001956 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957}
1958
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001959static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1960 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1961 u16 tx_seq_16)
1962{
1963 struct wl1271_ap_key *ap_key;
1964 int i;
1965
1966 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1967
1968 if (key_size > MAX_KEY_SIZE)
1969 return -EINVAL;
1970
1971 /*
1972 * Find next free entry in ap_keys. Also check we are not replacing
1973 * an existing key.
1974 */
1975 for (i = 0; i < MAX_NUM_KEYS; i++) {
1976 if (wl->recorded_ap_keys[i] == NULL)
1977 break;
1978
1979 if (wl->recorded_ap_keys[i]->id == id) {
1980 wl1271_warning("trying to record key replacement");
1981 return -EINVAL;
1982 }
1983 }
1984
1985 if (i == MAX_NUM_KEYS)
1986 return -EBUSY;
1987
1988 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1989 if (!ap_key)
1990 return -ENOMEM;
1991
1992 ap_key->id = id;
1993 ap_key->key_type = key_type;
1994 ap_key->key_size = key_size;
1995 memcpy(ap_key->key, key, key_size);
1996 ap_key->hlid = hlid;
1997 ap_key->tx_seq_32 = tx_seq_32;
1998 ap_key->tx_seq_16 = tx_seq_16;
1999
2000 wl->recorded_ap_keys[i] = ap_key;
2001 return 0;
2002}
2003
2004static void wl1271_free_ap_keys(struct wl1271 *wl)
2005{
2006 int i;
2007
2008 for (i = 0; i < MAX_NUM_KEYS; i++) {
2009 kfree(wl->recorded_ap_keys[i]);
2010 wl->recorded_ap_keys[i] = NULL;
2011 }
2012}
2013
2014static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2015{
2016 int i, ret = 0;
2017 struct wl1271_ap_key *key;
2018 bool wep_key_added = false;
2019
2020 for (i = 0; i < MAX_NUM_KEYS; i++) {
2021 if (wl->recorded_ap_keys[i] == NULL)
2022 break;
2023
2024 key = wl->recorded_ap_keys[i];
2025 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2026 key->id, key->key_type,
2027 key->key_size, key->key,
2028 key->hlid, key->tx_seq_32,
2029 key->tx_seq_16);
2030 if (ret < 0)
2031 goto out;
2032
2033 if (key->key_type == KEY_WEP)
2034 wep_key_added = true;
2035 }
2036
2037 if (wep_key_added) {
2038 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2039 if (ret < 0)
2040 goto out;
2041 }
2042
2043out:
2044 wl1271_free_ap_keys(wl);
2045 return ret;
2046}
2047
2048static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2049 u8 key_size, const u8 *key, u32 tx_seq_32,
2050 u16 tx_seq_16, struct ieee80211_sta *sta)
2051{
2052 int ret;
2053 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2054
2055 if (is_ap) {
2056 struct wl1271_station *wl_sta;
2057 u8 hlid;
2058
2059 if (sta) {
2060 wl_sta = (struct wl1271_station *)sta->drv_priv;
2061 hlid = wl_sta->hlid;
2062 } else {
2063 hlid = WL1271_AP_BROADCAST_HLID;
2064 }
2065
2066 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2067 /*
2068 * We do not support removing keys after AP shutdown.
2069 * Pretend we do to make mac80211 happy.
2070 */
2071 if (action != KEY_ADD_OR_REPLACE)
2072 return 0;
2073
2074 ret = wl1271_record_ap_key(wl, id,
2075 key_type, key_size,
2076 key, hlid, tx_seq_32,
2077 tx_seq_16);
2078 } else {
2079 ret = wl1271_cmd_set_ap_key(wl, action,
2080 id, key_type, key_size,
2081 key, hlid, tx_seq_32,
2082 tx_seq_16);
2083 }
2084
2085 if (ret < 0)
2086 return ret;
2087 } else {
2088 const u8 *addr;
2089 static const u8 bcast_addr[ETH_ALEN] = {
2090 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2091 };
2092
2093 addr = sta ? sta->addr : bcast_addr;
2094
2095 if (is_zero_ether_addr(addr)) {
2096 /* We dont support TX only encryption */
2097 return -EOPNOTSUPP;
2098 }
2099
2100 /* The wl1271 does not allow to remove unicast keys - they
2101 will be cleared automatically on next CMD_JOIN. Ignore the
2102 request silently, as we dont want the mac80211 to emit
2103 an error message. */
2104 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2105 return 0;
2106
2107 ret = wl1271_cmd_set_sta_key(wl, action,
2108 id, key_type, key_size,
2109 key, addr, tx_seq_32,
2110 tx_seq_16);
2111 if (ret < 0)
2112 return ret;
2113
2114 /* the default WEP key needs to be configured at least once */
2115 if (key_type == KEY_WEP) {
2116 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2117 wl->default_key);
2118 if (ret < 0)
2119 return ret;
2120 }
2121 }
2122
2123 return 0;
2124}
2125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002126static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2127 struct ieee80211_vif *vif,
2128 struct ieee80211_sta *sta,
2129 struct ieee80211_key_conf *key_conf)
2130{
2131 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002133 u32 tx_seq_32 = 0;
2134 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135 u8 key_type;
2136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2138
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002139 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002141 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142 key_conf->keylen, key_conf->flags);
2143 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 mutex_lock(&wl->mutex);
2146
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002147 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2148 ret = -EAGAIN;
2149 goto out_unlock;
2150 }
2151
Ido Yariva6208652011-03-01 15:14:41 +02002152 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 if (ret < 0)
2154 goto out_unlock;
2155
Johannes Berg97359d12010-08-10 09:46:38 +02002156 switch (key_conf->cipher) {
2157 case WLAN_CIPHER_SUITE_WEP40:
2158 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159 key_type = KEY_WEP;
2160
2161 key_conf->hw_key_idx = key_conf->keyidx;
2162 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002163 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164 key_type = KEY_TKIP;
2165
2166 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002167 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2168 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002170 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171 key_type = KEY_AES;
2172
2173 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002174 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2175 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002177 case WL1271_CIPHER_SUITE_GEM:
2178 key_type = KEY_GEM;
2179 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2180 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2181 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002183 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184
2185 ret = -EOPNOTSUPP;
2186 goto out_sleep;
2187 }
2188
2189 switch (cmd) {
2190 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002191 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2192 key_conf->keyidx, key_type,
2193 key_conf->keylen, key_conf->key,
2194 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195 if (ret < 0) {
2196 wl1271_error("Could not add or replace key");
2197 goto out_sleep;
2198 }
2199 break;
2200
2201 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002202 ret = wl1271_set_key(wl, KEY_REMOVE,
2203 key_conf->keyidx, key_type,
2204 key_conf->keylen, key_conf->key,
2205 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206 if (ret < 0) {
2207 wl1271_error("Could not remove key");
2208 goto out_sleep;
2209 }
2210 break;
2211
2212 default:
2213 wl1271_error("Unsupported key cmd 0x%x", cmd);
2214 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215 break;
2216 }
2217
2218out_sleep:
2219 wl1271_ps_elp_sleep(wl);
2220
2221out_unlock:
2222 mutex_unlock(&wl->mutex);
2223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002224 return ret;
2225}
2226
2227static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002228 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002229 struct cfg80211_scan_request *req)
2230{
2231 struct wl1271 *wl = hw->priv;
2232 int ret;
2233 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002234 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002235
2236 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2237
2238 if (req->n_ssids) {
2239 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002240 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002241 }
2242
2243 mutex_lock(&wl->mutex);
2244
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002245 if (wl->state == WL1271_STATE_OFF) {
2246 /*
2247 * We cannot return -EBUSY here because cfg80211 will expect
2248 * a call to ieee80211_scan_completed if we do - in this case
2249 * there won't be any call.
2250 */
2251 ret = -EAGAIN;
2252 goto out;
2253 }
2254
Ido Yariva6208652011-03-01 15:14:41 +02002255 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002256 if (ret < 0)
2257 goto out;
2258
Luciano Coelho5924f892010-08-04 03:46:22 +03002259 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002260
2261 wl1271_ps_elp_sleep(wl);
2262
2263out:
2264 mutex_unlock(&wl->mutex);
2265
2266 return ret;
2267}
2268
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002269static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2270{
2271 struct wl1271 *wl = hw->priv;
2272 int ret = 0;
2273
2274 mutex_lock(&wl->mutex);
2275
2276 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2277 ret = -EAGAIN;
2278 goto out;
2279 }
2280
Ido Yariva6208652011-03-01 15:14:41 +02002281 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002282 if (ret < 0)
2283 goto out;
2284
2285 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2286 if (ret < 0)
2287 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2288
2289 wl1271_ps_elp_sleep(wl);
2290
2291out:
2292 mutex_unlock(&wl->mutex);
2293
2294 return ret;
2295}
2296
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2298{
2299 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002300 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301
2302 mutex_lock(&wl->mutex);
2303
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002304 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2305 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002306 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002307 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002308
Ido Yariva6208652011-03-01 15:14:41 +02002309 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002310 if (ret < 0)
2311 goto out;
2312
2313 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2314 if (ret < 0)
2315 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2316
2317 wl1271_ps_elp_sleep(wl);
2318
2319out:
2320 mutex_unlock(&wl->mutex);
2321
2322 return ret;
2323}
2324
Arik Nemtsove78a2872010-10-16 19:07:21 +02002325static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002326 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002327{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002328 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002329
2330 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002331 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002332 if (ptr[0] == WLAN_EID_SSID) {
2333 wl->ssid_len = ptr[1];
2334 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002335 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002336 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002337 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002338 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002339
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002340 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002342}
2343
Arik Nemtsove78a2872010-10-16 19:07:21 +02002344static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2345 struct ieee80211_bss_conf *bss_conf,
2346 u32 changed)
2347{
2348 int ret = 0;
2349
2350 if (changed & BSS_CHANGED_ERP_SLOT) {
2351 if (bss_conf->use_short_slot)
2352 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2353 else
2354 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2355 if (ret < 0) {
2356 wl1271_warning("Set slot time failed %d", ret);
2357 goto out;
2358 }
2359 }
2360
2361 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2362 if (bss_conf->use_short_preamble)
2363 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2364 else
2365 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2366 }
2367
2368 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2369 if (bss_conf->use_cts_prot)
2370 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2371 else
2372 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2373 if (ret < 0) {
2374 wl1271_warning("Set ctsprotect failed %d", ret);
2375 goto out;
2376 }
2377 }
2378
2379out:
2380 return ret;
2381}
2382
2383static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2384 struct ieee80211_vif *vif,
2385 struct ieee80211_bss_conf *bss_conf,
2386 u32 changed)
2387{
2388 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2389 int ret = 0;
2390
2391 if ((changed & BSS_CHANGED_BEACON_INT)) {
2392 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2393 bss_conf->beacon_int);
2394
2395 wl->beacon_int = bss_conf->beacon_int;
2396 }
2397
2398 if ((changed & BSS_CHANGED_BEACON)) {
2399 struct ieee80211_hdr *hdr;
2400 int ieoffset = offsetof(struct ieee80211_mgmt,
2401 u.beacon.variable);
2402 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2403 u16 tmpl_id;
2404
2405 if (!beacon)
2406 goto out;
2407
2408 wl1271_debug(DEBUG_MASTER, "beacon updated");
2409
2410 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2411 if (ret < 0) {
2412 dev_kfree_skb(beacon);
2413 goto out;
2414 }
2415 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2416 CMD_TEMPL_BEACON;
2417 ret = wl1271_cmd_template_set(wl, tmpl_id,
2418 beacon->data,
2419 beacon->len, 0,
2420 wl1271_tx_min_rate_get(wl));
2421 if (ret < 0) {
2422 dev_kfree_skb(beacon);
2423 goto out;
2424 }
2425
2426 hdr = (struct ieee80211_hdr *) beacon->data;
2427 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2428 IEEE80211_STYPE_PROBE_RESP);
2429
2430 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2431 CMD_TEMPL_PROBE_RESPONSE;
2432 ret = wl1271_cmd_template_set(wl,
2433 tmpl_id,
2434 beacon->data,
2435 beacon->len, 0,
2436 wl1271_tx_min_rate_get(wl));
2437 dev_kfree_skb(beacon);
2438 if (ret < 0)
2439 goto out;
2440 }
2441
2442out:
2443 return ret;
2444}
2445
2446/* AP mode changes */
2447static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448 struct ieee80211_vif *vif,
2449 struct ieee80211_bss_conf *bss_conf,
2450 u32 changed)
2451{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002452 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453
Arik Nemtsove78a2872010-10-16 19:07:21 +02002454 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2455 u32 rates = bss_conf->basic_rates;
2456 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457
Arik Nemtsove78a2872010-10-16 19:07:21 +02002458 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2459 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2460 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2461 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002462
Arik Nemtsove78a2872010-10-16 19:07:21 +02002463 /* update the AP management rate policy with the new rates */
2464 mgmt_rc.enabled_rates = wl->basic_rate_set;
2465 mgmt_rc.long_retry_limit = 10;
2466 mgmt_rc.short_retry_limit = 10;
2467 mgmt_rc.aflags = 0;
2468 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2469 ACX_TX_AP_MODE_MGMT_RATE);
2470 if (ret < 0) {
2471 wl1271_error("AP mgmt policy change failed %d", ret);
2472 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002473 }
2474 }
2475
Arik Nemtsove78a2872010-10-16 19:07:21 +02002476 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2477 if (ret < 0)
2478 goto out;
2479
2480 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2481 if (bss_conf->enable_beacon) {
2482 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2483 ret = wl1271_cmd_start_bss(wl);
2484 if (ret < 0)
2485 goto out;
2486
2487 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2488 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002489
2490 ret = wl1271_ap_init_hwenc(wl);
2491 if (ret < 0)
2492 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002493 }
2494 } else {
2495 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2496 ret = wl1271_cmd_stop_bss(wl);
2497 if (ret < 0)
2498 goto out;
2499
2500 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2501 wl1271_debug(DEBUG_AP, "stopped AP");
2502 }
2503 }
2504 }
2505
2506 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2507 if (ret < 0)
2508 goto out;
2509out:
2510 return;
2511}
2512
2513/* STA/IBSS mode changes */
2514static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2515 struct ieee80211_vif *vif,
2516 struct ieee80211_bss_conf *bss_conf,
2517 u32 changed)
2518{
2519 bool do_join = false, set_assoc = false;
2520 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002521 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002522 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002523 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002524 bool sta_exists = false;
2525 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002526
2527 if (is_ibss) {
2528 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2529 changed);
2530 if (ret < 0)
2531 goto out;
2532 }
2533
2534 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2535 do_join = true;
2536
2537 /* Need to update the SSID (for filtering etc) */
2538 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2539 do_join = true;
2540
2541 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002542 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2543 bss_conf->enable_beacon ? "enabled" : "disabled");
2544
2545 if (bss_conf->enable_beacon)
2546 wl->set_bss_type = BSS_TYPE_IBSS;
2547 else
2548 wl->set_bss_type = BSS_TYPE_STA_BSS;
2549 do_join = true;
2550 }
2551
Arik Nemtsove78a2872010-10-16 19:07:21 +02002552 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002553 bool enable = false;
2554 if (bss_conf->cqm_rssi_thold)
2555 enable = true;
2556 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2557 bss_conf->cqm_rssi_thold,
2558 bss_conf->cqm_rssi_hyst);
2559 if (ret < 0)
2560 goto out;
2561 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2562 }
2563
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002564 if ((changed & BSS_CHANGED_BSSID) &&
2565 /*
2566 * Now we know the correct bssid, so we send a new join command
2567 * and enable the BSSID filter
2568 */
2569 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002570 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002571
Eliad Pellerfa287b82010-12-26 09:27:50 +01002572 if (!is_zero_ether_addr(wl->bssid)) {
2573 ret = wl1271_cmd_build_null_data(wl);
2574 if (ret < 0)
2575 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002576
Eliad Pellerfa287b82010-12-26 09:27:50 +01002577 ret = wl1271_build_qos_null_data(wl);
2578 if (ret < 0)
2579 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002580
Eliad Pellerfa287b82010-12-26 09:27:50 +01002581 /* filter out all packets not from this BSSID */
2582 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002583
Eliad Pellerfa287b82010-12-26 09:27:50 +01002584 /* Need to update the BSSID (for filtering etc) */
2585 do_join = true;
2586 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002587 }
2588
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002589 rcu_read_lock();
2590 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2591 if (sta) {
2592 /* save the supp_rates of the ap */
2593 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2594 if (sta->ht_cap.ht_supported)
2595 sta_rate_set |=
2596 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002597 sta_ht_cap = sta->ht_cap;
2598 sta_exists = true;
2599 }
2600 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002601
Arik Nemtsova1008852011-02-12 23:24:20 +02002602 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002603 /* handle new association with HT and HT information change */
2604 if ((changed & BSS_CHANGED_HT) &&
2605 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002606 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002607 true);
2608 if (ret < 0) {
2609 wl1271_warning("Set ht cap true failed %d",
2610 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002611 goto out;
2612 }
2613 ret = wl1271_acx_set_ht_information(wl,
2614 bss_conf->ht_operation_mode);
2615 if (ret < 0) {
2616 wl1271_warning("Set ht information failed %d",
2617 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002618 goto out;
2619 }
2620 }
2621 /* handle new association without HT and disassociation */
2622 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002623 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002624 false);
2625 if (ret < 0) {
2626 wl1271_warning("Set ht cap false failed %d",
2627 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002628 goto out;
2629 }
2630 }
2631 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002632
Arik Nemtsove78a2872010-10-16 19:07:21 +02002633 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002634 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002635 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002636 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002638 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002639
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002640 wl->ps_poll_failures = 0;
2641
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002642 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002643 * use basic rates from AP, and determine lowest rate
2644 * to use with control frames.
2645 */
2646 rates = bss_conf->basic_rates;
2647 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2648 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002649 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002650 if (sta_rate_set)
2651 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2652 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002653 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002654 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002655 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002656
2657 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002658 * with wl1271, we don't need to update the
2659 * beacon_int and dtim_period, because the firmware
2660 * updates it by itself when the first beacon is
2661 * received after a join.
2662 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2664 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002665 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002666
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002667 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002668 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002669 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002670 dev_kfree_skb(wl->probereq);
2671 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2672 ieoffset = offsetof(struct ieee80211_mgmt,
2673 u.probe_req.variable);
2674 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002675
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002676 /* enable the connection monitoring feature */
2677 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002680
2681 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002682 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2683 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002684 enum wl1271_cmd_ps_mode mode;
2685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002687 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002688 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002689 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002691 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002693 } else {
2694 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002695 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002696 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002697 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002698
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002699 /* free probe-request template */
2700 dev_kfree_skb(wl->probereq);
2701 wl->probereq = NULL;
2702
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002703 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002704 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002705
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002706 /* revert back to minimum rates for the current band */
2707 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002708 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002709 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002710 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002711 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002712
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002713 /* disable connection monitor features */
2714 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002715
2716 /* Disable the keep-alive feature */
2717 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002718 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002719 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002720
2721 /* restore the bssid filter and go to dummy bssid */
2722 wl1271_unjoin(wl);
2723 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002724 }
2725 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002726
Arik Nemtsove78a2872010-10-16 19:07:21 +02002727 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2728 if (ret < 0)
2729 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002731 if (changed & BSS_CHANGED_ARP_FILTER) {
2732 __be32 addr = bss_conf->arp_addr_list[0];
2733 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2734
Eliad Pellerc5312772010-12-09 11:31:27 +02002735 if (bss_conf->arp_addr_cnt == 1 &&
2736 bss_conf->arp_filter_enabled) {
2737 /*
2738 * The template should have been configured only upon
2739 * association. however, it seems that the correct ip
2740 * isn't being set (when sending), so we have to
2741 * reconfigure the template upon every ip change.
2742 */
2743 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2744 if (ret < 0) {
2745 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002746 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002747 }
2748
2749 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002750 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002751 addr);
2752 } else
2753 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002754
2755 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002756 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002757 }
2758
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002759 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002760 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002761 if (ret < 0) {
2762 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002763 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002764 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002765 }
2766
Arik Nemtsove78a2872010-10-16 19:07:21 +02002767out:
2768 return;
2769}
2770
2771static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2772 struct ieee80211_vif *vif,
2773 struct ieee80211_bss_conf *bss_conf,
2774 u32 changed)
2775{
2776 struct wl1271 *wl = hw->priv;
2777 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2778 int ret;
2779
2780 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2781 (int)changed);
2782
2783 mutex_lock(&wl->mutex);
2784
2785 if (unlikely(wl->state == WL1271_STATE_OFF))
2786 goto out;
2787
Ido Yariva6208652011-03-01 15:14:41 +02002788 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002789 if (ret < 0)
2790 goto out;
2791
2792 if (is_ap)
2793 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2794 else
2795 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797 wl1271_ps_elp_sleep(wl);
2798
2799out:
2800 mutex_unlock(&wl->mutex);
2801}
2802
Kalle Valoc6999d82010-02-18 13:25:41 +02002803static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2804 const struct ieee80211_tx_queue_params *params)
2805{
2806 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002807 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002808 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002809
2810 mutex_lock(&wl->mutex);
2811
2812 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2813
Kalle Valo4695dc92010-03-18 12:26:38 +02002814 if (params->uapsd)
2815 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2816 else
2817 ps_scheme = CONF_PS_SCHEME_LEGACY;
2818
Arik Nemtsov488fc542010-10-16 20:33:45 +02002819 if (wl->state == WL1271_STATE_OFF) {
2820 /*
2821 * If the state is off, the parameters will be recorded and
2822 * configured on init. This happens in AP-mode.
2823 */
2824 struct conf_tx_ac_category *conf_ac =
2825 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2826 struct conf_tx_tid *conf_tid =
2827 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2828
2829 conf_ac->ac = wl1271_tx_get_queue(queue);
2830 conf_ac->cw_min = (u8)params->cw_min;
2831 conf_ac->cw_max = params->cw_max;
2832 conf_ac->aifsn = params->aifs;
2833 conf_ac->tx_op_limit = params->txop << 5;
2834
2835 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2836 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2837 conf_tid->tsid = wl1271_tx_get_queue(queue);
2838 conf_tid->ps_scheme = ps_scheme;
2839 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2840 conf_tid->apsd_conf[0] = 0;
2841 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002842 goto out;
2843 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002844
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002845 ret = wl1271_ps_elp_wakeup(wl);
2846 if (ret < 0)
2847 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002848
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002849 /*
2850 * the txop is confed in units of 32us by the mac80211,
2851 * we need us
2852 */
2853 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2854 params->cw_min, params->cw_max,
2855 params->aifs, params->txop << 5);
2856 if (ret < 0)
2857 goto out_sleep;
2858
2859 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2860 CONF_CHANNEL_TYPE_EDCF,
2861 wl1271_tx_get_queue(queue),
2862 ps_scheme, CONF_ACK_POLICY_LEGACY,
2863 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002864
2865out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002866 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002867
2868out:
2869 mutex_unlock(&wl->mutex);
2870
2871 return ret;
2872}
2873
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002874static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2875{
2876
2877 struct wl1271 *wl = hw->priv;
2878 u64 mactime = ULLONG_MAX;
2879 int ret;
2880
2881 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2882
2883 mutex_lock(&wl->mutex);
2884
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002885 if (unlikely(wl->state == WL1271_STATE_OFF))
2886 goto out;
2887
Ido Yariva6208652011-03-01 15:14:41 +02002888 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002889 if (ret < 0)
2890 goto out;
2891
2892 ret = wl1271_acx_tsf_info(wl, &mactime);
2893 if (ret < 0)
2894 goto out_sleep;
2895
2896out_sleep:
2897 wl1271_ps_elp_sleep(wl);
2898
2899out:
2900 mutex_unlock(&wl->mutex);
2901 return mactime;
2902}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903
John W. Linvilleece550d2010-07-28 16:41:06 -04002904static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2905 struct survey_info *survey)
2906{
2907 struct wl1271 *wl = hw->priv;
2908 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002909
John W. Linvilleece550d2010-07-28 16:41:06 -04002910 if (idx != 0)
2911 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002912
John W. Linvilleece550d2010-07-28 16:41:06 -04002913 survey->channel = conf->channel;
2914 survey->filled = SURVEY_INFO_NOISE_DBM;
2915 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002916
John W. Linvilleece550d2010-07-28 16:41:06 -04002917 return 0;
2918}
2919
Arik Nemtsov409622e2011-02-23 00:22:29 +02002920static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002921 struct ieee80211_sta *sta,
2922 u8 *hlid)
2923{
2924 struct wl1271_station *wl_sta;
2925 int id;
2926
2927 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2928 if (id >= AP_MAX_STATIONS) {
2929 wl1271_warning("could not allocate HLID - too much stations");
2930 return -EBUSY;
2931 }
2932
2933 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002934 __set_bit(id, wl->ap_hlid_map);
2935 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2936 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002937 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002938 return 0;
2939}
2940
Arik Nemtsov409622e2011-02-23 00:22:29 +02002941static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002942{
2943 int id = hlid - WL1271_AP_STA_HLID_START;
2944
Arik Nemtsov409622e2011-02-23 00:22:29 +02002945 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2946 return;
2947
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002948 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002949 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002950 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002951 __clear_bit(hlid, &wl->ap_ps_map);
2952 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002953}
2954
2955static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2956 struct ieee80211_vif *vif,
2957 struct ieee80211_sta *sta)
2958{
2959 struct wl1271 *wl = hw->priv;
2960 int ret = 0;
2961 u8 hlid;
2962
2963 mutex_lock(&wl->mutex);
2964
2965 if (unlikely(wl->state == WL1271_STATE_OFF))
2966 goto out;
2967
2968 if (wl->bss_type != BSS_TYPE_AP_BSS)
2969 goto out;
2970
2971 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2972
Arik Nemtsov409622e2011-02-23 00:22:29 +02002973 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002974 if (ret < 0)
2975 goto out;
2976
Ido Yariva6208652011-03-01 15:14:41 +02002977 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002978 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002979 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002980
2981 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2982 if (ret < 0)
2983 goto out_sleep;
2984
2985out_sleep:
2986 wl1271_ps_elp_sleep(wl);
2987
Arik Nemtsov409622e2011-02-23 00:22:29 +02002988out_free_sta:
2989 if (ret < 0)
2990 wl1271_free_sta(wl, hlid);
2991
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002992out:
2993 mutex_unlock(&wl->mutex);
2994 return ret;
2995}
2996
2997static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2998 struct ieee80211_vif *vif,
2999 struct ieee80211_sta *sta)
3000{
3001 struct wl1271 *wl = hw->priv;
3002 struct wl1271_station *wl_sta;
3003 int ret = 0, id;
3004
3005 mutex_lock(&wl->mutex);
3006
3007 if (unlikely(wl->state == WL1271_STATE_OFF))
3008 goto out;
3009
3010 if (wl->bss_type != BSS_TYPE_AP_BSS)
3011 goto out;
3012
3013 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3014
3015 wl_sta = (struct wl1271_station *)sta->drv_priv;
3016 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3017 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3018 goto out;
3019
Ido Yariva6208652011-03-01 15:14:41 +02003020 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003021 if (ret < 0)
3022 goto out;
3023
3024 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3025 if (ret < 0)
3026 goto out_sleep;
3027
Arik Nemtsov409622e2011-02-23 00:22:29 +02003028 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003029
3030out_sleep:
3031 wl1271_ps_elp_sleep(wl);
3032
3033out:
3034 mutex_unlock(&wl->mutex);
3035 return ret;
3036}
3037
Luciano Coelho4623ec72011-03-21 19:26:41 +02003038static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3039 struct ieee80211_vif *vif,
3040 enum ieee80211_ampdu_mlme_action action,
3041 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3042 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003043{
3044 struct wl1271 *wl = hw->priv;
3045 int ret;
3046
3047 mutex_lock(&wl->mutex);
3048
3049 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3050 ret = -EAGAIN;
3051 goto out;
3052 }
3053
Ido Yariva6208652011-03-01 15:14:41 +02003054 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003055 if (ret < 0)
3056 goto out;
3057
3058 switch (action) {
3059 case IEEE80211_AMPDU_RX_START:
3060 if (wl->ba_support) {
3061 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3062 true);
3063 if (!ret)
3064 wl->ba_rx_bitmap |= BIT(tid);
3065 } else {
3066 ret = -ENOTSUPP;
3067 }
3068 break;
3069
3070 case IEEE80211_AMPDU_RX_STOP:
3071 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3072 if (!ret)
3073 wl->ba_rx_bitmap &= ~BIT(tid);
3074 break;
3075
3076 /*
3077 * The BA initiator session management in FW independently.
3078 * Falling break here on purpose for all TX APDU commands.
3079 */
3080 case IEEE80211_AMPDU_TX_START:
3081 case IEEE80211_AMPDU_TX_STOP:
3082 case IEEE80211_AMPDU_TX_OPERATIONAL:
3083 ret = -EINVAL;
3084 break;
3085
3086 default:
3087 wl1271_error("Incorrect ampdu action id=%x\n", action);
3088 ret = -EINVAL;
3089 }
3090
3091 wl1271_ps_elp_sleep(wl);
3092
3093out:
3094 mutex_unlock(&wl->mutex);
3095
3096 return ret;
3097}
3098
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003099/* can't be const, mac80211 writes to this */
3100static struct ieee80211_rate wl1271_rates[] = {
3101 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003102 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3103 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003104 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003105 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3106 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003107 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3108 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003109 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3110 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3112 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003113 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3114 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003115 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3116 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003117 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3118 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003119 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003120 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3121 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003122 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003123 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3124 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003125 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003126 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3127 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003128 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003129 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3130 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003132 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3133 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003134 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003135 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3136 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003138 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3139 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003140};
3141
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003142/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003144 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003145 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003146 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3147 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3148 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003149 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003150 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3151 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3152 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003153 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003154 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3155 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3156 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003157 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003158};
3159
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003160/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003161static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003162 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003163 7, /* CONF_HW_RXTX_RATE_MCS7 */
3164 6, /* CONF_HW_RXTX_RATE_MCS6 */
3165 5, /* CONF_HW_RXTX_RATE_MCS5 */
3166 4, /* CONF_HW_RXTX_RATE_MCS4 */
3167 3, /* CONF_HW_RXTX_RATE_MCS3 */
3168 2, /* CONF_HW_RXTX_RATE_MCS2 */
3169 1, /* CONF_HW_RXTX_RATE_MCS1 */
3170 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003171
3172 11, /* CONF_HW_RXTX_RATE_54 */
3173 10, /* CONF_HW_RXTX_RATE_48 */
3174 9, /* CONF_HW_RXTX_RATE_36 */
3175 8, /* CONF_HW_RXTX_RATE_24 */
3176
3177 /* TI-specific rate */
3178 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3179
3180 7, /* CONF_HW_RXTX_RATE_18 */
3181 6, /* CONF_HW_RXTX_RATE_12 */
3182 3, /* CONF_HW_RXTX_RATE_11 */
3183 5, /* CONF_HW_RXTX_RATE_9 */
3184 4, /* CONF_HW_RXTX_RATE_6 */
3185 2, /* CONF_HW_RXTX_RATE_5_5 */
3186 1, /* CONF_HW_RXTX_RATE_2 */
3187 0 /* CONF_HW_RXTX_RATE_1 */
3188};
3189
Shahar Levie8b03a22010-10-13 16:09:39 +02003190/* 11n STA capabilities */
3191#define HW_RX_HIGHEST_RATE 72
3192
Shahar Levi00d20102010-11-08 11:20:10 +00003193#ifdef CONFIG_WL12XX_HT
3194#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003195 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3196 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003197 .ht_supported = true, \
3198 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3199 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3200 .mcs = { \
3201 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3202 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3203 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3204 }, \
3205}
Shahar Levi18357852010-10-13 16:09:41 +02003206#else
Shahar Levi00d20102010-11-08 11:20:10 +00003207#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003208 .ht_supported = false, \
3209}
3210#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212/* can't be const, mac80211 writes to this */
3213static struct ieee80211_supported_band wl1271_band_2ghz = {
3214 .channels = wl1271_channels,
3215 .n_channels = ARRAY_SIZE(wl1271_channels),
3216 .bitrates = wl1271_rates,
3217 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003218 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219};
3220
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003221/* 5 GHz data rates for WL1273 */
3222static struct ieee80211_rate wl1271_rates_5ghz[] = {
3223 { .bitrate = 60,
3224 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3225 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3226 { .bitrate = 90,
3227 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3228 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3229 { .bitrate = 120,
3230 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3231 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3232 { .bitrate = 180,
3233 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3234 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3235 { .bitrate = 240,
3236 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3237 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3238 { .bitrate = 360,
3239 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3240 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3241 { .bitrate = 480,
3242 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3243 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3244 { .bitrate = 540,
3245 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3246 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3247};
3248
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003249/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003250static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003251 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003252 { .hw_value = 8, .center_freq = 5040},
3253 { .hw_value = 9, .center_freq = 5045},
3254 { .hw_value = 11, .center_freq = 5055},
3255 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003256 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003257 { .hw_value = 34, .center_freq = 5170},
3258 { .hw_value = 36, .center_freq = 5180},
3259 { .hw_value = 38, .center_freq = 5190},
3260 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003261 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003262 { .hw_value = 44, .center_freq = 5220},
3263 { .hw_value = 46, .center_freq = 5230},
3264 { .hw_value = 48, .center_freq = 5240},
3265 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003266 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003267 { .hw_value = 60, .center_freq = 5300},
3268 { .hw_value = 64, .center_freq = 5320},
3269 { .hw_value = 100, .center_freq = 5500},
3270 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003271 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003272 { .hw_value = 112, .center_freq = 5560},
3273 { .hw_value = 116, .center_freq = 5580},
3274 { .hw_value = 120, .center_freq = 5600},
3275 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003276 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003277 { .hw_value = 132, .center_freq = 5660},
3278 { .hw_value = 136, .center_freq = 5680},
3279 { .hw_value = 140, .center_freq = 5700},
3280 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003281 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003282 { .hw_value = 157, .center_freq = 5785},
3283 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003284 { .hw_value = 165, .center_freq = 5825},
3285};
3286
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003287/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003288static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003289 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003290 7, /* CONF_HW_RXTX_RATE_MCS7 */
3291 6, /* CONF_HW_RXTX_RATE_MCS6 */
3292 5, /* CONF_HW_RXTX_RATE_MCS5 */
3293 4, /* CONF_HW_RXTX_RATE_MCS4 */
3294 3, /* CONF_HW_RXTX_RATE_MCS3 */
3295 2, /* CONF_HW_RXTX_RATE_MCS2 */
3296 1, /* CONF_HW_RXTX_RATE_MCS1 */
3297 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003298
3299 7, /* CONF_HW_RXTX_RATE_54 */
3300 6, /* CONF_HW_RXTX_RATE_48 */
3301 5, /* CONF_HW_RXTX_RATE_36 */
3302 4, /* CONF_HW_RXTX_RATE_24 */
3303
3304 /* TI-specific rate */
3305 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3306
3307 3, /* CONF_HW_RXTX_RATE_18 */
3308 2, /* CONF_HW_RXTX_RATE_12 */
3309 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3310 1, /* CONF_HW_RXTX_RATE_9 */
3311 0, /* CONF_HW_RXTX_RATE_6 */
3312 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3313 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3314 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3315};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003316
3317static struct ieee80211_supported_band wl1271_band_5ghz = {
3318 .channels = wl1271_channels_5ghz,
3319 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3320 .bitrates = wl1271_rates_5ghz,
3321 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003322 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003323};
3324
Tobias Klausera0ea9492010-05-20 10:38:11 +02003325static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003326 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3327 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3328};
3329
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003330static const struct ieee80211_ops wl1271_ops = {
3331 .start = wl1271_op_start,
3332 .stop = wl1271_op_stop,
3333 .add_interface = wl1271_op_add_interface,
3334 .remove_interface = wl1271_op_remove_interface,
3335 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003336 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003337 .configure_filter = wl1271_op_configure_filter,
3338 .tx = wl1271_op_tx,
3339 .set_key = wl1271_op_set_key,
3340 .hw_scan = wl1271_op_hw_scan,
3341 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003342 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003343 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003344 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003345 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003346 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003347 .sta_add = wl1271_op_sta_add,
3348 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003349 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003350 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003351};
3352
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003353
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003354u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003355{
3356 u8 idx;
3357
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003358 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003359
3360 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3361 wl1271_error("Illegal RX rate from HW: %d", rate);
3362 return 0;
3363 }
3364
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003365 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003366 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3367 wl1271_error("Unsupported RX rate from HW: %d", rate);
3368 return 0;
3369 }
3370
3371 return idx;
3372}
3373
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003374static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3375 struct device_attribute *attr,
3376 char *buf)
3377{
3378 struct wl1271 *wl = dev_get_drvdata(dev);
3379 ssize_t len;
3380
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003381 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003382
3383 mutex_lock(&wl->mutex);
3384 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3385 wl->sg_enabled);
3386 mutex_unlock(&wl->mutex);
3387
3388 return len;
3389
3390}
3391
3392static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3393 struct device_attribute *attr,
3394 const char *buf, size_t count)
3395{
3396 struct wl1271 *wl = dev_get_drvdata(dev);
3397 unsigned long res;
3398 int ret;
3399
3400 ret = strict_strtoul(buf, 10, &res);
3401
3402 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>");