blob: 0c69e959d0dee5c9341b9698a76c509383c66192 [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 Nemtsov47684802011-04-26 23:21:51 +0300195 .max_tx_retries = 100,
196 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200199 [CONF_TX_AC_BE] = {
200 .queue_id = CONF_TX_AC_BE,
201 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300202 .tsid = CONF_TX_AC_BE,
203 .ps_scheme = CONF_PS_SCHEME_LEGACY,
204 .ack_policy = CONF_ACK_POLICY_LEGACY,
205 .apsd_conf = {0, 0},
206 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200207 [CONF_TX_AC_BK] = {
208 .queue_id = CONF_TX_AC_BK,
209 .channel_type = CONF_CHANNEL_TYPE_EDCF,
210 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300211 .ps_scheme = CONF_PS_SCHEME_LEGACY,
212 .ack_policy = CONF_ACK_POLICY_LEGACY,
213 .apsd_conf = {0, 0},
214 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_VI] = {
216 .queue_id = CONF_TX_AC_VI,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
218 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_VO] = {
224 .queue_id = CONF_TX_AC_VO,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
232 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200233 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300234 .tx_compl_threshold = 4,
235 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
236 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200237 .tmpl_short_retry_limit = 10,
238 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 },
240 .conn = {
241 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
244 .bcn_filt_ie_count = 1,
245 .bcn_filt_ie = {
246 [0] = {
247 .ie = WLAN_EID_CHANNEL_SWITCH,
248 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
249 }
250 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200251 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300252 .bss_lose_timeout = 100,
253 .beacon_rx_timeout = 10000,
254 .broadcast_timeout = 20000,
255 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300256 .ps_poll_threshold = 10,
257 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300258 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200259 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200261 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200262 .psm_entry_nullfunc_retries = 3,
263 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300264 .keep_alive_interval = 55000,
265 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300266 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200267 .itrim = {
268 .enable = false,
269 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200270 },
271 .pm_config = {
272 .host_clk_settling_time = 5000,
273 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 },
275 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300276 .trigger_pacing = 1,
277 .avg_weight_rssi_beacon = 20,
278 .avg_weight_rssi_data = 10,
279 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100280 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200281 },
282 .scan = {
283 .min_dwell_time_active = 7500,
284 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100285 .min_dwell_time_passive = 100000,
286 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200287 .num_probe_reqs = 2,
288 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200289 .rf = {
290 .tx_per_channel_power_compensation_2 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 },
293 .tx_per_channel_power_compensation_5 = {
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 },
298 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100299 .ht = {
300 .tx_ba_win_size = 64,
301 .inactivity_timeout = 10000,
302 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 70,
307 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200308 .dynamic_memory = 0,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200309 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200312 },
313 .mem_wl128x = {
314 .num_stations = 1,
315 .ssid_profiles = 1,
316 .rx_block_num = 40,
317 .tx_min_block_num = 40,
318 .dynamic_memory = 1,
319 .min_req_tx_blocks = 45,
320 .min_req_rx_blocks = 22,
321 .tx_min = 27,
322 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300323 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300324};
325
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200326static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200327static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200328
329
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200330static void wl1271_device_release(struct device *dev)
331{
332
333}
334
335static struct platform_device wl1271_device = {
336 .name = "wl1271",
337 .id = -1,
338
339 /* device model insists to have a release function */
340 .dev = {
341 .release = wl1271_device_release,
342 },
343};
344
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200345static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300346static LIST_HEAD(wl_list);
347
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300348static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
349 void *arg)
350{
351 struct net_device *dev = arg;
352 struct wireless_dev *wdev;
353 struct wiphy *wiphy;
354 struct ieee80211_hw *hw;
355 struct wl1271 *wl;
356 struct wl1271 *wl_temp;
357 int ret = 0;
358
359 /* Check that this notification is for us. */
360 if (what != NETDEV_CHANGE)
361 return NOTIFY_DONE;
362
363 wdev = dev->ieee80211_ptr;
364 if (wdev == NULL)
365 return NOTIFY_DONE;
366
367 wiphy = wdev->wiphy;
368 if (wiphy == NULL)
369 return NOTIFY_DONE;
370
371 hw = wiphy_priv(wiphy);
372 if (hw == NULL)
373 return NOTIFY_DONE;
374
375 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200376 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300377 list_for_each_entry(wl, &wl_list, list) {
378 if (wl == wl_temp)
379 break;
380 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200381 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300382 if (wl != wl_temp)
383 return NOTIFY_DONE;
384
385 mutex_lock(&wl->mutex);
386
387 if (wl->state == WL1271_STATE_OFF)
388 goto out;
389
390 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
391 goto out;
392
Ido Yariva6208652011-03-01 15:14:41 +0200393 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300394 if (ret < 0)
395 goto out;
396
397 if ((dev->operstate == IF_OPER_UP) &&
398 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
399 wl1271_cmd_set_sta_state(wl);
400 wl1271_info("Association completed.");
401 }
402
403 wl1271_ps_elp_sleep(wl);
404
405out:
406 mutex_unlock(&wl->mutex);
407
408 return NOTIFY_OK;
409}
410
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100411static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200412 struct regulatory_request *request)
413{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100414 struct ieee80211_supported_band *band;
415 struct ieee80211_channel *ch;
416 int i;
417
418 band = wiphy->bands[IEEE80211_BAND_5GHZ];
419 for (i = 0; i < band->n_channels; i++) {
420 ch = &band->channels[i];
421 if (ch->flags & IEEE80211_CHAN_DISABLED)
422 continue;
423
424 if (ch->flags & IEEE80211_CHAN_RADAR)
425 ch->flags |= IEEE80211_CHAN_NO_IBSS |
426 IEEE80211_CHAN_PASSIVE_SCAN;
427
428 }
429
430 return 0;
431}
432
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300433static void wl1271_conf_init(struct wl1271 *wl)
434{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300435
436 /*
437 * This function applies the default configuration to the driver. This
438 * function is invoked upon driver load (spi probe.)
439 *
440 * The configuration is stored in a run-time structure in order to
441 * facilitate for run-time adjustment of any of the parameters. Making
442 * changes to the configuration structure will apply the new values on
443 * the next interface up (wl1271_op_start.)
444 */
445
446 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300447 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300448}
449
450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300451static int wl1271_plt_init(struct wl1271 *wl)
452{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200453 struct conf_tx_ac_category *conf_ac;
454 struct conf_tx_tid *conf_tid;
455 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300456
Shahar Levi49d750ca2011-03-06 16:32:09 +0200457 if (wl->chip.id == CHIP_ID_1283_PG20)
458 ret = wl128x_cmd_general_parms(wl);
459 else
460 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200461 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200462 return ret;
463
Shahar Levi49d750ca2011-03-06 16:32:09 +0200464 if (wl->chip.id == CHIP_ID_1283_PG20)
465 ret = wl128x_cmd_radio_parms(wl);
466 else
467 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200468 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200469 return ret;
470
Shahar Levi49d750ca2011-03-06 16:32:09 +0200471 if (wl->chip.id != CHIP_ID_1283_PG20) {
472 ret = wl1271_cmd_ext_radio_parms(wl);
473 if (ret < 0)
474 return ret;
475 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200476 if (ret < 0)
477 return ret;
478
Shahar Levi48a61472011-03-06 16:32:08 +0200479 /* Chip-specific initializations */
480 ret = wl1271_chip_specific_init(wl);
481 if (ret < 0)
482 return ret;
483
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200484 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200485 if (ret < 0)
486 return ret;
487
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300488 ret = wl1271_acx_init_mem_config(wl);
489 if (ret < 0)
490 return ret;
491
Luciano Coelho12419cc2010-02-18 13:25:44 +0200492 /* PHY layer config */
493 ret = wl1271_init_phy_config(wl);
494 if (ret < 0)
495 goto out_free_memmap;
496
497 ret = wl1271_acx_dco_itrim_params(wl);
498 if (ret < 0)
499 goto out_free_memmap;
500
501 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200502 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200503 if (ret < 0)
504 goto out_free_memmap;
505
506 /* Bluetooth WLAN coexistence */
507 ret = wl1271_init_pta(wl);
508 if (ret < 0)
509 goto out_free_memmap;
510
511 /* Energy detection */
512 ret = wl1271_init_energy_detection(wl);
513 if (ret < 0)
514 goto out_free_memmap;
515
Gery Kahn1ec610e2011-02-01 03:03:08 -0600516 ret = wl1271_acx_sta_mem_cfg(wl);
517 if (ret < 0)
518 goto out_free_memmap;
519
Luciano Coelho12419cc2010-02-18 13:25:44 +0200520 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100521 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200522 if (ret < 0)
523 goto out_free_memmap;
524
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200525 /* Default TID/AC configuration */
526 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200527 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200528 conf_ac = &wl->conf.tx.ac_conf[i];
529 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
530 conf_ac->cw_max, conf_ac->aifsn,
531 conf_ac->tx_op_limit);
532 if (ret < 0)
533 goto out_free_memmap;
534
Luciano Coelho12419cc2010-02-18 13:25:44 +0200535 conf_tid = &wl->conf.tx.tid_conf[i];
536 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
537 conf_tid->channel_type,
538 conf_tid->tsid,
539 conf_tid->ps_scheme,
540 conf_tid->ack_policy,
541 conf_tid->apsd_conf[0],
542 conf_tid->apsd_conf[1]);
543 if (ret < 0)
544 goto out_free_memmap;
545 }
546
Luciano Coelho12419cc2010-02-18 13:25:44 +0200547 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200548 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200550 goto out_free_memmap;
551
552 /* Configure for CAM power saving (ie. always active) */
553 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
554 if (ret < 0)
555 goto out_free_memmap;
556
557 /* configure PM */
558 ret = wl1271_acx_pm_config(wl);
559 if (ret < 0)
560 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561
562 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200563
564 out_free_memmap:
565 kfree(wl->target_mem_map);
566 wl->target_mem_map = NULL;
567
568 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569}
570
Arik Nemtsovb622d992011-02-23 00:22:31 +0200571static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
572{
573 bool fw_ps;
574
575 /* only regulate station links */
576 if (hlid < WL1271_AP_STA_HLID_START)
577 return;
578
579 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
580
581 /*
582 * Wake up from high level PS if the STA is asleep with too little
583 * blocks in FW or if the STA is awake.
584 */
585 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
586 wl1271_ps_link_end(wl, hlid);
587
588 /* Start high-level PS if the STA is asleep with enough blocks in FW */
589 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
590 wl1271_ps_link_start(wl, hlid, true);
591}
592
593static void wl1271_irq_update_links_status(struct wl1271 *wl,
594 struct wl1271_fw_ap_status *status)
595{
596 u32 cur_fw_ps_map;
597 u8 hlid;
598
599 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
600 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
601 wl1271_debug(DEBUG_PSM,
602 "link ps prev 0x%x cur 0x%x changed 0x%x",
603 wl->ap_fw_ps_map, cur_fw_ps_map,
604 wl->ap_fw_ps_map ^ cur_fw_ps_map);
605
606 wl->ap_fw_ps_map = cur_fw_ps_map;
607 }
608
609 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
610 u8 cnt = status->tx_lnk_free_blks[hlid] -
611 wl->links[hlid].prev_freed_blks;
612
613 wl->links[hlid].prev_freed_blks =
614 status->tx_lnk_free_blks[hlid];
615 wl->links[hlid].allocated_blks -= cnt;
616
617 wl1271_irq_ps_regulate_link(wl, hlid,
618 wl->links[hlid].allocated_blks);
619 }
620}
621
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300622static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200623 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300624{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200625 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200626 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200627 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200628 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629 int i;
630
Shahar Levi13b107d2011-03-06 16:32:12 +0200631 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200632 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
633 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200634 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200635 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
636 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200637 }
638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
640 "drv_rx_counter = %d, tx_results_counter = %d)",
641 status->intr,
642 status->fw_rx_counter,
643 status->drv_rx_counter,
644 status->tx_results_counter);
645
646 /* update number of available TX blocks */
647 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200648 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
649 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300650
651 wl->tx_blocks_freed[i] =
652 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200653 }
654
Ido Yarivd2f4d472011-03-31 10:07:00 +0200655 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200656
Ido Yarivd2f4d472011-03-31 10:07:00 +0200657 if (wl->bss_type == BSS_TYPE_AP_BSS) {
658 /* Update num of allocated TX blocks per link and ps status */
659 wl1271_irq_update_links_status(wl, &full_status->ap);
660 wl->tx_blocks_available += freed_blocks;
661 } else {
662 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
663
664 /*
665 * The FW might change the total number of TX memblocks before
666 * we get a notification about blocks being released. Thus, the
667 * available blocks calculation might yield a temporary result
668 * which is lower than the actual available blocks. Keeping in
669 * mind that only blocks that were allocated can be moved from
670 * TX to RX, tx_blocks_available should never decrease here.
671 */
672 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
673 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674 }
675
Ido Yariva5225502010-10-12 14:49:10 +0200676 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200677 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200678 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679
680 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200681 getnstimeofday(&ts);
682 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
683 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684}
685
Ido Yariva6208652011-03-01 15:14:41 +0200686static void wl1271_flush_deferred_work(struct wl1271 *wl)
687{
688 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200689
Ido Yariva6208652011-03-01 15:14:41 +0200690 /* Pass all received frames to the network stack */
691 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
692 ieee80211_rx_ni(wl->hw, skb);
693
694 /* Return sent skbs to the network stack */
695 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
696 ieee80211_tx_status(wl->hw, skb);
697}
698
699static void wl1271_netstack_work(struct work_struct *work)
700{
701 struct wl1271 *wl =
702 container_of(work, struct wl1271, netstack_work);
703
704 do {
705 wl1271_flush_deferred_work(wl);
706 } while (skb_queue_len(&wl->deferred_rx_queue));
707}
708
709#define WL1271_IRQ_MAX_LOOPS 256
710
711irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300714 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200715 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200716 struct wl1271 *wl = (struct wl1271 *)cookie;
717 bool done = false;
718 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200719 unsigned long flags;
720
721 /* TX might be handled here, avoid redundant work */
722 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
723 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724
Ido Yariv341b7cd2011-03-31 10:07:01 +0200725 /*
726 * In case edge triggered interrupt must be used, we cannot iterate
727 * more than once without introducing race conditions with the hardirq.
728 */
729 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
730 loopcount = 1;
731
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 mutex_lock(&wl->mutex);
733
734 wl1271_debug(DEBUG_IRQ, "IRQ work");
735
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200736 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737 goto out;
738
Ido Yariva6208652011-03-01 15:14:41 +0200739 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740 if (ret < 0)
741 goto out;
742
Ido Yariva6208652011-03-01 15:14:41 +0200743 while (!done && loopcount--) {
744 /*
745 * In order to avoid a race with the hardirq, clear the flag
746 * before acknowledging the chip. Since the mutex is held,
747 * wl1271_ps_elp_wakeup cannot be called concurrently.
748 */
749 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
750 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200751
752 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200753 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200754 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200755 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200756 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200757 continue;
758 }
759
Eliad Pellerccc83b02010-10-27 14:09:57 +0200760 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
761 wl1271_error("watchdog interrupt received! "
762 "starting recovery.");
763 ieee80211_queue_work(wl->hw, &wl->recovery_work);
764
765 /* restarting the chip. ignore any other interrupt. */
766 goto out;
767 }
768
Ido Yariva6208652011-03-01 15:14:41 +0200769 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200770 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
771
Ido Yariv8aad2462011-03-01 15:14:38 +0200772 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200773
Ido Yariva5225502010-10-12 14:49:10 +0200774 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200775 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200776 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200777 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200778 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200779 /*
780 * In order to avoid starvation of the TX path,
781 * call the work function directly.
782 */
783 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200784 } else {
785 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200786 }
787
Ido Yariv8aad2462011-03-01 15:14:38 +0200788 /* check for tx results */
789 if (wl->fw_status->common.tx_results_counter !=
790 (wl->tx_results_count & 0xff))
791 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200792
793 /* Make sure the deferred queues don't get too long */
794 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
795 skb_queue_len(&wl->deferred_rx_queue);
796 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
797 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200798 }
799
800 if (intr & WL1271_ACX_INTR_EVENT_A) {
801 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
802 wl1271_event_handle(wl, 0);
803 }
804
805 if (intr & WL1271_ACX_INTR_EVENT_B) {
806 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
807 wl1271_event_handle(wl, 1);
808 }
809
810 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
811 wl1271_debug(DEBUG_IRQ,
812 "WL1271_ACX_INTR_INIT_COMPLETE");
813
814 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
815 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 }
817
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818 wl1271_ps_elp_sleep(wl);
819
820out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200821 spin_lock_irqsave(&wl->wl_lock, flags);
822 /* In case TX was not handled here, queue TX work */
823 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
824 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
825 wl->tx_queue_count)
826 ieee80211_queue_work(wl->hw, &wl->tx_work);
827 spin_unlock_irqrestore(&wl->wl_lock, flags);
828
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300829 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200830
831 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832}
Ido Yariva6208652011-03-01 15:14:41 +0200833EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300835static int wl1271_fetch_firmware(struct wl1271 *wl)
836{
837 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200838 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 int ret;
840
Arik Nemtsov166d5042010-10-16 21:44:57 +0200841 switch (wl->bss_type) {
842 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200843 if (wl->chip.id == CHIP_ID_1283_PG20)
844 fw_name = WL128X_AP_FW_NAME;
845 else
846 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200847 break;
848 case BSS_TYPE_IBSS:
849 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200850 if (wl->chip.id == CHIP_ID_1283_PG20)
851 fw_name = WL128X_FW_NAME;
852 else
853 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200854 break;
855 default:
856 wl1271_error("no compatible firmware for bss_type %d",
857 wl->bss_type);
858 return -EINVAL;
859 }
860
861 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
862
863 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864
865 if (ret < 0) {
866 wl1271_error("could not get firmware: %d", ret);
867 return ret;
868 }
869
870 if (fw->size % 4) {
871 wl1271_error("firmware size is not multiple of 32 bits: %zu",
872 fw->size);
873 ret = -EILSEQ;
874 goto out;
875 }
876
Arik Nemtsov166d5042010-10-16 21:44:57 +0200877 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300879 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880
881 if (!wl->fw) {
882 wl1271_error("could not allocate memory for the firmware");
883 ret = -ENOMEM;
884 goto out;
885 }
886
887 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200888 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889 ret = 0;
890
891out:
892 release_firmware(fw);
893
894 return ret;
895}
896
897static int wl1271_fetch_nvs(struct wl1271 *wl)
898{
899 const struct firmware *fw;
900 int ret;
901
Shahar Levi5aa42342011-03-06 16:32:07 +0200902 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300903
904 if (ret < 0) {
905 wl1271_error("could not get nvs file: %d", ret);
906 return ret;
907 }
908
Shahar Levibc765bf2011-03-06 16:32:10 +0200909 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300910
911 if (!wl->nvs) {
912 wl1271_error("could not allocate memory for the nvs file");
913 ret = -ENOMEM;
914 goto out;
915 }
916
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200917 wl->nvs_len = fw->size;
918
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919out:
920 release_firmware(fw);
921
922 return ret;
923}
924
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200925static void wl1271_recovery_work(struct work_struct *work)
926{
927 struct wl1271 *wl =
928 container_of(work, struct wl1271, recovery_work);
929
930 mutex_lock(&wl->mutex);
931
932 if (wl->state != WL1271_STATE_ON)
933 goto out;
934
935 wl1271_info("Hardware recovery in progress.");
936
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200937 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
938 ieee80211_connection_loss(wl->vif);
939
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200940 /* reboot the chipset */
941 __wl1271_op_remove_interface(wl);
942 ieee80211_restart_hw(wl->hw);
943
944out:
945 mutex_unlock(&wl->mutex);
946}
947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948static void wl1271_fw_wakeup(struct wl1271 *wl)
949{
950 u32 elp_reg;
951
952 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300953 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954}
955
956static int wl1271_setup(struct wl1271 *wl)
957{
958 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
959 if (!wl->fw_status)
960 return -ENOMEM;
961
962 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
963 if (!wl->tx_res_if) {
964 kfree(wl->fw_status);
965 return -ENOMEM;
966 }
967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 return 0;
969}
970
971static int wl1271_chip_wakeup(struct wl1271 *wl)
972{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300973 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 int ret = 0;
975
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200976 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200977 ret = wl1271_power_on(wl);
978 if (ret < 0)
979 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200981 wl1271_io_reset(wl);
982 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983
984 /* We don't need a real memory partition here, because we only want
985 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300986 memset(&partition, 0, sizeof(partition));
987 partition.reg.start = REGISTERS_BASE;
988 partition.reg.size = REGISTERS_DOWN_SIZE;
989 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990
991 /* ELP module wake up */
992 wl1271_fw_wakeup(wl);
993
994 /* whal_FwCtrl_BootSm() */
995
996 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200997 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998
999 /* 1. check if chip id is valid */
1000
1001 switch (wl->chip.id) {
1002 case CHIP_ID_1271_PG10:
1003 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1004 wl->chip.id);
1005
1006 ret = wl1271_setup(wl);
1007 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 break;
1010 case CHIP_ID_1271_PG20:
1011 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1012 wl->chip.id);
1013
1014 ret = wl1271_setup(wl);
1015 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001016 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001018 case CHIP_ID_1283_PG20:
1019 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1020 wl->chip.id);
1021
1022 ret = wl1271_setup(wl);
1023 if (ret < 0)
1024 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001025 if (wl1271_set_block_size(wl))
1026 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001027 break;
1028 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001030 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001032 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 }
1034
Arik Nemtsov166d5042010-10-16 21:44:57 +02001035 /* Make sure the firmware type matches the BSS type */
1036 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 ret = wl1271_fetch_firmware(wl);
1038 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001039 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
1042 /* No NVS from netlink, try to get it from the filesystem */
1043 if (wl->nvs == NULL) {
1044 ret = wl1271_fetch_nvs(wl);
1045 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001046 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 }
1048
1049out:
1050 return ret;
1051}
1052
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001053static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1054{
1055 unsigned int quirks = 0;
1056 unsigned int *fw_ver = wl->chip.fw_ver;
1057
1058 /* Only for wl127x */
1059 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1060 /* Check STA version */
1061 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1062 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1063 /* Check AP version */
1064 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1065 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1066 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1067
1068 return quirks;
1069}
1070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071int wl1271_plt_start(struct wl1271 *wl)
1072{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001073 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074 int ret;
1075
1076 mutex_lock(&wl->mutex);
1077
1078 wl1271_notice("power up");
1079
1080 if (wl->state != WL1271_STATE_OFF) {
1081 wl1271_error("cannot go into PLT state because not "
1082 "in off state: %d", wl->state);
1083 ret = -EBUSY;
1084 goto out;
1085 }
1086
Arik Nemtsov166d5042010-10-16 21:44:57 +02001087 wl->bss_type = BSS_TYPE_STA_BSS;
1088
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001089 while (retries) {
1090 retries--;
1091 ret = wl1271_chip_wakeup(wl);
1092 if (ret < 0)
1093 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001095 ret = wl1271_boot(wl);
1096 if (ret < 0)
1097 goto power_off;
1098
1099 ret = wl1271_plt_init(wl);
1100 if (ret < 0)
1101 goto irq_disable;
1102
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001103 wl->state = WL1271_STATE_PLT;
1104 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001105 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001106
1107 /* Check if any quirks are needed with older fw versions */
1108 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 goto out;
1110
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001111irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001112 mutex_unlock(&wl->mutex);
1113 /* Unlocking the mutex in the middle of handling is
1114 inherently unsafe. In this case we deem it safe to do,
1115 because we need to let any possibly pending IRQ out of
1116 the system (and while we are WL1271_STATE_OFF the IRQ
1117 work function will not do anything.) Also, any other
1118 possible concurrent operations will fail due to the
1119 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001120 wl1271_disable_interrupts(wl);
1121 wl1271_flush_deferred_work(wl);
1122 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001123 mutex_lock(&wl->mutex);
1124power_off:
1125 wl1271_power_off(wl);
1126 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001127
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001128 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1129 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130out:
1131 mutex_unlock(&wl->mutex);
1132
1133 return ret;
1134}
1135
Luciano Coelho4623ec72011-03-21 19:26:41 +02001136static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137{
1138 int ret = 0;
1139
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140 wl1271_notice("power down");
1141
1142 if (wl->state != WL1271_STATE_PLT) {
1143 wl1271_error("cannot power down because not in PLT "
1144 "state: %d", wl->state);
1145 ret = -EBUSY;
1146 goto out;
1147 }
1148
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001149 wl1271_power_off(wl);
1150
1151 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001152 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001155 wl1271_disable_interrupts(wl);
1156 wl1271_flush_deferred_work(wl);
1157 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001158 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001159 mutex_lock(&wl->mutex);
1160out:
1161 return ret;
1162}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001163
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001164int wl1271_plt_stop(struct wl1271 *wl)
1165{
1166 int ret;
1167
1168 mutex_lock(&wl->mutex);
1169 ret = __wl1271_plt_stop(wl);
1170 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001171 return ret;
1172}
1173
Johannes Berg7bb45682011-02-24 14:42:06 +01001174static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175{
1176 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001177 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001178 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001179 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001180
Ido Yarivb07d4032011-03-01 15:14:43 +02001181 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1182
1183 if (wl->bss_type == BSS_TYPE_AP_BSS)
1184 hlid = wl1271_tx_get_hlid(skb);
1185
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001186 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001187
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001188 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001189
1190 /*
1191 * The workqueue is slow to process the tx_queue and we need stop
1192 * the queue here, otherwise the queue will get too long.
1193 */
1194 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1195 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1196 ieee80211_stop_queues(wl->hw);
1197 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1198 }
1199
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001200 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001201 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001202 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1203 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1204 } else {
1205 skb_queue_tail(&wl->tx_queue[q], skb);
1206 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207
1208 /*
1209 * The chip specific setup must run before the first TX packet -
1210 * before that, the tx_work will not be initialized!
1211 */
1212
Ido Yarivb07d4032011-03-01 15:14:43 +02001213 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1214 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001215 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001216
1217 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
Shahar Leviae47c452011-03-06 16:32:14 +02001220int wl1271_tx_dummy_packet(struct wl1271 *wl)
1221{
Ido Yariv990f5de2011-03-31 10:06:59 +02001222 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001223
Ido Yariv990f5de2011-03-31 10:06:59 +02001224 spin_lock_irqsave(&wl->wl_lock, flags);
1225 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1226 wl->tx_queue_count++;
1227 spin_unlock_irqrestore(&wl->wl_lock, flags);
1228
1229 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1230 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1231 wl1271_tx_work_locked(wl);
1232
1233 /*
1234 * If the FW TX is busy, TX work will be scheduled by the threaded
1235 * interrupt handler function
1236 */
1237 return 0;
1238}
1239
1240/*
1241 * The size of the dummy packet should be at least 1400 bytes. However, in
1242 * order to minimize the number of bus transactions, aligning it to 512 bytes
1243 * boundaries could be beneficial, performance wise
1244 */
1245#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1246
Luciano Coelhocf27d862011-04-01 21:08:23 +03001247static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001248{
1249 struct sk_buff *skb;
1250 struct ieee80211_hdr_3addr *hdr;
1251 unsigned int dummy_packet_size;
1252
1253 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1254 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1255
1256 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001257 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001258 wl1271_warning("Failed to allocate a dummy packet skb");
1259 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001260 }
1261
1262 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1263
1264 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1265 memset(hdr, 0, sizeof(*hdr));
1266 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001267 IEEE80211_STYPE_NULLFUNC |
1268 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001269
Ido Yariv990f5de2011-03-31 10:06:59 +02001270 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001271
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001272 /* Dummy packets require the TID to be management */
1273 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001274
1275 /* Initialize all fields that might be used */
Shahar Leviae47c452011-03-06 16:32:14 +02001276 skb->queue_mapping = 0;
Ido Yariv990f5de2011-03-31 10:06:59 +02001277 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001278
Ido Yariv990f5de2011-03-31 10:06:59 +02001279 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001280}
1281
Ido Yariv990f5de2011-03-31 10:06:59 +02001282
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001283static struct notifier_block wl1271_dev_notifier = {
1284 .notifier_call = wl1271_dev_notify,
1285};
1286
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287static int wl1271_op_start(struct ieee80211_hw *hw)
1288{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001289 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1290
1291 /*
1292 * We have to delay the booting of the hardware because
1293 * we need to know the local MAC address before downloading and
1294 * initializing the firmware. The MAC address cannot be changed
1295 * after boot, and without the proper MAC address, the firmware
1296 * will not function properly.
1297 *
1298 * The MAC address is first known when the corresponding interface
1299 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001300 *
1301 * In addition, we currently have different firmwares for AP and managed
1302 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001303 */
1304
1305 return 0;
1306}
1307
1308static void wl1271_op_stop(struct ieee80211_hw *hw)
1309{
1310 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1311}
1312
1313static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1314 struct ieee80211_vif *vif)
1315{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001317 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001318 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001320 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001322 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1323 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324
1325 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001326 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001327 wl1271_debug(DEBUG_MAC80211,
1328 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001329 ret = -EBUSY;
1330 goto out;
1331 }
1332
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001333 /*
1334 * in some very corner case HW recovery scenarios its possible to
1335 * get here before __wl1271_op_remove_interface is complete, so
1336 * opt out if that is the case.
1337 */
1338 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1339 ret = -EBUSY;
1340 goto out;
1341 }
1342
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001343 switch (vif->type) {
1344 case NL80211_IFTYPE_STATION:
1345 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001346 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001347 break;
1348 case NL80211_IFTYPE_ADHOC:
1349 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001350 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001351 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001352 case NL80211_IFTYPE_AP:
1353 wl->bss_type = BSS_TYPE_AP_BSS;
1354 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001355 default:
1356 ret = -EOPNOTSUPP;
1357 goto out;
1358 }
1359
1360 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361
1362 if (wl->state != WL1271_STATE_OFF) {
1363 wl1271_error("cannot start because not in off state: %d",
1364 wl->state);
1365 ret = -EBUSY;
1366 goto out;
1367 }
1368
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369 while (retries) {
1370 retries--;
1371 ret = wl1271_chip_wakeup(wl);
1372 if (ret < 0)
1373 goto power_off;
1374
1375 ret = wl1271_boot(wl);
1376 if (ret < 0)
1377 goto power_off;
1378
1379 ret = wl1271_hw_init(wl);
1380 if (ret < 0)
1381 goto irq_disable;
1382
Eliad Peller71125ab2010-10-28 21:46:43 +02001383 booted = true;
1384 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001386irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 mutex_unlock(&wl->mutex);
1388 /* Unlocking the mutex in the middle of handling is
1389 inherently unsafe. In this case we deem it safe to do,
1390 because we need to let any possibly pending IRQ out of
1391 the system (and while we are WL1271_STATE_OFF the IRQ
1392 work function will not do anything.) Also, any other
1393 possible concurrent operations will fail due to the
1394 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001395 wl1271_disable_interrupts(wl);
1396 wl1271_flush_deferred_work(wl);
1397 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001398 mutex_lock(&wl->mutex);
1399power_off:
1400 wl1271_power_off(wl);
1401 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
Eliad Peller71125ab2010-10-28 21:46:43 +02001403 if (!booted) {
1404 wl1271_error("firmware boot failed despite %d retries",
1405 WL1271_BOOT_RETRIES);
1406 goto out;
1407 }
1408
1409 wl->vif = vif;
1410 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001411 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001412 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001413
1414 /* update hw/fw version info in wiphy struct */
1415 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001416 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001417 sizeof(wiphy->fw_version));
1418
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001419 /* Check if any quirks are needed with older fw versions */
1420 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1421
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001422 /*
1423 * Now we know if 11a is supported (info from the NVS), so disable
1424 * 11a channels if not supported
1425 */
1426 if (!wl->enable_11a)
1427 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1428
1429 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1430 wl->enable_11a ? "" : "not ");
1431
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001432out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001433 mutex_unlock(&wl->mutex);
1434
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001435 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001436 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001437 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001438 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001440 return ret;
1441}
1442
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001443static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445 int i;
1446
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001447 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001449 /* because of hardware recovery, we may get here twice */
1450 if (wl->state != WL1271_STATE_ON)
1451 return;
1452
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001453 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001455 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001456 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001457 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001458
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001459 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001460 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001461 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001462
Luciano Coelho08688d62010-07-08 17:50:07 +03001463 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001464 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001465 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001466 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001467 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 }
1469
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001470 /*
1471 * this must be before the cancel_work calls below, so that the work
1472 * functions don't perform further work.
1473 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 wl->state = WL1271_STATE_OFF;
1475
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476 mutex_unlock(&wl->mutex);
1477
Ido Yariva6208652011-03-01 15:14:41 +02001478 wl1271_disable_interrupts(wl);
1479 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001480 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001481 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001483 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001484 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485
1486 mutex_lock(&wl->mutex);
1487
1488 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001489 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001490 wl1271_power_off(wl);
1491
1492 memset(wl->bssid, 0, ETH_ALEN);
1493 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1494 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001496 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001497 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498
1499 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001500 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1502 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001503 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 wl->tx_results_count = 0;
1505 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001506 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001507 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 wl->time_offset = 0;
1509 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001510 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001511 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001512 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001513 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001514 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001515 wl->ap_fw_ps_map = 0;
1516 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001517
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001518 /*
1519 * this is performed after the cancel_work calls and the associated
1520 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1521 * get executed before all these vars have been reset.
1522 */
1523 wl->flags = 0;
1524
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001525 for (i = 0; i < NUM_TX_QUEUES; i++)
1526 wl->tx_blocks_freed[i] = 0;
1527
1528 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001529
1530 kfree(wl->fw_status);
1531 wl->fw_status = NULL;
1532 kfree(wl->tx_res_if);
1533 wl->tx_res_if = NULL;
1534 kfree(wl->target_mem_map);
1535 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001536}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001537
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001538static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1539 struct ieee80211_vif *vif)
1540{
1541 struct wl1271 *wl = hw->priv;
1542
1543 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001544 /*
1545 * wl->vif can be null here if someone shuts down the interface
1546 * just when hardware recovery has been started.
1547 */
1548 if (wl->vif) {
1549 WARN_ON(wl->vif != vif);
1550 __wl1271_op_remove_interface(wl);
1551 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001552
Juuso Oikarinen67353292010-11-18 15:19:02 +02001553 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001554 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001555}
1556
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001557void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001558{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001559 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001560
1561 /* combine requested filters with current filter config */
1562 filters = wl->filters | filters;
1563
1564 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1565
1566 if (filters & FIF_PROMISC_IN_BSS) {
1567 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1568 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1569 wl->rx_config |= CFG_BSSID_FILTER_EN;
1570 }
1571 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1572 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1573 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1574 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1575 }
1576 if (filters & FIF_OTHER_BSS) {
1577 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1578 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1579 }
1580 if (filters & FIF_CONTROL) {
1581 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1582 wl->rx_filter |= CFG_RX_CTL_EN;
1583 }
1584 if (filters & FIF_FCSFAIL) {
1585 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1586 wl->rx_filter |= CFG_RX_FCS_ERROR;
1587 }
1588}
1589
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001590static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001591{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001592 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001593 /* we need to use a dummy BSSID for now */
1594 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1595 0xad, 0xbe, 0xef };
1596
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001597 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1598
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001599 /* pass through frames from all BSS */
1600 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1601
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001602 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001603 if (ret < 0)
1604 goto out;
1605
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001606 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001607
1608out:
1609 return ret;
1610}
1611
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001612static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001613{
1614 int ret;
1615
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001616 /*
1617 * One of the side effects of the JOIN command is that is clears
1618 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1619 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001620 * Currently the only valid scenario for JOIN during association
1621 * is on roaming, in which case we will also be given new keys.
1622 * Keep the below message for now, unless it starts bothering
1623 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001624 */
1625 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1626 wl1271_info("JOIN while associated.");
1627
1628 if (set_assoc)
1629 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1630
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001631 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1632 if (ret < 0)
1633 goto out;
1634
1635 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1636
1637 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1638 goto out;
1639
1640 /*
1641 * The join command disable the keep-alive mode, shut down its process,
1642 * and also clear the template config, so we need to reset it all after
1643 * the join. The acx_aid starts the keep-alive process, and the order
1644 * of the commands below is relevant.
1645 */
1646 ret = wl1271_acx_keep_alive_mode(wl, true);
1647 if (ret < 0)
1648 goto out;
1649
1650 ret = wl1271_acx_aid(wl, wl->aid);
1651 if (ret < 0)
1652 goto out;
1653
1654 ret = wl1271_cmd_build_klv_null_data(wl);
1655 if (ret < 0)
1656 goto out;
1657
1658 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1659 ACX_KEEP_ALIVE_TPL_VALID);
1660 if (ret < 0)
1661 goto out;
1662
1663out:
1664 return ret;
1665}
1666
1667static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001668{
1669 int ret;
1670
1671 /* to stop listening to a channel, we disconnect */
1672 ret = wl1271_cmd_disconnect(wl);
1673 if (ret < 0)
1674 goto out;
1675
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001676 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001677 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001678
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001679 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001680 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001681
1682out:
1683 return ret;
1684}
1685
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001686static void wl1271_set_band_rate(struct wl1271 *wl)
1687{
1688 if (wl->band == IEEE80211_BAND_2GHZ)
1689 wl->basic_rate_set = wl->conf.tx.basic_rate;
1690 else
1691 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1692}
1693
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001694static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001695{
1696 int ret;
1697
1698 if (idle) {
1699 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1700 ret = wl1271_unjoin(wl);
1701 if (ret < 0)
1702 goto out;
1703 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001704 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001705 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001706 if (ret < 0)
1707 goto out;
1708 ret = wl1271_acx_keep_alive_config(
1709 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1710 ACX_KEEP_ALIVE_TPL_INVALID);
1711 if (ret < 0)
1712 goto out;
1713 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1714 } else {
1715 /* increment the session counter */
1716 wl->session_counter++;
1717 if (wl->session_counter >= SESSION_COUNTER_MAX)
1718 wl->session_counter = 0;
1719 ret = wl1271_dummy_join(wl);
1720 if (ret < 0)
1721 goto out;
1722 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1723 }
1724
1725out:
1726 return ret;
1727}
1728
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1730{
1731 struct wl1271 *wl = hw->priv;
1732 struct ieee80211_conf *conf = &hw->conf;
1733 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001734 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001735
1736 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1737
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001738 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1739 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001740 channel,
1741 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001742 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001743 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1744 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001745
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001746 /*
1747 * mac80211 will go to idle nearly immediately after transmitting some
1748 * frames, such as the deauth. To make sure those frames reach the air,
1749 * wait here until the TX queue is fully flushed.
1750 */
1751 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1752 (conf->flags & IEEE80211_CONF_IDLE))
1753 wl1271_tx_flush(wl);
1754
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755 mutex_lock(&wl->mutex);
1756
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001757 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001758 /* we support configuring the channel and band while off */
1759 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1760 wl->band = conf->channel->band;
1761 wl->channel = channel;
1762 }
1763
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001764 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001765 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001766
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001767 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1768
Ido Yariva6208652011-03-01 15:14:41 +02001769 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 if (ret < 0)
1771 goto out;
1772
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001773 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001774 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1775 ((wl->band != conf->channel->band) ||
1776 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001777 wl->band = conf->channel->band;
1778 wl->channel = channel;
1779
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001780 if (!is_ap) {
1781 /*
1782 * FIXME: the mac80211 should really provide a fixed
1783 * rate to use here. for now, just use the smallest
1784 * possible rate for the band as a fixed rate for
1785 * association frames and other control messages.
1786 */
1787 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1788 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001789
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001790 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1791 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001792 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001793 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001794 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001795
1796 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1797 ret = wl1271_join(wl, false);
1798 if (ret < 0)
1799 wl1271_warning("cmd join on channel "
1800 "failed %d", ret);
1801 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001802 }
1803 }
1804
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001805 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1806 ret = wl1271_sta_handle_idle(wl,
1807 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001808 if (ret < 0)
1809 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 }
1811
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001812 /*
1813 * if mac80211 changes the PSM mode, make sure the mode is not
1814 * incorrectly changed after the pspoll failure active window.
1815 */
1816 if (changed & IEEE80211_CONF_CHANGE_PS)
1817 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1818
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001819 if (conf->flags & IEEE80211_CONF_PS &&
1820 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1821 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822
1823 /*
1824 * We enter PSM only if we're already associated.
1825 * If we're not, we'll enter it when joining an SSID,
1826 * through the bss_info_changed() hook.
1827 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001828 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001829 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001830 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001831 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001832 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001834 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001835 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001837 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001838
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001839 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001840 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001841 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 }
1843
1844 if (conf->power_level != wl->power_level) {
1845 ret = wl1271_acx_tx_power(wl, conf->power_level);
1846 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001847 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001848
1849 wl->power_level = conf->power_level;
1850 }
1851
1852out_sleep:
1853 wl1271_ps_elp_sleep(wl);
1854
1855out:
1856 mutex_unlock(&wl->mutex);
1857
1858 return ret;
1859}
1860
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001861struct wl1271_filter_params {
1862 bool enabled;
1863 int mc_list_length;
1864 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1865};
1866
Jiri Pirko22bedad2010-04-01 21:22:57 +00001867static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1868 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001869{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001870 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001871 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001872 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001873
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001874 if (unlikely(wl->state == WL1271_STATE_OFF))
1875 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001876
Juuso Oikarinen74441132009-10-13 12:47:53 +03001877 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001878 if (!fp) {
1879 wl1271_error("Out of memory setting filters.");
1880 return 0;
1881 }
1882
1883 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001884 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001885 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1886 fp->enabled = false;
1887 } else {
1888 fp->enabled = true;
1889 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001890 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001891 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001892 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001893 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001894 }
1895
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001896 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001897}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001898
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001899#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1900 FIF_ALLMULTI | \
1901 FIF_FCSFAIL | \
1902 FIF_BCN_PRBRESP_PROMISC | \
1903 FIF_CONTROL | \
1904 FIF_OTHER_BSS)
1905
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1907 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001908 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001910 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001911 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001912 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913
Arik Nemtsov7d057862010-10-16 19:25:35 +02001914 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1915 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001917 mutex_lock(&wl->mutex);
1918
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001919 *total &= WL1271_SUPPORTED_FILTERS;
1920 changed &= WL1271_SUPPORTED_FILTERS;
1921
1922 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001923 goto out;
1924
Ido Yariva6208652011-03-01 15:14:41 +02001925 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001926 if (ret < 0)
1927 goto out;
1928
Arik Nemtsov7d057862010-10-16 19:25:35 +02001929 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1930 if (*total & FIF_ALLMULTI)
1931 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1932 else if (fp)
1933 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1934 fp->mc_list,
1935 fp->mc_list_length);
1936 if (ret < 0)
1937 goto out_sleep;
1938 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001940 /* determine, whether supported filter values have changed */
1941 if (changed == 0)
1942 goto out_sleep;
1943
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001944 /* configure filters */
1945 wl->filters = *total;
1946 wl1271_configure_filters(wl, 0);
1947
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001948 /* apply configured filters */
1949 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1950 if (ret < 0)
1951 goto out_sleep;
1952
1953out_sleep:
1954 wl1271_ps_elp_sleep(wl);
1955
1956out:
1957 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001958 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959}
1960
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001961static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1962 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1963 u16 tx_seq_16)
1964{
1965 struct wl1271_ap_key *ap_key;
1966 int i;
1967
1968 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1969
1970 if (key_size > MAX_KEY_SIZE)
1971 return -EINVAL;
1972
1973 /*
1974 * Find next free entry in ap_keys. Also check we are not replacing
1975 * an existing key.
1976 */
1977 for (i = 0; i < MAX_NUM_KEYS; i++) {
1978 if (wl->recorded_ap_keys[i] == NULL)
1979 break;
1980
1981 if (wl->recorded_ap_keys[i]->id == id) {
1982 wl1271_warning("trying to record key replacement");
1983 return -EINVAL;
1984 }
1985 }
1986
1987 if (i == MAX_NUM_KEYS)
1988 return -EBUSY;
1989
1990 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1991 if (!ap_key)
1992 return -ENOMEM;
1993
1994 ap_key->id = id;
1995 ap_key->key_type = key_type;
1996 ap_key->key_size = key_size;
1997 memcpy(ap_key->key, key, key_size);
1998 ap_key->hlid = hlid;
1999 ap_key->tx_seq_32 = tx_seq_32;
2000 ap_key->tx_seq_16 = tx_seq_16;
2001
2002 wl->recorded_ap_keys[i] = ap_key;
2003 return 0;
2004}
2005
2006static void wl1271_free_ap_keys(struct wl1271 *wl)
2007{
2008 int i;
2009
2010 for (i = 0; i < MAX_NUM_KEYS; i++) {
2011 kfree(wl->recorded_ap_keys[i]);
2012 wl->recorded_ap_keys[i] = NULL;
2013 }
2014}
2015
2016static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2017{
2018 int i, ret = 0;
2019 struct wl1271_ap_key *key;
2020 bool wep_key_added = false;
2021
2022 for (i = 0; i < MAX_NUM_KEYS; i++) {
2023 if (wl->recorded_ap_keys[i] == NULL)
2024 break;
2025
2026 key = wl->recorded_ap_keys[i];
2027 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2028 key->id, key->key_type,
2029 key->key_size, key->key,
2030 key->hlid, key->tx_seq_32,
2031 key->tx_seq_16);
2032 if (ret < 0)
2033 goto out;
2034
2035 if (key->key_type == KEY_WEP)
2036 wep_key_added = true;
2037 }
2038
2039 if (wep_key_added) {
2040 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2041 if (ret < 0)
2042 goto out;
2043 }
2044
2045out:
2046 wl1271_free_ap_keys(wl);
2047 return ret;
2048}
2049
2050static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2051 u8 key_size, const u8 *key, u32 tx_seq_32,
2052 u16 tx_seq_16, struct ieee80211_sta *sta)
2053{
2054 int ret;
2055 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2056
2057 if (is_ap) {
2058 struct wl1271_station *wl_sta;
2059 u8 hlid;
2060
2061 if (sta) {
2062 wl_sta = (struct wl1271_station *)sta->drv_priv;
2063 hlid = wl_sta->hlid;
2064 } else {
2065 hlid = WL1271_AP_BROADCAST_HLID;
2066 }
2067
2068 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2069 /*
2070 * We do not support removing keys after AP shutdown.
2071 * Pretend we do to make mac80211 happy.
2072 */
2073 if (action != KEY_ADD_OR_REPLACE)
2074 return 0;
2075
2076 ret = wl1271_record_ap_key(wl, id,
2077 key_type, key_size,
2078 key, hlid, tx_seq_32,
2079 tx_seq_16);
2080 } else {
2081 ret = wl1271_cmd_set_ap_key(wl, action,
2082 id, key_type, key_size,
2083 key, hlid, tx_seq_32,
2084 tx_seq_16);
2085 }
2086
2087 if (ret < 0)
2088 return ret;
2089 } else {
2090 const u8 *addr;
2091 static const u8 bcast_addr[ETH_ALEN] = {
2092 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2093 };
2094
2095 addr = sta ? sta->addr : bcast_addr;
2096
2097 if (is_zero_ether_addr(addr)) {
2098 /* We dont support TX only encryption */
2099 return -EOPNOTSUPP;
2100 }
2101
2102 /* The wl1271 does not allow to remove unicast keys - they
2103 will be cleared automatically on next CMD_JOIN. Ignore the
2104 request silently, as we dont want the mac80211 to emit
2105 an error message. */
2106 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2107 return 0;
2108
2109 ret = wl1271_cmd_set_sta_key(wl, action,
2110 id, key_type, key_size,
2111 key, addr, tx_seq_32,
2112 tx_seq_16);
2113 if (ret < 0)
2114 return ret;
2115
2116 /* the default WEP key needs to be configured at least once */
2117 if (key_type == KEY_WEP) {
2118 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2119 wl->default_key);
2120 if (ret < 0)
2121 return ret;
2122 }
2123 }
2124
2125 return 0;
2126}
2127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2129 struct ieee80211_vif *vif,
2130 struct ieee80211_sta *sta,
2131 struct ieee80211_key_conf *key_conf)
2132{
2133 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002135 u32 tx_seq_32 = 0;
2136 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137 u8 key_type;
2138
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002139 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2140
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002141 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002143 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144 key_conf->keylen, key_conf->flags);
2145 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002147 mutex_lock(&wl->mutex);
2148
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002149 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2150 ret = -EAGAIN;
2151 goto out_unlock;
2152 }
2153
Ido Yariva6208652011-03-01 15:14:41 +02002154 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155 if (ret < 0)
2156 goto out_unlock;
2157
Johannes Berg97359d12010-08-10 09:46:38 +02002158 switch (key_conf->cipher) {
2159 case WLAN_CIPHER_SUITE_WEP40:
2160 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161 key_type = KEY_WEP;
2162
2163 key_conf->hw_key_idx = key_conf->keyidx;
2164 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002165 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166 key_type = KEY_TKIP;
2167
2168 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002169 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2170 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002172 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173 key_type = KEY_AES;
2174
2175 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002176 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2177 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002179 case WL1271_CIPHER_SUITE_GEM:
2180 key_type = KEY_GEM;
2181 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2182 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2183 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002185 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186
2187 ret = -EOPNOTSUPP;
2188 goto out_sleep;
2189 }
2190
2191 switch (cmd) {
2192 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002193 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2194 key_conf->keyidx, key_type,
2195 key_conf->keylen, key_conf->key,
2196 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197 if (ret < 0) {
2198 wl1271_error("Could not add or replace key");
2199 goto out_sleep;
2200 }
2201 break;
2202
2203 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002204 ret = wl1271_set_key(wl, KEY_REMOVE,
2205 key_conf->keyidx, key_type,
2206 key_conf->keylen, key_conf->key,
2207 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208 if (ret < 0) {
2209 wl1271_error("Could not remove key");
2210 goto out_sleep;
2211 }
2212 break;
2213
2214 default:
2215 wl1271_error("Unsupported key cmd 0x%x", cmd);
2216 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 break;
2218 }
2219
2220out_sleep:
2221 wl1271_ps_elp_sleep(wl);
2222
2223out_unlock:
2224 mutex_unlock(&wl->mutex);
2225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226 return ret;
2227}
2228
2229static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002230 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 struct cfg80211_scan_request *req)
2232{
2233 struct wl1271 *wl = hw->priv;
2234 int ret;
2235 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002236 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002237
2238 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2239
2240 if (req->n_ssids) {
2241 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002242 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002243 }
2244
2245 mutex_lock(&wl->mutex);
2246
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002247 if (wl->state == WL1271_STATE_OFF) {
2248 /*
2249 * We cannot return -EBUSY here because cfg80211 will expect
2250 * a call to ieee80211_scan_completed if we do - in this case
2251 * there won't be any call.
2252 */
2253 ret = -EAGAIN;
2254 goto out;
2255 }
2256
Ido Yariva6208652011-03-01 15:14:41 +02002257 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 if (ret < 0)
2259 goto out;
2260
Luciano Coelho5924f892010-08-04 03:46:22 +03002261 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262
2263 wl1271_ps_elp_sleep(wl);
2264
2265out:
2266 mutex_unlock(&wl->mutex);
2267
2268 return ret;
2269}
2270
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002271static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2272{
2273 struct wl1271 *wl = hw->priv;
2274 int ret = 0;
2275
2276 mutex_lock(&wl->mutex);
2277
2278 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2279 ret = -EAGAIN;
2280 goto out;
2281 }
2282
Ido Yariva6208652011-03-01 15:14:41 +02002283 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002284 if (ret < 0)
2285 goto out;
2286
2287 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2288 if (ret < 0)
2289 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2290
2291 wl1271_ps_elp_sleep(wl);
2292
2293out:
2294 mutex_unlock(&wl->mutex);
2295
2296 return ret;
2297}
2298
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2300{
2301 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002302 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303
2304 mutex_lock(&wl->mutex);
2305
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002306 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2307 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002308 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002309 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002310
Ido Yariva6208652011-03-01 15:14:41 +02002311 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312 if (ret < 0)
2313 goto out;
2314
2315 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2316 if (ret < 0)
2317 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2318
2319 wl1271_ps_elp_sleep(wl);
2320
2321out:
2322 mutex_unlock(&wl->mutex);
2323
2324 return ret;
2325}
2326
Arik Nemtsove78a2872010-10-16 19:07:21 +02002327static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002328 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002329{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002330 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002331
2332 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002333 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002334 if (ptr[0] == WLAN_EID_SSID) {
2335 wl->ssid_len = ptr[1];
2336 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002337 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002338 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002339 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002340 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002342 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002343 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002344}
2345
Arik Nemtsove78a2872010-10-16 19:07:21 +02002346static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2347 struct ieee80211_bss_conf *bss_conf,
2348 u32 changed)
2349{
2350 int ret = 0;
2351
2352 if (changed & BSS_CHANGED_ERP_SLOT) {
2353 if (bss_conf->use_short_slot)
2354 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2355 else
2356 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2357 if (ret < 0) {
2358 wl1271_warning("Set slot time failed %d", ret);
2359 goto out;
2360 }
2361 }
2362
2363 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2364 if (bss_conf->use_short_preamble)
2365 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2366 else
2367 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2368 }
2369
2370 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2371 if (bss_conf->use_cts_prot)
2372 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2373 else
2374 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2375 if (ret < 0) {
2376 wl1271_warning("Set ctsprotect failed %d", ret);
2377 goto out;
2378 }
2379 }
2380
2381out:
2382 return ret;
2383}
2384
2385static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2386 struct ieee80211_vif *vif,
2387 struct ieee80211_bss_conf *bss_conf,
2388 u32 changed)
2389{
2390 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2391 int ret = 0;
2392
2393 if ((changed & BSS_CHANGED_BEACON_INT)) {
2394 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2395 bss_conf->beacon_int);
2396
2397 wl->beacon_int = bss_conf->beacon_int;
2398 }
2399
2400 if ((changed & BSS_CHANGED_BEACON)) {
2401 struct ieee80211_hdr *hdr;
2402 int ieoffset = offsetof(struct ieee80211_mgmt,
2403 u.beacon.variable);
2404 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2405 u16 tmpl_id;
2406
2407 if (!beacon)
2408 goto out;
2409
2410 wl1271_debug(DEBUG_MASTER, "beacon updated");
2411
2412 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2413 if (ret < 0) {
2414 dev_kfree_skb(beacon);
2415 goto out;
2416 }
2417 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2418 CMD_TEMPL_BEACON;
2419 ret = wl1271_cmd_template_set(wl, tmpl_id,
2420 beacon->data,
2421 beacon->len, 0,
2422 wl1271_tx_min_rate_get(wl));
2423 if (ret < 0) {
2424 dev_kfree_skb(beacon);
2425 goto out;
2426 }
2427
2428 hdr = (struct ieee80211_hdr *) beacon->data;
2429 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2430 IEEE80211_STYPE_PROBE_RESP);
2431
2432 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2433 CMD_TEMPL_PROBE_RESPONSE;
2434 ret = wl1271_cmd_template_set(wl,
2435 tmpl_id,
2436 beacon->data,
2437 beacon->len, 0,
2438 wl1271_tx_min_rate_get(wl));
2439 dev_kfree_skb(beacon);
2440 if (ret < 0)
2441 goto out;
2442 }
2443
2444out:
2445 return ret;
2446}
2447
2448/* AP mode changes */
2449static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450 struct ieee80211_vif *vif,
2451 struct ieee80211_bss_conf *bss_conf,
2452 u32 changed)
2453{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002454 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455
Arik Nemtsove78a2872010-10-16 19:07:21 +02002456 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2457 u32 rates = bss_conf->basic_rates;
2458 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002459
Arik Nemtsove78a2872010-10-16 19:07:21 +02002460 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2461 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2462 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2463 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464
Arik Nemtsove78a2872010-10-16 19:07:21 +02002465 /* update the AP management rate policy with the new rates */
2466 mgmt_rc.enabled_rates = wl->basic_rate_set;
2467 mgmt_rc.long_retry_limit = 10;
2468 mgmt_rc.short_retry_limit = 10;
2469 mgmt_rc.aflags = 0;
2470 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2471 ACX_TX_AP_MODE_MGMT_RATE);
2472 if (ret < 0) {
2473 wl1271_error("AP mgmt policy change failed %d", ret);
2474 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002475 }
2476 }
2477
Arik Nemtsove78a2872010-10-16 19:07:21 +02002478 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2479 if (ret < 0)
2480 goto out;
2481
2482 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2483 if (bss_conf->enable_beacon) {
2484 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2485 ret = wl1271_cmd_start_bss(wl);
2486 if (ret < 0)
2487 goto out;
2488
2489 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2490 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002491
2492 ret = wl1271_ap_init_hwenc(wl);
2493 if (ret < 0)
2494 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002495 }
2496 } else {
2497 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2498 ret = wl1271_cmd_stop_bss(wl);
2499 if (ret < 0)
2500 goto out;
2501
2502 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2503 wl1271_debug(DEBUG_AP, "stopped AP");
2504 }
2505 }
2506 }
2507
2508 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2509 if (ret < 0)
2510 goto out;
2511out:
2512 return;
2513}
2514
2515/* STA/IBSS mode changes */
2516static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2517 struct ieee80211_vif *vif,
2518 struct ieee80211_bss_conf *bss_conf,
2519 u32 changed)
2520{
2521 bool do_join = false, set_assoc = false;
2522 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002523 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002524 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002525 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002526 bool sta_exists = false;
2527 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002528
2529 if (is_ibss) {
2530 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2531 changed);
2532 if (ret < 0)
2533 goto out;
2534 }
2535
2536 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2537 do_join = true;
2538
2539 /* Need to update the SSID (for filtering etc) */
2540 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2541 do_join = true;
2542
2543 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002544 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2545 bss_conf->enable_beacon ? "enabled" : "disabled");
2546
2547 if (bss_conf->enable_beacon)
2548 wl->set_bss_type = BSS_TYPE_IBSS;
2549 else
2550 wl->set_bss_type = BSS_TYPE_STA_BSS;
2551 do_join = true;
2552 }
2553
Arik Nemtsove78a2872010-10-16 19:07:21 +02002554 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002555 bool enable = false;
2556 if (bss_conf->cqm_rssi_thold)
2557 enable = true;
2558 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2559 bss_conf->cqm_rssi_thold,
2560 bss_conf->cqm_rssi_hyst);
2561 if (ret < 0)
2562 goto out;
2563 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2564 }
2565
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002566 if ((changed & BSS_CHANGED_BSSID) &&
2567 /*
2568 * Now we know the correct bssid, so we send a new join command
2569 * and enable the BSSID filter
2570 */
2571 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002572 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002573
Eliad Pellerfa287b82010-12-26 09:27:50 +01002574 if (!is_zero_ether_addr(wl->bssid)) {
2575 ret = wl1271_cmd_build_null_data(wl);
2576 if (ret < 0)
2577 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002578
Eliad Pellerfa287b82010-12-26 09:27:50 +01002579 ret = wl1271_build_qos_null_data(wl);
2580 if (ret < 0)
2581 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002582
Eliad Pellerfa287b82010-12-26 09:27:50 +01002583 /* filter out all packets not from this BSSID */
2584 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002585
Eliad Pellerfa287b82010-12-26 09:27:50 +01002586 /* Need to update the BSSID (for filtering etc) */
2587 do_join = true;
2588 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002589 }
2590
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002591 rcu_read_lock();
2592 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2593 if (sta) {
2594 /* save the supp_rates of the ap */
2595 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2596 if (sta->ht_cap.ht_supported)
2597 sta_rate_set |=
2598 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002599 sta_ht_cap = sta->ht_cap;
2600 sta_exists = true;
2601 }
2602 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002603
Arik Nemtsova1008852011-02-12 23:24:20 +02002604 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002605 /* handle new association with HT and HT information change */
2606 if ((changed & BSS_CHANGED_HT) &&
2607 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002608 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002609 true);
2610 if (ret < 0) {
2611 wl1271_warning("Set ht cap true failed %d",
2612 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002613 goto out;
2614 }
2615 ret = wl1271_acx_set_ht_information(wl,
2616 bss_conf->ht_operation_mode);
2617 if (ret < 0) {
2618 wl1271_warning("Set ht information failed %d",
2619 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002620 goto out;
2621 }
2622 }
2623 /* handle new association without HT and disassociation */
2624 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002625 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002626 false);
2627 if (ret < 0) {
2628 wl1271_warning("Set ht cap false failed %d",
2629 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002630 goto out;
2631 }
2632 }
2633 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002634
Arik Nemtsove78a2872010-10-16 19:07:21 +02002635 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002636 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002637 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002638 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002639 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002640 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002641
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002642 wl->ps_poll_failures = 0;
2643
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002644 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002645 * use basic rates from AP, and determine lowest rate
2646 * to use with control frames.
2647 */
2648 rates = bss_conf->basic_rates;
2649 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2650 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002651 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002652 if (sta_rate_set)
2653 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2654 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002655 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002656 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002657 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002658
2659 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002660 * with wl1271, we don't need to update the
2661 * beacon_int and dtim_period, because the firmware
2662 * updates it by itself when the first beacon is
2663 * received after a join.
2664 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2666 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002667 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002669 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002670 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002671 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002672 dev_kfree_skb(wl->probereq);
2673 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2674 ieoffset = offsetof(struct ieee80211_mgmt,
2675 u.probe_req.variable);
2676 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002677
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002678 /* enable the connection monitoring feature */
2679 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002680 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002681 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002682
2683 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002684 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2685 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002686 enum wl1271_cmd_ps_mode mode;
2687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002688 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002689 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002690 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002691 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002693 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002695 } else {
2696 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002697 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002698 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002699 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002700
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002701 /* free probe-request template */
2702 dev_kfree_skb(wl->probereq);
2703 wl->probereq = NULL;
2704
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002705 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002706 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002707
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002708 /* revert back to minimum rates for the current band */
2709 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002710 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002711 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002712 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002713 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002714
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002715 /* disable connection monitor features */
2716 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002717
2718 /* Disable the keep-alive feature */
2719 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002720 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002721 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002722
2723 /* restore the bssid filter and go to dummy bssid */
2724 wl1271_unjoin(wl);
2725 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002726 }
2727 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002728
Arik Nemtsove78a2872010-10-16 19:07:21 +02002729 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2730 if (ret < 0)
2731 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002733 if (changed & BSS_CHANGED_ARP_FILTER) {
2734 __be32 addr = bss_conf->arp_addr_list[0];
2735 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2736
Eliad Pellerc5312772010-12-09 11:31:27 +02002737 if (bss_conf->arp_addr_cnt == 1 &&
2738 bss_conf->arp_filter_enabled) {
2739 /*
2740 * The template should have been configured only upon
2741 * association. however, it seems that the correct ip
2742 * isn't being set (when sending), so we have to
2743 * reconfigure the template upon every ip change.
2744 */
2745 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2746 if (ret < 0) {
2747 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002748 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002749 }
2750
2751 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002752 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002753 addr);
2754 } else
2755 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002756
2757 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002758 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002759 }
2760
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002761 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002762 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002763 if (ret < 0) {
2764 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002765 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002766 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002767 }
2768
Arik Nemtsove78a2872010-10-16 19:07:21 +02002769out:
2770 return;
2771}
2772
2773static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2774 struct ieee80211_vif *vif,
2775 struct ieee80211_bss_conf *bss_conf,
2776 u32 changed)
2777{
2778 struct wl1271 *wl = hw->priv;
2779 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2780 int ret;
2781
2782 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2783 (int)changed);
2784
2785 mutex_lock(&wl->mutex);
2786
2787 if (unlikely(wl->state == WL1271_STATE_OFF))
2788 goto out;
2789
Ido Yariva6208652011-03-01 15:14:41 +02002790 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002791 if (ret < 0)
2792 goto out;
2793
2794 if (is_ap)
2795 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2796 else
2797 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2798
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 wl1271_ps_elp_sleep(wl);
2800
2801out:
2802 mutex_unlock(&wl->mutex);
2803}
2804
Kalle Valoc6999d82010-02-18 13:25:41 +02002805static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2806 const struct ieee80211_tx_queue_params *params)
2807{
2808 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002809 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002810 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002811
2812 mutex_lock(&wl->mutex);
2813
2814 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2815
Kalle Valo4695dc92010-03-18 12:26:38 +02002816 if (params->uapsd)
2817 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2818 else
2819 ps_scheme = CONF_PS_SCHEME_LEGACY;
2820
Arik Nemtsov488fc542010-10-16 20:33:45 +02002821 if (wl->state == WL1271_STATE_OFF) {
2822 /*
2823 * If the state is off, the parameters will be recorded and
2824 * configured on init. This happens in AP-mode.
2825 */
2826 struct conf_tx_ac_category *conf_ac =
2827 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2828 struct conf_tx_tid *conf_tid =
2829 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2830
2831 conf_ac->ac = wl1271_tx_get_queue(queue);
2832 conf_ac->cw_min = (u8)params->cw_min;
2833 conf_ac->cw_max = params->cw_max;
2834 conf_ac->aifsn = params->aifs;
2835 conf_ac->tx_op_limit = params->txop << 5;
2836
2837 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2838 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2839 conf_tid->tsid = wl1271_tx_get_queue(queue);
2840 conf_tid->ps_scheme = ps_scheme;
2841 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2842 conf_tid->apsd_conf[0] = 0;
2843 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002844 goto out;
2845 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002846
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002847 ret = wl1271_ps_elp_wakeup(wl);
2848 if (ret < 0)
2849 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002850
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002851 /*
2852 * the txop is confed in units of 32us by the mac80211,
2853 * we need us
2854 */
2855 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2856 params->cw_min, params->cw_max,
2857 params->aifs, params->txop << 5);
2858 if (ret < 0)
2859 goto out_sleep;
2860
2861 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2862 CONF_CHANNEL_TYPE_EDCF,
2863 wl1271_tx_get_queue(queue),
2864 ps_scheme, CONF_ACK_POLICY_LEGACY,
2865 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002866
2867out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002868 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002869
2870out:
2871 mutex_unlock(&wl->mutex);
2872
2873 return ret;
2874}
2875
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002876static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2877{
2878
2879 struct wl1271 *wl = hw->priv;
2880 u64 mactime = ULLONG_MAX;
2881 int ret;
2882
2883 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2884
2885 mutex_lock(&wl->mutex);
2886
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002887 if (unlikely(wl->state == WL1271_STATE_OFF))
2888 goto out;
2889
Ido Yariva6208652011-03-01 15:14:41 +02002890 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002891 if (ret < 0)
2892 goto out;
2893
2894 ret = wl1271_acx_tsf_info(wl, &mactime);
2895 if (ret < 0)
2896 goto out_sleep;
2897
2898out_sleep:
2899 wl1271_ps_elp_sleep(wl);
2900
2901out:
2902 mutex_unlock(&wl->mutex);
2903 return mactime;
2904}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905
John W. Linvilleece550d2010-07-28 16:41:06 -04002906static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2907 struct survey_info *survey)
2908{
2909 struct wl1271 *wl = hw->priv;
2910 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002911
John W. Linvilleece550d2010-07-28 16:41:06 -04002912 if (idx != 0)
2913 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002914
John W. Linvilleece550d2010-07-28 16:41:06 -04002915 survey->channel = conf->channel;
2916 survey->filled = SURVEY_INFO_NOISE_DBM;
2917 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002918
John W. Linvilleece550d2010-07-28 16:41:06 -04002919 return 0;
2920}
2921
Arik Nemtsov409622e2011-02-23 00:22:29 +02002922static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002923 struct ieee80211_sta *sta,
2924 u8 *hlid)
2925{
2926 struct wl1271_station *wl_sta;
2927 int id;
2928
2929 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2930 if (id >= AP_MAX_STATIONS) {
2931 wl1271_warning("could not allocate HLID - too much stations");
2932 return -EBUSY;
2933 }
2934
2935 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002936 __set_bit(id, wl->ap_hlid_map);
2937 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2938 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002939 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002940 return 0;
2941}
2942
Arik Nemtsov409622e2011-02-23 00:22:29 +02002943static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002944{
2945 int id = hlid - WL1271_AP_STA_HLID_START;
2946
Arik Nemtsov409622e2011-02-23 00:22:29 +02002947 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2948 return;
2949
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002950 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002951 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002952 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002953 __clear_bit(hlid, &wl->ap_ps_map);
2954 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002955}
2956
Arik Nemtsov47684802011-04-26 23:21:51 +03002957bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
2958{
2959 int id = hlid - WL1271_AP_STA_HLID_START;
2960 return test_bit(id, wl->ap_hlid_map);
2961}
2962
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002963static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2964 struct ieee80211_vif *vif,
2965 struct ieee80211_sta *sta)
2966{
2967 struct wl1271 *wl = hw->priv;
2968 int ret = 0;
2969 u8 hlid;
2970
2971 mutex_lock(&wl->mutex);
2972
2973 if (unlikely(wl->state == WL1271_STATE_OFF))
2974 goto out;
2975
2976 if (wl->bss_type != BSS_TYPE_AP_BSS)
2977 goto out;
2978
2979 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2980
Arik Nemtsov409622e2011-02-23 00:22:29 +02002981 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002982 if (ret < 0)
2983 goto out;
2984
Ido Yariva6208652011-03-01 15:14:41 +02002985 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002986 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002987 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002988
2989 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2990 if (ret < 0)
2991 goto out_sleep;
2992
2993out_sleep:
2994 wl1271_ps_elp_sleep(wl);
2995
Arik Nemtsov409622e2011-02-23 00:22:29 +02002996out_free_sta:
2997 if (ret < 0)
2998 wl1271_free_sta(wl, hlid);
2999
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003000out:
3001 mutex_unlock(&wl->mutex);
3002 return ret;
3003}
3004
3005static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3006 struct ieee80211_vif *vif,
3007 struct ieee80211_sta *sta)
3008{
3009 struct wl1271 *wl = hw->priv;
3010 struct wl1271_station *wl_sta;
3011 int ret = 0, id;
3012
3013 mutex_lock(&wl->mutex);
3014
3015 if (unlikely(wl->state == WL1271_STATE_OFF))
3016 goto out;
3017
3018 if (wl->bss_type != BSS_TYPE_AP_BSS)
3019 goto out;
3020
3021 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3022
3023 wl_sta = (struct wl1271_station *)sta->drv_priv;
3024 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3025 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3026 goto out;
3027
Ido Yariva6208652011-03-01 15:14:41 +02003028 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003029 if (ret < 0)
3030 goto out;
3031
3032 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3033 if (ret < 0)
3034 goto out_sleep;
3035
Arik Nemtsov409622e2011-02-23 00:22:29 +02003036 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003037
3038out_sleep:
3039 wl1271_ps_elp_sleep(wl);
3040
3041out:
3042 mutex_unlock(&wl->mutex);
3043 return ret;
3044}
3045
Luciano Coelho4623ec72011-03-21 19:26:41 +02003046static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3047 struct ieee80211_vif *vif,
3048 enum ieee80211_ampdu_mlme_action action,
3049 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3050 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003051{
3052 struct wl1271 *wl = hw->priv;
3053 int ret;
3054
3055 mutex_lock(&wl->mutex);
3056
3057 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3058 ret = -EAGAIN;
3059 goto out;
3060 }
3061
Ido Yariva6208652011-03-01 15:14:41 +02003062 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003063 if (ret < 0)
3064 goto out;
3065
3066 switch (action) {
3067 case IEEE80211_AMPDU_RX_START:
3068 if (wl->ba_support) {
3069 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3070 true);
3071 if (!ret)
3072 wl->ba_rx_bitmap |= BIT(tid);
3073 } else {
3074 ret = -ENOTSUPP;
3075 }
3076 break;
3077
3078 case IEEE80211_AMPDU_RX_STOP:
3079 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3080 if (!ret)
3081 wl->ba_rx_bitmap &= ~BIT(tid);
3082 break;
3083
3084 /*
3085 * The BA initiator session management in FW independently.
3086 * Falling break here on purpose for all TX APDU commands.
3087 */
3088 case IEEE80211_AMPDU_TX_START:
3089 case IEEE80211_AMPDU_TX_STOP:
3090 case IEEE80211_AMPDU_TX_OPERATIONAL:
3091 ret = -EINVAL;
3092 break;
3093
3094 default:
3095 wl1271_error("Incorrect ampdu action id=%x\n", action);
3096 ret = -EINVAL;
3097 }
3098
3099 wl1271_ps_elp_sleep(wl);
3100
3101out:
3102 mutex_unlock(&wl->mutex);
3103
3104 return ret;
3105}
3106
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003107/* can't be const, mac80211 writes to this */
3108static struct ieee80211_rate wl1271_rates[] = {
3109 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003110 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3111 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003113 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3114 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003115 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3116 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003117 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3118 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003119 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3120 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003121 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3122 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3124 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003125 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3126 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003127 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003128 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3129 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003130 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003131 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3132 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003133 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003134 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3135 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003136 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003137 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3138 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003139 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003140 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3141 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003142 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003143 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3144 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003146 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3147 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003148};
3149
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003150/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003151static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003152 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003153 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003154 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3155 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3156 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003157 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003158 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3159 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3160 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003161 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003162 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3163 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3164 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003165 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003166};
3167
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003168/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003169static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003170 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003171 7, /* CONF_HW_RXTX_RATE_MCS7 */
3172 6, /* CONF_HW_RXTX_RATE_MCS6 */
3173 5, /* CONF_HW_RXTX_RATE_MCS5 */
3174 4, /* CONF_HW_RXTX_RATE_MCS4 */
3175 3, /* CONF_HW_RXTX_RATE_MCS3 */
3176 2, /* CONF_HW_RXTX_RATE_MCS2 */
3177 1, /* CONF_HW_RXTX_RATE_MCS1 */
3178 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003179
3180 11, /* CONF_HW_RXTX_RATE_54 */
3181 10, /* CONF_HW_RXTX_RATE_48 */
3182 9, /* CONF_HW_RXTX_RATE_36 */
3183 8, /* CONF_HW_RXTX_RATE_24 */
3184
3185 /* TI-specific rate */
3186 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3187
3188 7, /* CONF_HW_RXTX_RATE_18 */
3189 6, /* CONF_HW_RXTX_RATE_12 */
3190 3, /* CONF_HW_RXTX_RATE_11 */
3191 5, /* CONF_HW_RXTX_RATE_9 */
3192 4, /* CONF_HW_RXTX_RATE_6 */
3193 2, /* CONF_HW_RXTX_RATE_5_5 */
3194 1, /* CONF_HW_RXTX_RATE_2 */
3195 0 /* CONF_HW_RXTX_RATE_1 */
3196};
3197
Shahar Levie8b03a22010-10-13 16:09:39 +02003198/* 11n STA capabilities */
3199#define HW_RX_HIGHEST_RATE 72
3200
Shahar Levi00d20102010-11-08 11:20:10 +00003201#ifdef CONFIG_WL12XX_HT
3202#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003203 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3204 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003205 .ht_supported = true, \
3206 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3207 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3208 .mcs = { \
3209 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3210 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3211 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3212 }, \
3213}
Shahar Levi18357852010-10-13 16:09:41 +02003214#else
Shahar Levi00d20102010-11-08 11:20:10 +00003215#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003216 .ht_supported = false, \
3217}
3218#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220/* can't be const, mac80211 writes to this */
3221static struct ieee80211_supported_band wl1271_band_2ghz = {
3222 .channels = wl1271_channels,
3223 .n_channels = ARRAY_SIZE(wl1271_channels),
3224 .bitrates = wl1271_rates,
3225 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003226 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003227};
3228
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003229/* 5 GHz data rates for WL1273 */
3230static struct ieee80211_rate wl1271_rates_5ghz[] = {
3231 { .bitrate = 60,
3232 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3233 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3234 { .bitrate = 90,
3235 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3236 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3237 { .bitrate = 120,
3238 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3239 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3240 { .bitrate = 180,
3241 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3242 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3243 { .bitrate = 240,
3244 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3245 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3246 { .bitrate = 360,
3247 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3248 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3249 { .bitrate = 480,
3250 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3251 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3252 { .bitrate = 540,
3253 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3254 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3255};
3256
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003257/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003258static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003259 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003260 { .hw_value = 8, .center_freq = 5040},
3261 { .hw_value = 9, .center_freq = 5045},
3262 { .hw_value = 11, .center_freq = 5055},
3263 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003264 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003265 { .hw_value = 34, .center_freq = 5170},
3266 { .hw_value = 36, .center_freq = 5180},
3267 { .hw_value = 38, .center_freq = 5190},
3268 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003269 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003270 { .hw_value = 44, .center_freq = 5220},
3271 { .hw_value = 46, .center_freq = 5230},
3272 { .hw_value = 48, .center_freq = 5240},
3273 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003274 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003275 { .hw_value = 60, .center_freq = 5300},
3276 { .hw_value = 64, .center_freq = 5320},
3277 { .hw_value = 100, .center_freq = 5500},
3278 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003279 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003280 { .hw_value = 112, .center_freq = 5560},
3281 { .hw_value = 116, .center_freq = 5580},
3282 { .hw_value = 120, .center_freq = 5600},
3283 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003284 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003285 { .hw_value = 132, .center_freq = 5660},
3286 { .hw_value = 136, .center_freq = 5680},
3287 { .hw_value = 140, .center_freq = 5700},
3288 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003289 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003290 { .hw_value = 157, .center_freq = 5785},
3291 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003292 { .hw_value = 165, .center_freq = 5825},
3293};
3294
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003295/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003296static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003297 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003298 7, /* CONF_HW_RXTX_RATE_MCS7 */
3299 6, /* CONF_HW_RXTX_RATE_MCS6 */
3300 5, /* CONF_HW_RXTX_RATE_MCS5 */
3301 4, /* CONF_HW_RXTX_RATE_MCS4 */
3302 3, /* CONF_HW_RXTX_RATE_MCS3 */
3303 2, /* CONF_HW_RXTX_RATE_MCS2 */
3304 1, /* CONF_HW_RXTX_RATE_MCS1 */
3305 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003306
3307 7, /* CONF_HW_RXTX_RATE_54 */
3308 6, /* CONF_HW_RXTX_RATE_48 */
3309 5, /* CONF_HW_RXTX_RATE_36 */
3310 4, /* CONF_HW_RXTX_RATE_24 */
3311
3312 /* TI-specific rate */
3313 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3314
3315 3, /* CONF_HW_RXTX_RATE_18 */
3316 2, /* CONF_HW_RXTX_RATE_12 */
3317 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3318 1, /* CONF_HW_RXTX_RATE_9 */
3319 0, /* CONF_HW_RXTX_RATE_6 */
3320 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3321 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3322 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3323};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003324
3325static struct ieee80211_supported_band wl1271_band_5ghz = {
3326 .channels = wl1271_channels_5ghz,
3327 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3328 .bitrates = wl1271_rates_5ghz,
3329 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003330 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003331};
3332
Tobias Klausera0ea9492010-05-20 10:38:11 +02003333static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003334 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3335 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3336};
3337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003338static const struct ieee80211_ops wl1271_ops = {
3339 .start = wl1271_op_start,
3340 .stop = wl1271_op_stop,
3341 .add_interface = wl1271_op_add_interface,
3342 .remove_interface = wl1271_op_remove_interface,
3343 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003344 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003345 .configure_filter = wl1271_op_configure_filter,
3346 .tx = wl1271_op_tx,
3347 .set_key = wl1271_op_set_key,
3348 .hw_scan = wl1271_op_hw_scan,
3349 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003350 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003351 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003352 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003353 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003354 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003355 .sta_add = wl1271_op_sta_add,
3356 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003357 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003358 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359};
3360
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003361
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003362u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003363{
3364 u8 idx;
3365
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003366 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003367
3368 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3369 wl1271_error("Illegal RX rate from HW: %d", rate);
3370 return 0;
3371 }
3372
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003373 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003374 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3375 wl1271_error("Unsupported RX rate from HW: %d", rate);
3376 return 0;
3377 }
3378
3379 return idx;
3380}
3381
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003382static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3383 struct device_attribute *attr,
3384 char *buf)
3385{
3386 struct wl1271 *wl = dev_get_drvdata(dev);
3387 ssize_t len;
3388
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003389 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003390
3391 mutex_lock(&wl->mutex);
3392 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3393 wl->sg_enabled);
3394 mutex_unlock(&wl->mutex);
3395
3396 return len;
3397
3398}
3399
3400static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3401 struct device_attribute *attr,
3402 const char *buf, size_t count)
3403{
3404 struct wl1271 *wl = dev_get_drvdata(dev);
3405 unsigned long res;
3406 int ret;
3407
Luciano Coelho6277ed62011-04-01 17:49:54 +03003408 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003409 if (ret < 0) {
3410 wl1271_warning("incorrect value written to bt_coex_mode");
3411 return count;
3412 }
3413
3414 mutex_lock(&wl->mutex);
3415
3416 res = !!res;
3417
3418 if (res == wl->sg_enabled)
3419 goto out;
3420
3421 wl->sg_enabled = res;
3422
3423 if (wl->state == WL1271_STATE_OFF)
3424 goto out;
3425
Ido Yariva6208652011-03-01 15:14:41 +02003426 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003427 if (ret < 0)
3428 goto out;
3429
3430 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3431 wl1271_ps_elp_sleep(wl);
3432
3433 out:
3434 mutex_unlock(&wl->mutex);
3435 return count;
3436}
3437
3438static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3439 wl1271_sysfs_show_bt_coex_state,
3440 wl1271_sysfs_store_bt_coex_state);
3441
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003442static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3443 struct device_attribute *attr,
3444 char *buf)
3445{
3446 struct wl1271 *wl = dev_get_drvdata(dev);
3447 ssize_t len;
3448
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003449 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003450
3451 mutex_lock(&wl->mutex);
3452 if (wl->hw_pg_ver >= 0)
3453 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3454 else
3455 len = snprintf(buf, len, "n/a\n");
3456 mutex_unlock(&wl->mutex);
3457
3458 return len;
3459}
3460
3461static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3462 wl1271_sysfs_show_hw_pg_ver, NULL);
3463
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003464int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003465{
3466 int ret;
3467
3468 if (wl->mac80211_registered)
3469 return 0;
3470
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003471 ret = wl1271_fetch_nvs(wl);
3472 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003473 /* NOTE: The wl->nvs->nvs element must be first, in
3474 * order to simplify the casting, we assume it is at
3475 * the beginning of the wl->nvs structure.
3476 */
3477 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003478
3479 wl->mac_addr[0] = nvs_ptr[11];
3480 wl->mac_addr[1] = nvs_ptr[10];
3481 wl->mac_addr[2] = nvs_ptr[6];
3482 wl->mac_addr[3] = nvs_ptr[5];
3483 wl->mac_addr[4] = nvs_ptr[4];
3484 wl->mac_addr[5] = nvs_ptr[3];
3485 }
3486
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003487 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3488
3489 ret = ieee80211_register_hw(wl->hw);
3490 if (ret < 0) {
3491 wl1271_error("unable to register mac80211 hw: %d", ret);
3492 return ret;
3493 }
3494
3495 wl->mac80211_registered = true;
3496
Eliad Pellerd60080a2010-11-24 12:53:16 +02003497 wl1271_debugfs_init(wl);
3498
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003499 register_netdevice_notifier(&wl1271_dev_notifier);
3500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003501 wl1271_notice("loaded");
3502
3503 return 0;
3504}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003505EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003506
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003507void wl1271_unregister_hw(struct wl1271 *wl)
3508{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003509 if (wl->state == WL1271_STATE_PLT)
3510 __wl1271_plt_stop(wl);
3511
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003512 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003513 ieee80211_unregister_hw(wl->hw);
3514 wl->mac80211_registered = false;
3515
3516}
3517EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3518
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003519int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003520{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003521 static const u32 cipher_suites[] = {
3522 WLAN_CIPHER_SUITE_WEP40,
3523 WLAN_CIPHER_SUITE_WEP104,
3524 WLAN_CIPHER_SUITE_TKIP,
3525 WLAN_CIPHER_SUITE_CCMP,
3526 WL1271_CIPHER_SUITE_GEM,
3527 };
3528
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003529 /* The tx descriptor buffer and the TKIP space. */
3530 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3531 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
3533 /* unit us */
3534 /* FIXME: find a proper value */
3535 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003536 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537
3538 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003539 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003540 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003541 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003542 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003543 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003544 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003545 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003546
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003547 wl->hw->wiphy->cipher_suites = cipher_suites;
3548 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3549
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003550 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003551 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003552 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003553 /*
3554 * Maximum length of elements in scanning probe request templates
3555 * should be the maximum length possible for a template, without
3556 * the IEEE80211 header of the template
3557 */
3558 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3559 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003560
Luciano Coelho4a31c112011-03-21 23:16:14 +02003561 /* make sure all our channels fit in the scanned_ch bitmask */
3562 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3563 ARRAY_SIZE(wl1271_channels_5ghz) >
3564 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003565 /*
3566 * We keep local copies of the band structs because we need to
3567 * modify them on a per-device basis.
3568 */
3569 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3570 sizeof(wl1271_band_2ghz));
3571 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3572 sizeof(wl1271_band_5ghz));
3573
3574 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3575 &wl->bands[IEEE80211_BAND_2GHZ];
3576 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3577 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003578
Kalle Valo12bd8942010-03-18 12:26:33 +02003579 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003580 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003581
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003582 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3583
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003584 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003585
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003586 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3587
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003588 wl->hw->max_rx_aggregation_subframes = 8;
3589
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003590 return 0;
3591}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003592EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003594#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003595
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003596struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003598 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003599 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003600 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003601 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003602 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003603
3604 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3605 if (!hw) {
3606 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003607 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003608 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003609 }
3610
Julia Lawall929ebd32010-05-15 23:16:39 +02003611 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003612 if (!plat_dev) {
3613 wl1271_error("could not allocate platform_device");
3614 ret = -ENOMEM;
3615 goto err_plat_alloc;
3616 }
3617
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003618 wl = hw->priv;
3619 memset(wl, 0, sizeof(*wl));
3620
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003621 INIT_LIST_HEAD(&wl->list);
3622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003623 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003624 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003625
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003626 for (i = 0; i < NUM_TX_QUEUES; i++)
3627 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003628
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003629 for (i = 0; i < NUM_TX_QUEUES; i++)
3630 for (j = 0; j < AP_MAX_LINKS; j++)
3631 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3632
Ido Yariva6208652011-03-01 15:14:41 +02003633 skb_queue_head_init(&wl->deferred_rx_queue);
3634 skb_queue_head_init(&wl->deferred_tx_queue);
3635
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003636 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003637 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003638 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003639 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3640 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3641 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003642 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003643 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003644 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003645 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003646 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3647 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003648 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003649 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003650 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003651 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003652 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003653 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003654 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003655 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003656 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003657 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003658 wl->bss_type = MAX_BSS_TYPE;
3659 wl->set_bss_type = MAX_BSS_TYPE;
3660 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003661 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003662 wl->ap_ps_map = 0;
3663 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003664 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003665 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003666
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003667 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003668 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003669 wl->tx_frames[i] = NULL;
3670
3671 spin_lock_init(&wl->wl_lock);
3672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003673 wl->state = WL1271_STATE_OFF;
3674 mutex_init(&wl->mutex);
3675
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003676 /* Apply default driver configuration. */
3677 wl1271_conf_init(wl);
3678
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003679 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3680 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3681 if (!wl->aggr_buf) {
3682 ret = -ENOMEM;
3683 goto err_hw;
3684 }
3685
Ido Yariv990f5de2011-03-31 10:06:59 +02003686 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3687 if (!wl->dummy_packet) {
3688 ret = -ENOMEM;
3689 goto err_aggr;
3690 }
3691
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003692 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003693 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003694 if (ret) {
3695 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003696 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003697 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003698 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003699
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003700 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003701 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003702 if (ret < 0) {
3703 wl1271_error("failed to create sysfs file bt_coex_state");
3704 goto err_platform;
3705 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003706
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003707 /* Create sysfs file to get HW PG version */
3708 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3709 if (ret < 0) {
3710 wl1271_error("failed to create sysfs file hw_pg_ver");
3711 goto err_bt_coex_state;
3712 }
3713
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003714 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003715
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003716err_bt_coex_state:
3717 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3718
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003719err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003720 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003721
Ido Yariv990f5de2011-03-31 10:06:59 +02003722err_dummy_packet:
3723 dev_kfree_skb(wl->dummy_packet);
3724
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003725err_aggr:
3726 free_pages((unsigned long)wl->aggr_buf, order);
3727
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003728err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003729 wl1271_debugfs_exit(wl);
3730 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003731
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003732err_plat_alloc:
3733 ieee80211_free_hw(hw);
3734
3735err_hw_alloc:
3736
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003737 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003738}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003739EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003740
3741int wl1271_free_hw(struct wl1271 *wl)
3742{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003743 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003744 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003745 free_pages((unsigned long)wl->aggr_buf,
3746 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003747 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003748
3749 wl1271_debugfs_exit(wl);
3750
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003751 vfree(wl->fw);
3752 wl->fw = NULL;
3753 kfree(wl->nvs);
3754 wl->nvs = NULL;
3755
3756 kfree(wl->fw_status);
3757 kfree(wl->tx_res_if);
3758
3759 ieee80211_free_hw(wl->hw);
3760
3761 return 0;
3762}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003763EXPORT_SYMBOL_GPL(wl1271_free_hw);
3764
Guy Eilam491bbd62011-01-12 10:33:29 +01003765u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003766EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003767module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003768MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3769
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003770MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003771MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003772MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");