blob: 11497a90463b1410e4030400321bea50f4600b89 [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
Shahar Levi564f5952011-04-04 10:20:39 +03001014 /* end-of-transaction flag should be set in wl127x AP mode */
1015 if (wl->bss_type == BSS_TYPE_AP_BSS)
1016 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1017
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 ret = wl1271_setup(wl);
1019 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001020 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001022 case CHIP_ID_1283_PG20:
1023 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1024 wl->chip.id);
1025
1026 ret = wl1271_setup(wl);
1027 if (ret < 0)
1028 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001029 if (wl1271_set_block_size(wl))
1030 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001031 break;
1032 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001034 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001036 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 }
1038
Arik Nemtsov166d5042010-10-16 21:44:57 +02001039 /* Make sure the firmware type matches the BSS type */
1040 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041 ret = wl1271_fetch_firmware(wl);
1042 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001043 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 }
1045
1046 /* No NVS from netlink, try to get it from the filesystem */
1047 if (wl->nvs == NULL) {
1048 ret = wl1271_fetch_nvs(wl);
1049 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001050 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 }
1052
1053out:
1054 return ret;
1055}
1056
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001057static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1058{
1059 unsigned int quirks = 0;
1060 unsigned int *fw_ver = wl->chip.fw_ver;
1061
1062 /* Only for wl127x */
1063 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1064 /* Check STA version */
1065 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1066 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1067 /* Check AP version */
1068 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1069 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1070 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1071
1072 return quirks;
1073}
1074
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075int wl1271_plt_start(struct wl1271 *wl)
1076{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001077 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 int ret;
1079
1080 mutex_lock(&wl->mutex);
1081
1082 wl1271_notice("power up");
1083
1084 if (wl->state != WL1271_STATE_OFF) {
1085 wl1271_error("cannot go into PLT state because not "
1086 "in off state: %d", wl->state);
1087 ret = -EBUSY;
1088 goto out;
1089 }
1090
Arik Nemtsov166d5042010-10-16 21:44:57 +02001091 wl->bss_type = BSS_TYPE_STA_BSS;
1092
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001093 while (retries) {
1094 retries--;
1095 ret = wl1271_chip_wakeup(wl);
1096 if (ret < 0)
1097 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001099 ret = wl1271_boot(wl);
1100 if (ret < 0)
1101 goto power_off;
1102
1103 ret = wl1271_plt_init(wl);
1104 if (ret < 0)
1105 goto irq_disable;
1106
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001107 wl->state = WL1271_STATE_PLT;
1108 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001109 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001110
1111 /* Check if any quirks are needed with older fw versions */
1112 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 goto out;
1114
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001115irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001116 mutex_unlock(&wl->mutex);
1117 /* Unlocking the mutex in the middle of handling is
1118 inherently unsafe. In this case we deem it safe to do,
1119 because we need to let any possibly pending IRQ out of
1120 the system (and while we are WL1271_STATE_OFF the IRQ
1121 work function will not do anything.) Also, any other
1122 possible concurrent operations will fail due to the
1123 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001124 wl1271_disable_interrupts(wl);
1125 wl1271_flush_deferred_work(wl);
1126 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001127 mutex_lock(&wl->mutex);
1128power_off:
1129 wl1271_power_off(wl);
1130 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001131
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001132 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1133 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134out:
1135 mutex_unlock(&wl->mutex);
1136
1137 return ret;
1138}
1139
Luciano Coelho4623ec72011-03-21 19:26:41 +02001140static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141{
1142 int ret = 0;
1143
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001144 wl1271_notice("power down");
1145
1146 if (wl->state != WL1271_STATE_PLT) {
1147 wl1271_error("cannot power down because not in PLT "
1148 "state: %d", wl->state);
1149 ret = -EBUSY;
1150 goto out;
1151 }
1152
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001153 wl1271_power_off(wl);
1154
1155 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001156 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001159 wl1271_disable_interrupts(wl);
1160 wl1271_flush_deferred_work(wl);
1161 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001162 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001163 mutex_lock(&wl->mutex);
1164out:
1165 return ret;
1166}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001167
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001168int wl1271_plt_stop(struct wl1271 *wl)
1169{
1170 int ret;
1171
1172 mutex_lock(&wl->mutex);
1173 ret = __wl1271_plt_stop(wl);
1174 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 return ret;
1176}
1177
Johannes Berg7bb45682011-02-24 14:42:06 +01001178static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179{
1180 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001181 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001182 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001183 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001184
Ido Yarivb07d4032011-03-01 15:14:43 +02001185 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1186
1187 if (wl->bss_type == BSS_TYPE_AP_BSS)
1188 hlid = wl1271_tx_get_hlid(skb);
1189
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001190 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001191
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001192 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001193
1194 /*
1195 * The workqueue is slow to process the tx_queue and we need stop
1196 * the queue here, otherwise the queue will get too long.
1197 */
1198 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1199 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1200 ieee80211_stop_queues(wl->hw);
1201 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1202 }
1203
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001204 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001205 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001206 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1207 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1208 } else {
1209 skb_queue_tail(&wl->tx_queue[q], skb);
1210 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211
1212 /*
1213 * The chip specific setup must run before the first TX packet -
1214 * before that, the tx_work will not be initialized!
1215 */
1216
Ido Yarivb07d4032011-03-01 15:14:43 +02001217 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1218 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001219 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001220
1221 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222}
1223
Shahar Leviae47c452011-03-06 16:32:14 +02001224int wl1271_tx_dummy_packet(struct wl1271 *wl)
1225{
Ido Yariv990f5de2011-03-31 10:06:59 +02001226 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001227
Ido Yariv990f5de2011-03-31 10:06:59 +02001228 spin_lock_irqsave(&wl->wl_lock, flags);
1229 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1230 wl->tx_queue_count++;
1231 spin_unlock_irqrestore(&wl->wl_lock, flags);
1232
1233 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1234 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1235 wl1271_tx_work_locked(wl);
1236
1237 /*
1238 * If the FW TX is busy, TX work will be scheduled by the threaded
1239 * interrupt handler function
1240 */
1241 return 0;
1242}
1243
1244/*
1245 * The size of the dummy packet should be at least 1400 bytes. However, in
1246 * order to minimize the number of bus transactions, aligning it to 512 bytes
1247 * boundaries could be beneficial, performance wise
1248 */
1249#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1250
Luciano Coelhocf27d862011-04-01 21:08:23 +03001251static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001252{
1253 struct sk_buff *skb;
1254 struct ieee80211_hdr_3addr *hdr;
1255 unsigned int dummy_packet_size;
1256
1257 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1258 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1259
1260 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001261 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001262 wl1271_warning("Failed to allocate a dummy packet skb");
1263 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001264 }
1265
1266 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1267
1268 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1269 memset(hdr, 0, sizeof(*hdr));
1270 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001271 IEEE80211_STYPE_NULLFUNC |
1272 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001273
Ido Yariv990f5de2011-03-31 10:06:59 +02001274 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001275
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001276 /* Dummy packets require the TID to be management */
1277 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001278
1279 /* Initialize all fields that might be used */
Shahar Leviae47c452011-03-06 16:32:14 +02001280 skb->queue_mapping = 0;
Ido Yariv990f5de2011-03-31 10:06:59 +02001281 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001282
Ido Yariv990f5de2011-03-31 10:06:59 +02001283 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001284}
1285
Ido Yariv990f5de2011-03-31 10:06:59 +02001286
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001287static struct notifier_block wl1271_dev_notifier = {
1288 .notifier_call = wl1271_dev_notify,
1289};
1290
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291static int wl1271_op_start(struct ieee80211_hw *hw)
1292{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001293 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1294
1295 /*
1296 * We have to delay the booting of the hardware because
1297 * we need to know the local MAC address before downloading and
1298 * initializing the firmware. The MAC address cannot be changed
1299 * after boot, and without the proper MAC address, the firmware
1300 * will not function properly.
1301 *
1302 * The MAC address is first known when the corresponding interface
1303 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001304 *
1305 * In addition, we currently have different firmwares for AP and managed
1306 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001307 */
1308
1309 return 0;
1310}
1311
1312static void wl1271_op_stop(struct ieee80211_hw *hw)
1313{
1314 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1315}
1316
1317static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1318 struct ieee80211_vif *vif)
1319{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001321 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001322 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001324 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001325
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001326 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1327 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
1329 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001330 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001331 wl1271_debug(DEBUG_MAC80211,
1332 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001333 ret = -EBUSY;
1334 goto out;
1335 }
1336
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001337 /*
1338 * in some very corner case HW recovery scenarios its possible to
1339 * get here before __wl1271_op_remove_interface is complete, so
1340 * opt out if that is the case.
1341 */
1342 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1343 ret = -EBUSY;
1344 goto out;
1345 }
1346
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001347 switch (vif->type) {
1348 case NL80211_IFTYPE_STATION:
1349 wl->bss_type = BSS_TYPE_STA_BSS;
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;
1352 case NL80211_IFTYPE_ADHOC:
1353 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001354 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001355 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001356 case NL80211_IFTYPE_AP:
1357 wl->bss_type = BSS_TYPE_AP_BSS;
1358 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001359 default:
1360 ret = -EOPNOTSUPP;
1361 goto out;
1362 }
1363
1364 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365
1366 if (wl->state != WL1271_STATE_OFF) {
1367 wl1271_error("cannot start because not in off state: %d",
1368 wl->state);
1369 ret = -EBUSY;
1370 goto out;
1371 }
1372
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001373 while (retries) {
1374 retries--;
1375 ret = wl1271_chip_wakeup(wl);
1376 if (ret < 0)
1377 goto power_off;
1378
1379 ret = wl1271_boot(wl);
1380 if (ret < 0)
1381 goto power_off;
1382
1383 ret = wl1271_hw_init(wl);
1384 if (ret < 0)
1385 goto irq_disable;
1386
Eliad Peller71125ab2010-10-28 21:46:43 +02001387 booted = true;
1388 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001390irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391 mutex_unlock(&wl->mutex);
1392 /* Unlocking the mutex in the middle of handling is
1393 inherently unsafe. In this case we deem it safe to do,
1394 because we need to let any possibly pending IRQ out of
1395 the system (and while we are WL1271_STATE_OFF the IRQ
1396 work function will not do anything.) Also, any other
1397 possible concurrent operations will fail due to the
1398 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001399 wl1271_disable_interrupts(wl);
1400 wl1271_flush_deferred_work(wl);
1401 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001402 mutex_lock(&wl->mutex);
1403power_off:
1404 wl1271_power_off(wl);
1405 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406
Eliad Peller71125ab2010-10-28 21:46:43 +02001407 if (!booted) {
1408 wl1271_error("firmware boot failed despite %d retries",
1409 WL1271_BOOT_RETRIES);
1410 goto out;
1411 }
1412
1413 wl->vif = vif;
1414 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001415 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001416 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001417
1418 /* update hw/fw version info in wiphy struct */
1419 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001420 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001421 sizeof(wiphy->fw_version));
1422
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001423 /* Check if any quirks are needed with older fw versions */
1424 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1425
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001426 /*
1427 * Now we know if 11a is supported (info from the NVS), so disable
1428 * 11a channels if not supported
1429 */
1430 if (!wl->enable_11a)
1431 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1432
1433 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1434 wl->enable_11a ? "" : "not ");
1435
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001436out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437 mutex_unlock(&wl->mutex);
1438
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001439 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001440 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001441 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001442 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 return ret;
1445}
1446
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001447static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449 int i;
1450
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001451 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001453 /* because of hardware recovery, we may get here twice */
1454 if (wl->state != WL1271_STATE_ON)
1455 return;
1456
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001457 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001459 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001460 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001461 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001462
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001463 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001464 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001465 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001466
Luciano Coelho08688d62010-07-08 17:50:07 +03001467 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001468 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001469 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001470 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001471 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 }
1473
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001474 /*
1475 * this must be before the cancel_work calls below, so that the work
1476 * functions don't perform further work.
1477 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 wl->state = WL1271_STATE_OFF;
1479
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480 mutex_unlock(&wl->mutex);
1481
Ido Yariva6208652011-03-01 15:14:41 +02001482 wl1271_disable_interrupts(wl);
1483 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001484 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001485 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001487 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001488 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489
1490 mutex_lock(&wl->mutex);
1491
1492 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001493 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494 wl1271_power_off(wl);
1495
1496 memset(wl->bssid, 0, ETH_ALEN);
1497 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1498 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001500 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001501 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502
1503 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001504 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1506 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001507 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 wl->tx_results_count = 0;
1509 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001510 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001511 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512 wl->time_offset = 0;
1513 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001514 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001515 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001516 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001517 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001518 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001519 wl->ap_fw_ps_map = 0;
1520 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001521
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001522 /*
1523 * this is performed after the cancel_work calls and the associated
1524 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1525 * get executed before all these vars have been reset.
1526 */
1527 wl->flags = 0;
1528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 for (i = 0; i < NUM_TX_QUEUES; i++)
1530 wl->tx_blocks_freed[i] = 0;
1531
1532 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001533
1534 kfree(wl->fw_status);
1535 wl->fw_status = NULL;
1536 kfree(wl->tx_res_if);
1537 wl->tx_res_if = NULL;
1538 kfree(wl->target_mem_map);
1539 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001540}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001541
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001542static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1543 struct ieee80211_vif *vif)
1544{
1545 struct wl1271 *wl = hw->priv;
1546
1547 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001548 /*
1549 * wl->vif can be null here if someone shuts down the interface
1550 * just when hardware recovery has been started.
1551 */
1552 if (wl->vif) {
1553 WARN_ON(wl->vif != vif);
1554 __wl1271_op_remove_interface(wl);
1555 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001556
Juuso Oikarinen67353292010-11-18 15:19:02 +02001557 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001558 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559}
1560
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001561void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001562{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001563 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001564
1565 /* combine requested filters with current filter config */
1566 filters = wl->filters | filters;
1567
1568 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1569
1570 if (filters & FIF_PROMISC_IN_BSS) {
1571 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1572 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1573 wl->rx_config |= CFG_BSSID_FILTER_EN;
1574 }
1575 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1576 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1577 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1578 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1579 }
1580 if (filters & FIF_OTHER_BSS) {
1581 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1582 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1583 }
1584 if (filters & FIF_CONTROL) {
1585 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1586 wl->rx_filter |= CFG_RX_CTL_EN;
1587 }
1588 if (filters & FIF_FCSFAIL) {
1589 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1590 wl->rx_filter |= CFG_RX_FCS_ERROR;
1591 }
1592}
1593
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001594static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001595{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001596 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001597 /* we need to use a dummy BSSID for now */
1598 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1599 0xad, 0xbe, 0xef };
1600
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001601 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1602
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001603 /* pass through frames from all BSS */
1604 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1605
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001606 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001607 if (ret < 0)
1608 goto out;
1609
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001610 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001611
1612out:
1613 return ret;
1614}
1615
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001616static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001617{
1618 int ret;
1619
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001620 /*
1621 * One of the side effects of the JOIN command is that is clears
1622 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1623 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001624 * Currently the only valid scenario for JOIN during association
1625 * is on roaming, in which case we will also be given new keys.
1626 * Keep the below message for now, unless it starts bothering
1627 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001628 */
1629 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1630 wl1271_info("JOIN while associated.");
1631
1632 if (set_assoc)
1633 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1634
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001635 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1636 if (ret < 0)
1637 goto out;
1638
1639 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1640
1641 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1642 goto out;
1643
1644 /*
1645 * The join command disable the keep-alive mode, shut down its process,
1646 * and also clear the template config, so we need to reset it all after
1647 * the join. The acx_aid starts the keep-alive process, and the order
1648 * of the commands below is relevant.
1649 */
1650 ret = wl1271_acx_keep_alive_mode(wl, true);
1651 if (ret < 0)
1652 goto out;
1653
1654 ret = wl1271_acx_aid(wl, wl->aid);
1655 if (ret < 0)
1656 goto out;
1657
1658 ret = wl1271_cmd_build_klv_null_data(wl);
1659 if (ret < 0)
1660 goto out;
1661
1662 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1663 ACX_KEEP_ALIVE_TPL_VALID);
1664 if (ret < 0)
1665 goto out;
1666
1667out:
1668 return ret;
1669}
1670
1671static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001672{
1673 int ret;
1674
1675 /* to stop listening to a channel, we disconnect */
1676 ret = wl1271_cmd_disconnect(wl);
1677 if (ret < 0)
1678 goto out;
1679
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001680 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001681 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001682
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001683 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001684 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001685
1686out:
1687 return ret;
1688}
1689
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001690static void wl1271_set_band_rate(struct wl1271 *wl)
1691{
1692 if (wl->band == IEEE80211_BAND_2GHZ)
1693 wl->basic_rate_set = wl->conf.tx.basic_rate;
1694 else
1695 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1696}
1697
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001698static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001699{
1700 int ret;
1701
1702 if (idle) {
1703 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1704 ret = wl1271_unjoin(wl);
1705 if (ret < 0)
1706 goto out;
1707 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001708 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001709 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001710 if (ret < 0)
1711 goto out;
1712 ret = wl1271_acx_keep_alive_config(
1713 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1714 ACX_KEEP_ALIVE_TPL_INVALID);
1715 if (ret < 0)
1716 goto out;
1717 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1718 } else {
1719 /* increment the session counter */
1720 wl->session_counter++;
1721 if (wl->session_counter >= SESSION_COUNTER_MAX)
1722 wl->session_counter = 0;
1723 ret = wl1271_dummy_join(wl);
1724 if (ret < 0)
1725 goto out;
1726 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1727 }
1728
1729out:
1730 return ret;
1731}
1732
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001733static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1734{
1735 struct wl1271 *wl = hw->priv;
1736 struct ieee80211_conf *conf = &hw->conf;
1737 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001738 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739
1740 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1741
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001742 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1743 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001744 channel,
1745 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001746 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001747 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1748 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001750 /*
1751 * mac80211 will go to idle nearly immediately after transmitting some
1752 * frames, such as the deauth. To make sure those frames reach the air,
1753 * wait here until the TX queue is fully flushed.
1754 */
1755 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1756 (conf->flags & IEEE80211_CONF_IDLE))
1757 wl1271_tx_flush(wl);
1758
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759 mutex_lock(&wl->mutex);
1760
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001761 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001762 /* we support configuring the channel and band while off */
1763 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1764 wl->band = conf->channel->band;
1765 wl->channel = channel;
1766 }
1767
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001768 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001769 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001770
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001771 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1772
Ido Yariva6208652011-03-01 15:14:41 +02001773 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 if (ret < 0)
1775 goto out;
1776
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001777 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001778 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1779 ((wl->band != conf->channel->band) ||
1780 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001781 wl->band = conf->channel->band;
1782 wl->channel = channel;
1783
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001784 if (!is_ap) {
1785 /*
1786 * FIXME: the mac80211 should really provide a fixed
1787 * rate to use here. for now, just use the smallest
1788 * possible rate for the band as a fixed rate for
1789 * association frames and other control messages.
1790 */
1791 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1792 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001793
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001794 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1795 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001796 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001797 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001798 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001799
1800 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1801 ret = wl1271_join(wl, false);
1802 if (ret < 0)
1803 wl1271_warning("cmd join on channel "
1804 "failed %d", ret);
1805 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001806 }
1807 }
1808
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001809 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1810 ret = wl1271_sta_handle_idle(wl,
1811 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001812 if (ret < 0)
1813 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 }
1815
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001816 /*
1817 * if mac80211 changes the PSM mode, make sure the mode is not
1818 * incorrectly changed after the pspoll failure active window.
1819 */
1820 if (changed & IEEE80211_CONF_CHANGE_PS)
1821 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1822
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001823 if (conf->flags & IEEE80211_CONF_PS &&
1824 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1825 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826
1827 /*
1828 * We enter PSM only if we're already associated.
1829 * If we're not, we'll enter it when joining an SSID,
1830 * through the bss_info_changed() hook.
1831 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001832 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001833 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001834 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001835 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001836 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001838 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001839 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001841 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001843 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001844 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001845 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 }
1847
1848 if (conf->power_level != wl->power_level) {
1849 ret = wl1271_acx_tx_power(wl, conf->power_level);
1850 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001851 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852
1853 wl->power_level = conf->power_level;
1854 }
1855
1856out_sleep:
1857 wl1271_ps_elp_sleep(wl);
1858
1859out:
1860 mutex_unlock(&wl->mutex);
1861
1862 return ret;
1863}
1864
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001865struct wl1271_filter_params {
1866 bool enabled;
1867 int mc_list_length;
1868 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1869};
1870
Jiri Pirko22bedad2010-04-01 21:22:57 +00001871static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1872 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001873{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001874 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001875 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001876 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001877
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001878 if (unlikely(wl->state == WL1271_STATE_OFF))
1879 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001880
Juuso Oikarinen74441132009-10-13 12:47:53 +03001881 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001882 if (!fp) {
1883 wl1271_error("Out of memory setting filters.");
1884 return 0;
1885 }
1886
1887 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001888 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001889 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1890 fp->enabled = false;
1891 } else {
1892 fp->enabled = true;
1893 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001894 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001895 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001896 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001897 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001898 }
1899
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001900 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001901}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001903#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1904 FIF_ALLMULTI | \
1905 FIF_FCSFAIL | \
1906 FIF_BCN_PRBRESP_PROMISC | \
1907 FIF_CONTROL | \
1908 FIF_OTHER_BSS)
1909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1911 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001912 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001914 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001916 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001917
Arik Nemtsov7d057862010-10-16 19:25:35 +02001918 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1919 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001921 mutex_lock(&wl->mutex);
1922
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001923 *total &= WL1271_SUPPORTED_FILTERS;
1924 changed &= WL1271_SUPPORTED_FILTERS;
1925
1926 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001927 goto out;
1928
Ido Yariva6208652011-03-01 15:14:41 +02001929 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001930 if (ret < 0)
1931 goto out;
1932
Arik Nemtsov7d057862010-10-16 19:25:35 +02001933 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1934 if (*total & FIF_ALLMULTI)
1935 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1936 else if (fp)
1937 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1938 fp->mc_list,
1939 fp->mc_list_length);
1940 if (ret < 0)
1941 goto out_sleep;
1942 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001944 /* determine, whether supported filter values have changed */
1945 if (changed == 0)
1946 goto out_sleep;
1947
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001948 /* configure filters */
1949 wl->filters = *total;
1950 wl1271_configure_filters(wl, 0);
1951
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001952 /* apply configured filters */
1953 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1954 if (ret < 0)
1955 goto out_sleep;
1956
1957out_sleep:
1958 wl1271_ps_elp_sleep(wl);
1959
1960out:
1961 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001962 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963}
1964
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001965static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1966 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1967 u16 tx_seq_16)
1968{
1969 struct wl1271_ap_key *ap_key;
1970 int i;
1971
1972 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1973
1974 if (key_size > MAX_KEY_SIZE)
1975 return -EINVAL;
1976
1977 /*
1978 * Find next free entry in ap_keys. Also check we are not replacing
1979 * an existing key.
1980 */
1981 for (i = 0; i < MAX_NUM_KEYS; i++) {
1982 if (wl->recorded_ap_keys[i] == NULL)
1983 break;
1984
1985 if (wl->recorded_ap_keys[i]->id == id) {
1986 wl1271_warning("trying to record key replacement");
1987 return -EINVAL;
1988 }
1989 }
1990
1991 if (i == MAX_NUM_KEYS)
1992 return -EBUSY;
1993
1994 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1995 if (!ap_key)
1996 return -ENOMEM;
1997
1998 ap_key->id = id;
1999 ap_key->key_type = key_type;
2000 ap_key->key_size = key_size;
2001 memcpy(ap_key->key, key, key_size);
2002 ap_key->hlid = hlid;
2003 ap_key->tx_seq_32 = tx_seq_32;
2004 ap_key->tx_seq_16 = tx_seq_16;
2005
2006 wl->recorded_ap_keys[i] = ap_key;
2007 return 0;
2008}
2009
2010static void wl1271_free_ap_keys(struct wl1271 *wl)
2011{
2012 int i;
2013
2014 for (i = 0; i < MAX_NUM_KEYS; i++) {
2015 kfree(wl->recorded_ap_keys[i]);
2016 wl->recorded_ap_keys[i] = NULL;
2017 }
2018}
2019
2020static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2021{
2022 int i, ret = 0;
2023 struct wl1271_ap_key *key;
2024 bool wep_key_added = false;
2025
2026 for (i = 0; i < MAX_NUM_KEYS; i++) {
2027 if (wl->recorded_ap_keys[i] == NULL)
2028 break;
2029
2030 key = wl->recorded_ap_keys[i];
2031 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2032 key->id, key->key_type,
2033 key->key_size, key->key,
2034 key->hlid, key->tx_seq_32,
2035 key->tx_seq_16);
2036 if (ret < 0)
2037 goto out;
2038
2039 if (key->key_type == KEY_WEP)
2040 wep_key_added = true;
2041 }
2042
2043 if (wep_key_added) {
2044 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2045 if (ret < 0)
2046 goto out;
2047 }
2048
2049out:
2050 wl1271_free_ap_keys(wl);
2051 return ret;
2052}
2053
2054static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2055 u8 key_size, const u8 *key, u32 tx_seq_32,
2056 u16 tx_seq_16, struct ieee80211_sta *sta)
2057{
2058 int ret;
2059 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2060
2061 if (is_ap) {
2062 struct wl1271_station *wl_sta;
2063 u8 hlid;
2064
2065 if (sta) {
2066 wl_sta = (struct wl1271_station *)sta->drv_priv;
2067 hlid = wl_sta->hlid;
2068 } else {
2069 hlid = WL1271_AP_BROADCAST_HLID;
2070 }
2071
2072 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2073 /*
2074 * We do not support removing keys after AP shutdown.
2075 * Pretend we do to make mac80211 happy.
2076 */
2077 if (action != KEY_ADD_OR_REPLACE)
2078 return 0;
2079
2080 ret = wl1271_record_ap_key(wl, id,
2081 key_type, key_size,
2082 key, hlid, tx_seq_32,
2083 tx_seq_16);
2084 } else {
2085 ret = wl1271_cmd_set_ap_key(wl, action,
2086 id, key_type, key_size,
2087 key, hlid, tx_seq_32,
2088 tx_seq_16);
2089 }
2090
2091 if (ret < 0)
2092 return ret;
2093 } else {
2094 const u8 *addr;
2095 static const u8 bcast_addr[ETH_ALEN] = {
2096 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2097 };
2098
2099 addr = sta ? sta->addr : bcast_addr;
2100
2101 if (is_zero_ether_addr(addr)) {
2102 /* We dont support TX only encryption */
2103 return -EOPNOTSUPP;
2104 }
2105
2106 /* The wl1271 does not allow to remove unicast keys - they
2107 will be cleared automatically on next CMD_JOIN. Ignore the
2108 request silently, as we dont want the mac80211 to emit
2109 an error message. */
2110 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2111 return 0;
2112
2113 ret = wl1271_cmd_set_sta_key(wl, action,
2114 id, key_type, key_size,
2115 key, addr, tx_seq_32,
2116 tx_seq_16);
2117 if (ret < 0)
2118 return ret;
2119
2120 /* the default WEP key needs to be configured at least once */
2121 if (key_type == KEY_WEP) {
2122 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2123 wl->default_key);
2124 if (ret < 0)
2125 return ret;
2126 }
2127 }
2128
2129 return 0;
2130}
2131
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2133 struct ieee80211_vif *vif,
2134 struct ieee80211_sta *sta,
2135 struct ieee80211_key_conf *key_conf)
2136{
2137 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002139 u32 tx_seq_32 = 0;
2140 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141 u8 key_type;
2142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2144
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002145 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002147 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148 key_conf->keylen, key_conf->flags);
2149 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2150
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151 mutex_lock(&wl->mutex);
2152
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002153 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2154 ret = -EAGAIN;
2155 goto out_unlock;
2156 }
2157
Ido Yariva6208652011-03-01 15:14:41 +02002158 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159 if (ret < 0)
2160 goto out_unlock;
2161
Johannes Berg97359d12010-08-10 09:46:38 +02002162 switch (key_conf->cipher) {
2163 case WLAN_CIPHER_SUITE_WEP40:
2164 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 key_type = KEY_WEP;
2166
2167 key_conf->hw_key_idx = key_conf->keyidx;
2168 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002169 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170 key_type = KEY_TKIP;
2171
2172 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002173 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2174 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002175 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002176 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177 key_type = KEY_AES;
2178
2179 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002180 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2181 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002183 case WL1271_CIPHER_SUITE_GEM:
2184 key_type = KEY_GEM;
2185 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2186 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2187 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002188 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002189 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190
2191 ret = -EOPNOTSUPP;
2192 goto out_sleep;
2193 }
2194
2195 switch (cmd) {
2196 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002197 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2198 key_conf->keyidx, key_type,
2199 key_conf->keylen, key_conf->key,
2200 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 if (ret < 0) {
2202 wl1271_error("Could not add or replace key");
2203 goto out_sleep;
2204 }
2205 break;
2206
2207 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002208 ret = wl1271_set_key(wl, KEY_REMOVE,
2209 key_conf->keyidx, key_type,
2210 key_conf->keylen, key_conf->key,
2211 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002212 if (ret < 0) {
2213 wl1271_error("Could not remove key");
2214 goto out_sleep;
2215 }
2216 break;
2217
2218 default:
2219 wl1271_error("Unsupported key cmd 0x%x", cmd);
2220 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221 break;
2222 }
2223
2224out_sleep:
2225 wl1271_ps_elp_sleep(wl);
2226
2227out_unlock:
2228 mutex_unlock(&wl->mutex);
2229
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002230 return ret;
2231}
2232
2233static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002234 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002235 struct cfg80211_scan_request *req)
2236{
2237 struct wl1271 *wl = hw->priv;
2238 int ret;
2239 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002240 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002241
2242 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2243
2244 if (req->n_ssids) {
2245 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002246 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247 }
2248
2249 mutex_lock(&wl->mutex);
2250
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002251 if (wl->state == WL1271_STATE_OFF) {
2252 /*
2253 * We cannot return -EBUSY here because cfg80211 will expect
2254 * a call to ieee80211_scan_completed if we do - in this case
2255 * there won't be any call.
2256 */
2257 ret = -EAGAIN;
2258 goto out;
2259 }
2260
Ido Yariva6208652011-03-01 15:14:41 +02002261 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262 if (ret < 0)
2263 goto out;
2264
Luciano Coelho5924f892010-08-04 03:46:22 +03002265 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266
2267 wl1271_ps_elp_sleep(wl);
2268
2269out:
2270 mutex_unlock(&wl->mutex);
2271
2272 return ret;
2273}
2274
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002275static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2276{
2277 struct wl1271 *wl = hw->priv;
2278 int ret = 0;
2279
2280 mutex_lock(&wl->mutex);
2281
2282 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2283 ret = -EAGAIN;
2284 goto out;
2285 }
2286
Ido Yariva6208652011-03-01 15:14:41 +02002287 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002288 if (ret < 0)
2289 goto out;
2290
2291 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2292 if (ret < 0)
2293 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2294
2295 wl1271_ps_elp_sleep(wl);
2296
2297out:
2298 mutex_unlock(&wl->mutex);
2299
2300 return ret;
2301}
2302
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2304{
2305 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002306 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002307
2308 mutex_lock(&wl->mutex);
2309
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002310 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2311 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002312 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002313 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002314
Ido Yariva6208652011-03-01 15:14:41 +02002315 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316 if (ret < 0)
2317 goto out;
2318
2319 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2320 if (ret < 0)
2321 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2322
2323 wl1271_ps_elp_sleep(wl);
2324
2325out:
2326 mutex_unlock(&wl->mutex);
2327
2328 return ret;
2329}
2330
Arik Nemtsove78a2872010-10-16 19:07:21 +02002331static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002332 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002333{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002334 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002335
2336 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002337 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002338 if (ptr[0] == WLAN_EID_SSID) {
2339 wl->ssid_len = ptr[1];
2340 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002342 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002343 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002344 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002345
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002346 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002347 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002348}
2349
Arik Nemtsove78a2872010-10-16 19:07:21 +02002350static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2351 struct ieee80211_bss_conf *bss_conf,
2352 u32 changed)
2353{
2354 int ret = 0;
2355
2356 if (changed & BSS_CHANGED_ERP_SLOT) {
2357 if (bss_conf->use_short_slot)
2358 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2359 else
2360 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2361 if (ret < 0) {
2362 wl1271_warning("Set slot time failed %d", ret);
2363 goto out;
2364 }
2365 }
2366
2367 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2368 if (bss_conf->use_short_preamble)
2369 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2370 else
2371 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2372 }
2373
2374 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2375 if (bss_conf->use_cts_prot)
2376 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2377 else
2378 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2379 if (ret < 0) {
2380 wl1271_warning("Set ctsprotect failed %d", ret);
2381 goto out;
2382 }
2383 }
2384
2385out:
2386 return ret;
2387}
2388
2389static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2390 struct ieee80211_vif *vif,
2391 struct ieee80211_bss_conf *bss_conf,
2392 u32 changed)
2393{
2394 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2395 int ret = 0;
2396
2397 if ((changed & BSS_CHANGED_BEACON_INT)) {
2398 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2399 bss_conf->beacon_int);
2400
2401 wl->beacon_int = bss_conf->beacon_int;
2402 }
2403
2404 if ((changed & BSS_CHANGED_BEACON)) {
2405 struct ieee80211_hdr *hdr;
2406 int ieoffset = offsetof(struct ieee80211_mgmt,
2407 u.beacon.variable);
2408 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2409 u16 tmpl_id;
2410
2411 if (!beacon)
2412 goto out;
2413
2414 wl1271_debug(DEBUG_MASTER, "beacon updated");
2415
2416 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2417 if (ret < 0) {
2418 dev_kfree_skb(beacon);
2419 goto out;
2420 }
2421 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2422 CMD_TEMPL_BEACON;
2423 ret = wl1271_cmd_template_set(wl, tmpl_id,
2424 beacon->data,
2425 beacon->len, 0,
2426 wl1271_tx_min_rate_get(wl));
2427 if (ret < 0) {
2428 dev_kfree_skb(beacon);
2429 goto out;
2430 }
2431
2432 hdr = (struct ieee80211_hdr *) beacon->data;
2433 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2434 IEEE80211_STYPE_PROBE_RESP);
2435
2436 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2437 CMD_TEMPL_PROBE_RESPONSE;
2438 ret = wl1271_cmd_template_set(wl,
2439 tmpl_id,
2440 beacon->data,
2441 beacon->len, 0,
2442 wl1271_tx_min_rate_get(wl));
2443 dev_kfree_skb(beacon);
2444 if (ret < 0)
2445 goto out;
2446 }
2447
2448out:
2449 return ret;
2450}
2451
2452/* AP mode changes */
2453static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454 struct ieee80211_vif *vif,
2455 struct ieee80211_bss_conf *bss_conf,
2456 u32 changed)
2457{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002458 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002459
Arik Nemtsove78a2872010-10-16 19:07:21 +02002460 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2461 u32 rates = bss_conf->basic_rates;
2462 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002463
Arik Nemtsove78a2872010-10-16 19:07:21 +02002464 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2465 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2466 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2467 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468
Arik Nemtsove78a2872010-10-16 19:07:21 +02002469 /* update the AP management rate policy with the new rates */
2470 mgmt_rc.enabled_rates = wl->basic_rate_set;
2471 mgmt_rc.long_retry_limit = 10;
2472 mgmt_rc.short_retry_limit = 10;
2473 mgmt_rc.aflags = 0;
2474 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2475 ACX_TX_AP_MODE_MGMT_RATE);
2476 if (ret < 0) {
2477 wl1271_error("AP mgmt policy change failed %d", ret);
2478 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002479 }
2480 }
2481
Arik Nemtsove78a2872010-10-16 19:07:21 +02002482 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2483 if (ret < 0)
2484 goto out;
2485
2486 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2487 if (bss_conf->enable_beacon) {
2488 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2489 ret = wl1271_cmd_start_bss(wl);
2490 if (ret < 0)
2491 goto out;
2492
2493 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2494 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002495
2496 ret = wl1271_ap_init_hwenc(wl);
2497 if (ret < 0)
2498 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002499 }
2500 } else {
2501 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2502 ret = wl1271_cmd_stop_bss(wl);
2503 if (ret < 0)
2504 goto out;
2505
2506 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2507 wl1271_debug(DEBUG_AP, "stopped AP");
2508 }
2509 }
2510 }
2511
2512 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2513 if (ret < 0)
2514 goto out;
2515out:
2516 return;
2517}
2518
2519/* STA/IBSS mode changes */
2520static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2521 struct ieee80211_vif *vif,
2522 struct ieee80211_bss_conf *bss_conf,
2523 u32 changed)
2524{
2525 bool do_join = false, set_assoc = false;
2526 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002527 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002528 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002529 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002530 bool sta_exists = false;
2531 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002532
2533 if (is_ibss) {
2534 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2535 changed);
2536 if (ret < 0)
2537 goto out;
2538 }
2539
2540 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2541 do_join = true;
2542
2543 /* Need to update the SSID (for filtering etc) */
2544 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2545 do_join = true;
2546
2547 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002548 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2549 bss_conf->enable_beacon ? "enabled" : "disabled");
2550
2551 if (bss_conf->enable_beacon)
2552 wl->set_bss_type = BSS_TYPE_IBSS;
2553 else
2554 wl->set_bss_type = BSS_TYPE_STA_BSS;
2555 do_join = true;
2556 }
2557
Arik Nemtsove78a2872010-10-16 19:07:21 +02002558 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002559 bool enable = false;
2560 if (bss_conf->cqm_rssi_thold)
2561 enable = true;
2562 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2563 bss_conf->cqm_rssi_thold,
2564 bss_conf->cqm_rssi_hyst);
2565 if (ret < 0)
2566 goto out;
2567 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2568 }
2569
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002570 if ((changed & BSS_CHANGED_BSSID) &&
2571 /*
2572 * Now we know the correct bssid, so we send a new join command
2573 * and enable the BSSID filter
2574 */
2575 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002576 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002577
Eliad Pellerfa287b82010-12-26 09:27:50 +01002578 if (!is_zero_ether_addr(wl->bssid)) {
2579 ret = wl1271_cmd_build_null_data(wl);
2580 if (ret < 0)
2581 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002582
Eliad Pellerfa287b82010-12-26 09:27:50 +01002583 ret = wl1271_build_qos_null_data(wl);
2584 if (ret < 0)
2585 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002586
Eliad Pellerfa287b82010-12-26 09:27:50 +01002587 /* filter out all packets not from this BSSID */
2588 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002589
Eliad Pellerfa287b82010-12-26 09:27:50 +01002590 /* Need to update the BSSID (for filtering etc) */
2591 do_join = true;
2592 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002593 }
2594
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002595 rcu_read_lock();
2596 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2597 if (sta) {
2598 /* save the supp_rates of the ap */
2599 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2600 if (sta->ht_cap.ht_supported)
2601 sta_rate_set |=
2602 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002603 sta_ht_cap = sta->ht_cap;
2604 sta_exists = true;
2605 }
2606 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002607
Arik Nemtsova1008852011-02-12 23:24:20 +02002608 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002609 /* handle new association with HT and HT information change */
2610 if ((changed & BSS_CHANGED_HT) &&
2611 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002612 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002613 true);
2614 if (ret < 0) {
2615 wl1271_warning("Set ht cap true failed %d",
2616 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002617 goto out;
2618 }
2619 ret = wl1271_acx_set_ht_information(wl,
2620 bss_conf->ht_operation_mode);
2621 if (ret < 0) {
2622 wl1271_warning("Set ht information failed %d",
2623 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002624 goto out;
2625 }
2626 }
2627 /* handle new association without HT and disassociation */
2628 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002629 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002630 false);
2631 if (ret < 0) {
2632 wl1271_warning("Set ht cap false failed %d",
2633 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002634 goto out;
2635 }
2636 }
2637 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002638
Arik Nemtsove78a2872010-10-16 19:07:21 +02002639 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002641 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002642 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002643 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002644 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002645
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002646 wl->ps_poll_failures = 0;
2647
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002648 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002649 * use basic rates from AP, and determine lowest rate
2650 * to use with control frames.
2651 */
2652 rates = bss_conf->basic_rates;
2653 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2654 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002655 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002656 if (sta_rate_set)
2657 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2658 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002659 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002660 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002661 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002662
2663 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002664 * with wl1271, we don't need to update the
2665 * beacon_int and dtim_period, because the firmware
2666 * updates it by itself when the first beacon is
2667 * received after a join.
2668 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002669 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2670 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002671 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002672
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002673 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002674 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002675 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002676 dev_kfree_skb(wl->probereq);
2677 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2678 ieoffset = offsetof(struct ieee80211_mgmt,
2679 u.probe_req.variable);
2680 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002681
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002682 /* enable the connection monitoring feature */
2683 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002685 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686
2687 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002688 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2689 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002690 enum wl1271_cmd_ps_mode mode;
2691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002693 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002694 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002695 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002697 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002698 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002699 } else {
2700 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002701 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002702 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002703 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002704
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002705 /* free probe-request template */
2706 dev_kfree_skb(wl->probereq);
2707 wl->probereq = NULL;
2708
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002709 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002710 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002711
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002712 /* revert back to minimum rates for the current band */
2713 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002714 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002715 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002716 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002717 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002718
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002719 /* disable connection monitor features */
2720 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002721
2722 /* Disable the keep-alive feature */
2723 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002724 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002725 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002726
2727 /* restore the bssid filter and go to dummy bssid */
2728 wl1271_unjoin(wl);
2729 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730 }
2731 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002732
Arik Nemtsove78a2872010-10-16 19:07:21 +02002733 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2734 if (ret < 0)
2735 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002737 if (changed & BSS_CHANGED_ARP_FILTER) {
2738 __be32 addr = bss_conf->arp_addr_list[0];
2739 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2740
Eliad Pellerc5312772010-12-09 11:31:27 +02002741 if (bss_conf->arp_addr_cnt == 1 &&
2742 bss_conf->arp_filter_enabled) {
2743 /*
2744 * The template should have been configured only upon
2745 * association. however, it seems that the correct ip
2746 * isn't being set (when sending), so we have to
2747 * reconfigure the template upon every ip change.
2748 */
2749 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2750 if (ret < 0) {
2751 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002752 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002753 }
2754
2755 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002756 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002757 addr);
2758 } else
2759 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002760
2761 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002762 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002763 }
2764
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002765 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002766 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002767 if (ret < 0) {
2768 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002769 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002770 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002771 }
2772
Arik Nemtsove78a2872010-10-16 19:07:21 +02002773out:
2774 return;
2775}
2776
2777static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2778 struct ieee80211_vif *vif,
2779 struct ieee80211_bss_conf *bss_conf,
2780 u32 changed)
2781{
2782 struct wl1271 *wl = hw->priv;
2783 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2784 int ret;
2785
2786 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2787 (int)changed);
2788
2789 mutex_lock(&wl->mutex);
2790
2791 if (unlikely(wl->state == WL1271_STATE_OFF))
2792 goto out;
2793
Ido Yariva6208652011-03-01 15:14:41 +02002794 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002795 if (ret < 0)
2796 goto out;
2797
2798 if (is_ap)
2799 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2800 else
2801 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002803 wl1271_ps_elp_sleep(wl);
2804
2805out:
2806 mutex_unlock(&wl->mutex);
2807}
2808
Kalle Valoc6999d82010-02-18 13:25:41 +02002809static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2810 const struct ieee80211_tx_queue_params *params)
2811{
2812 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002813 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002814 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002815
2816 mutex_lock(&wl->mutex);
2817
2818 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2819
Kalle Valo4695dc92010-03-18 12:26:38 +02002820 if (params->uapsd)
2821 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2822 else
2823 ps_scheme = CONF_PS_SCHEME_LEGACY;
2824
Arik Nemtsov488fc542010-10-16 20:33:45 +02002825 if (wl->state == WL1271_STATE_OFF) {
2826 /*
2827 * If the state is off, the parameters will be recorded and
2828 * configured on init. This happens in AP-mode.
2829 */
2830 struct conf_tx_ac_category *conf_ac =
2831 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2832 struct conf_tx_tid *conf_tid =
2833 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2834
2835 conf_ac->ac = wl1271_tx_get_queue(queue);
2836 conf_ac->cw_min = (u8)params->cw_min;
2837 conf_ac->cw_max = params->cw_max;
2838 conf_ac->aifsn = params->aifs;
2839 conf_ac->tx_op_limit = params->txop << 5;
2840
2841 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2842 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2843 conf_tid->tsid = wl1271_tx_get_queue(queue);
2844 conf_tid->ps_scheme = ps_scheme;
2845 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2846 conf_tid->apsd_conf[0] = 0;
2847 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002848 goto out;
2849 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002850
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002851 ret = wl1271_ps_elp_wakeup(wl);
2852 if (ret < 0)
2853 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002854
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002855 /*
2856 * the txop is confed in units of 32us by the mac80211,
2857 * we need us
2858 */
2859 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2860 params->cw_min, params->cw_max,
2861 params->aifs, params->txop << 5);
2862 if (ret < 0)
2863 goto out_sleep;
2864
2865 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2866 CONF_CHANNEL_TYPE_EDCF,
2867 wl1271_tx_get_queue(queue),
2868 ps_scheme, CONF_ACK_POLICY_LEGACY,
2869 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002870
2871out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002872 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002873
2874out:
2875 mutex_unlock(&wl->mutex);
2876
2877 return ret;
2878}
2879
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002880static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2881{
2882
2883 struct wl1271 *wl = hw->priv;
2884 u64 mactime = ULLONG_MAX;
2885 int ret;
2886
2887 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2888
2889 mutex_lock(&wl->mutex);
2890
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002891 if (unlikely(wl->state == WL1271_STATE_OFF))
2892 goto out;
2893
Ido Yariva6208652011-03-01 15:14:41 +02002894 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002895 if (ret < 0)
2896 goto out;
2897
2898 ret = wl1271_acx_tsf_info(wl, &mactime);
2899 if (ret < 0)
2900 goto out_sleep;
2901
2902out_sleep:
2903 wl1271_ps_elp_sleep(wl);
2904
2905out:
2906 mutex_unlock(&wl->mutex);
2907 return mactime;
2908}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002909
John W. Linvilleece550d2010-07-28 16:41:06 -04002910static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2911 struct survey_info *survey)
2912{
2913 struct wl1271 *wl = hw->priv;
2914 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002915
John W. Linvilleece550d2010-07-28 16:41:06 -04002916 if (idx != 0)
2917 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002918
John W. Linvilleece550d2010-07-28 16:41:06 -04002919 survey->channel = conf->channel;
2920 survey->filled = SURVEY_INFO_NOISE_DBM;
2921 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002922
John W. Linvilleece550d2010-07-28 16:41:06 -04002923 return 0;
2924}
2925
Arik Nemtsov409622e2011-02-23 00:22:29 +02002926static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002927 struct ieee80211_sta *sta,
2928 u8 *hlid)
2929{
2930 struct wl1271_station *wl_sta;
2931 int id;
2932
2933 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2934 if (id >= AP_MAX_STATIONS) {
2935 wl1271_warning("could not allocate HLID - too much stations");
2936 return -EBUSY;
2937 }
2938
2939 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002940 __set_bit(id, wl->ap_hlid_map);
2941 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2942 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002943 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002944 return 0;
2945}
2946
Arik Nemtsov409622e2011-02-23 00:22:29 +02002947static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002948{
2949 int id = hlid - WL1271_AP_STA_HLID_START;
2950
Arik Nemtsov409622e2011-02-23 00:22:29 +02002951 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2952 return;
2953
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002954 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002955 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002956 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002957 __clear_bit(hlid, &wl->ap_ps_map);
2958 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002959}
2960
Arik Nemtsov47684802011-04-26 23:21:51 +03002961bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
2962{
2963 int id = hlid - WL1271_AP_STA_HLID_START;
2964 return test_bit(id, wl->ap_hlid_map);
2965}
2966
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002967static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2968 struct ieee80211_vif *vif,
2969 struct ieee80211_sta *sta)
2970{
2971 struct wl1271 *wl = hw->priv;
2972 int ret = 0;
2973 u8 hlid;
2974
2975 mutex_lock(&wl->mutex);
2976
2977 if (unlikely(wl->state == WL1271_STATE_OFF))
2978 goto out;
2979
2980 if (wl->bss_type != BSS_TYPE_AP_BSS)
2981 goto out;
2982
2983 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2984
Arik Nemtsov409622e2011-02-23 00:22:29 +02002985 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002986 if (ret < 0)
2987 goto out;
2988
Ido Yariva6208652011-03-01 15:14:41 +02002989 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002990 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002991 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002992
2993 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2994 if (ret < 0)
2995 goto out_sleep;
2996
2997out_sleep:
2998 wl1271_ps_elp_sleep(wl);
2999
Arik Nemtsov409622e2011-02-23 00:22:29 +02003000out_free_sta:
3001 if (ret < 0)
3002 wl1271_free_sta(wl, hlid);
3003
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003004out:
3005 mutex_unlock(&wl->mutex);
3006 return ret;
3007}
3008
3009static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3010 struct ieee80211_vif *vif,
3011 struct ieee80211_sta *sta)
3012{
3013 struct wl1271 *wl = hw->priv;
3014 struct wl1271_station *wl_sta;
3015 int ret = 0, id;
3016
3017 mutex_lock(&wl->mutex);
3018
3019 if (unlikely(wl->state == WL1271_STATE_OFF))
3020 goto out;
3021
3022 if (wl->bss_type != BSS_TYPE_AP_BSS)
3023 goto out;
3024
3025 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3026
3027 wl_sta = (struct wl1271_station *)sta->drv_priv;
3028 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3029 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3030 goto out;
3031
Ido Yariva6208652011-03-01 15:14:41 +02003032 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003033 if (ret < 0)
3034 goto out;
3035
3036 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3037 if (ret < 0)
3038 goto out_sleep;
3039
Arik Nemtsov409622e2011-02-23 00:22:29 +02003040 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003041
3042out_sleep:
3043 wl1271_ps_elp_sleep(wl);
3044
3045out:
3046 mutex_unlock(&wl->mutex);
3047 return ret;
3048}
3049
Luciano Coelho4623ec72011-03-21 19:26:41 +02003050static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3051 struct ieee80211_vif *vif,
3052 enum ieee80211_ampdu_mlme_action action,
3053 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3054 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003055{
3056 struct wl1271 *wl = hw->priv;
3057 int ret;
3058
3059 mutex_lock(&wl->mutex);
3060
3061 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3062 ret = -EAGAIN;
3063 goto out;
3064 }
3065
Ido Yariva6208652011-03-01 15:14:41 +02003066 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003067 if (ret < 0)
3068 goto out;
3069
3070 switch (action) {
3071 case IEEE80211_AMPDU_RX_START:
3072 if (wl->ba_support) {
3073 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3074 true);
3075 if (!ret)
3076 wl->ba_rx_bitmap |= BIT(tid);
3077 } else {
3078 ret = -ENOTSUPP;
3079 }
3080 break;
3081
3082 case IEEE80211_AMPDU_RX_STOP:
3083 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3084 if (!ret)
3085 wl->ba_rx_bitmap &= ~BIT(tid);
3086 break;
3087
3088 /*
3089 * The BA initiator session management in FW independently.
3090 * Falling break here on purpose for all TX APDU commands.
3091 */
3092 case IEEE80211_AMPDU_TX_START:
3093 case IEEE80211_AMPDU_TX_STOP:
3094 case IEEE80211_AMPDU_TX_OPERATIONAL:
3095 ret = -EINVAL;
3096 break;
3097
3098 default:
3099 wl1271_error("Incorrect ampdu action id=%x\n", action);
3100 ret = -EINVAL;
3101 }
3102
3103 wl1271_ps_elp_sleep(wl);
3104
3105out:
3106 mutex_unlock(&wl->mutex);
3107
3108 return ret;
3109}
3110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111/* can't be const, mac80211 writes to this */
3112static struct ieee80211_rate wl1271_rates[] = {
3113 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003114 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3115 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003116 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003117 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3118 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003119 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3120 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003121 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3122 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3124 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003125 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3126 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003127 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3128 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003129 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3130 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003132 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3133 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003134 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003135 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3136 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003138 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3139 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003140 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003141 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3142 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003144 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3145 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003146 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003147 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3148 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003149 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003150 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3151 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003152};
3153
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003154/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003155static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003156 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003157 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003158 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3159 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3160 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003161 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003162 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3163 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3164 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003165 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003166 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3167 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3168 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003169 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003170};
3171
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003172/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003173static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003174 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003175 7, /* CONF_HW_RXTX_RATE_MCS7 */
3176 6, /* CONF_HW_RXTX_RATE_MCS6 */
3177 5, /* CONF_HW_RXTX_RATE_MCS5 */
3178 4, /* CONF_HW_RXTX_RATE_MCS4 */
3179 3, /* CONF_HW_RXTX_RATE_MCS3 */
3180 2, /* CONF_HW_RXTX_RATE_MCS2 */
3181 1, /* CONF_HW_RXTX_RATE_MCS1 */
3182 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003183
3184 11, /* CONF_HW_RXTX_RATE_54 */
3185 10, /* CONF_HW_RXTX_RATE_48 */
3186 9, /* CONF_HW_RXTX_RATE_36 */
3187 8, /* CONF_HW_RXTX_RATE_24 */
3188
3189 /* TI-specific rate */
3190 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3191
3192 7, /* CONF_HW_RXTX_RATE_18 */
3193 6, /* CONF_HW_RXTX_RATE_12 */
3194 3, /* CONF_HW_RXTX_RATE_11 */
3195 5, /* CONF_HW_RXTX_RATE_9 */
3196 4, /* CONF_HW_RXTX_RATE_6 */
3197 2, /* CONF_HW_RXTX_RATE_5_5 */
3198 1, /* CONF_HW_RXTX_RATE_2 */
3199 0 /* CONF_HW_RXTX_RATE_1 */
3200};
3201
Shahar Levie8b03a22010-10-13 16:09:39 +02003202/* 11n STA capabilities */
3203#define HW_RX_HIGHEST_RATE 72
3204
Shahar Levi00d20102010-11-08 11:20:10 +00003205#ifdef CONFIG_WL12XX_HT
3206#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003207 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3208 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003209 .ht_supported = true, \
3210 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3211 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3212 .mcs = { \
3213 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3214 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3215 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3216 }, \
3217}
Shahar Levi18357852010-10-13 16:09:41 +02003218#else
Shahar Levi00d20102010-11-08 11:20:10 +00003219#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003220 .ht_supported = false, \
3221}
3222#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003224/* can't be const, mac80211 writes to this */
3225static struct ieee80211_supported_band wl1271_band_2ghz = {
3226 .channels = wl1271_channels,
3227 .n_channels = ARRAY_SIZE(wl1271_channels),
3228 .bitrates = wl1271_rates,
3229 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003230 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231};
3232
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003233/* 5 GHz data rates for WL1273 */
3234static struct ieee80211_rate wl1271_rates_5ghz[] = {
3235 { .bitrate = 60,
3236 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3237 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3238 { .bitrate = 90,
3239 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3240 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3241 { .bitrate = 120,
3242 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3243 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3244 { .bitrate = 180,
3245 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3246 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3247 { .bitrate = 240,
3248 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3249 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3250 { .bitrate = 360,
3251 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3252 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3253 { .bitrate = 480,
3254 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3255 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3256 { .bitrate = 540,
3257 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3258 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3259};
3260
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003261/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003262static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003263 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003264 { .hw_value = 8, .center_freq = 5040},
3265 { .hw_value = 9, .center_freq = 5045},
3266 { .hw_value = 11, .center_freq = 5055},
3267 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003268 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003269 { .hw_value = 34, .center_freq = 5170},
3270 { .hw_value = 36, .center_freq = 5180},
3271 { .hw_value = 38, .center_freq = 5190},
3272 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003273 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003274 { .hw_value = 44, .center_freq = 5220},
3275 { .hw_value = 46, .center_freq = 5230},
3276 { .hw_value = 48, .center_freq = 5240},
3277 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003278 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003279 { .hw_value = 60, .center_freq = 5300},
3280 { .hw_value = 64, .center_freq = 5320},
3281 { .hw_value = 100, .center_freq = 5500},
3282 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003283 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003284 { .hw_value = 112, .center_freq = 5560},
3285 { .hw_value = 116, .center_freq = 5580},
3286 { .hw_value = 120, .center_freq = 5600},
3287 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003288 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003289 { .hw_value = 132, .center_freq = 5660},
3290 { .hw_value = 136, .center_freq = 5680},
3291 { .hw_value = 140, .center_freq = 5700},
3292 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003293 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003294 { .hw_value = 157, .center_freq = 5785},
3295 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003296 { .hw_value = 165, .center_freq = 5825},
3297};
3298
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003299/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003300static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003301 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003302 7, /* CONF_HW_RXTX_RATE_MCS7 */
3303 6, /* CONF_HW_RXTX_RATE_MCS6 */
3304 5, /* CONF_HW_RXTX_RATE_MCS5 */
3305 4, /* CONF_HW_RXTX_RATE_MCS4 */
3306 3, /* CONF_HW_RXTX_RATE_MCS3 */
3307 2, /* CONF_HW_RXTX_RATE_MCS2 */
3308 1, /* CONF_HW_RXTX_RATE_MCS1 */
3309 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003310
3311 7, /* CONF_HW_RXTX_RATE_54 */
3312 6, /* CONF_HW_RXTX_RATE_48 */
3313 5, /* CONF_HW_RXTX_RATE_36 */
3314 4, /* CONF_HW_RXTX_RATE_24 */
3315
3316 /* TI-specific rate */
3317 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3318
3319 3, /* CONF_HW_RXTX_RATE_18 */
3320 2, /* CONF_HW_RXTX_RATE_12 */
3321 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3322 1, /* CONF_HW_RXTX_RATE_9 */
3323 0, /* CONF_HW_RXTX_RATE_6 */
3324 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3325 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3326 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3327};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003328
3329static struct ieee80211_supported_band wl1271_band_5ghz = {
3330 .channels = wl1271_channels_5ghz,
3331 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3332 .bitrates = wl1271_rates_5ghz,
3333 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003334 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003335};
3336
Tobias Klausera0ea9492010-05-20 10:38:11 +02003337static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003338 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3339 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3340};
3341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003342static const struct ieee80211_ops wl1271_ops = {
3343 .start = wl1271_op_start,
3344 .stop = wl1271_op_stop,
3345 .add_interface = wl1271_op_add_interface,
3346 .remove_interface = wl1271_op_remove_interface,
3347 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003348 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003349 .configure_filter = wl1271_op_configure_filter,
3350 .tx = wl1271_op_tx,
3351 .set_key = wl1271_op_set_key,
3352 .hw_scan = wl1271_op_hw_scan,
3353 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003354 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003355 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003356 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003357 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003358 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003359 .sta_add = wl1271_op_sta_add,
3360 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003361 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003362 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003363};
3364
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003365
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003366u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003367{
3368 u8 idx;
3369
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003370 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003371
3372 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3373 wl1271_error("Illegal RX rate from HW: %d", rate);
3374 return 0;
3375 }
3376
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003377 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003378 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3379 wl1271_error("Unsupported RX rate from HW: %d", rate);
3380 return 0;
3381 }
3382
3383 return idx;
3384}
3385
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003386static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3387 struct device_attribute *attr,
3388 char *buf)
3389{
3390 struct wl1271 *wl = dev_get_drvdata(dev);
3391 ssize_t len;
3392
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003393 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003394
3395 mutex_lock(&wl->mutex);
3396 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3397 wl->sg_enabled);
3398 mutex_unlock(&wl->mutex);
3399
3400 return len;
3401
3402}
3403
3404static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3405 struct device_attribute *attr,
3406 const char *buf, size_t count)
3407{
3408 struct wl1271 *wl = dev_get_drvdata(dev);
3409 unsigned long res;
3410 int ret;
3411
Luciano Coelho6277ed62011-04-01 17:49:54 +03003412 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003413 if (ret < 0) {
3414 wl1271_warning("incorrect value written to bt_coex_mode");
3415 return count;
3416 }
3417
3418 mutex_lock(&wl->mutex);
3419
3420 res = !!res;
3421
3422 if (res == wl->sg_enabled)
3423 goto out;
3424
3425 wl->sg_enabled = res;
3426
3427 if (wl->state == WL1271_STATE_OFF)
3428 goto out;
3429
Ido Yariva6208652011-03-01 15:14:41 +02003430 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003431 if (ret < 0)
3432 goto out;
3433
3434 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3435 wl1271_ps_elp_sleep(wl);
3436
3437 out:
3438 mutex_unlock(&wl->mutex);
3439 return count;
3440}
3441
3442static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3443 wl1271_sysfs_show_bt_coex_state,
3444 wl1271_sysfs_store_bt_coex_state);
3445
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003446static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3447 struct device_attribute *attr,
3448 char *buf)
3449{
3450 struct wl1271 *wl = dev_get_drvdata(dev);
3451 ssize_t len;
3452
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003453 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003454
3455 mutex_lock(&wl->mutex);
3456 if (wl->hw_pg_ver >= 0)
3457 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3458 else
3459 len = snprintf(buf, len, "n/a\n");
3460 mutex_unlock(&wl->mutex);
3461
3462 return len;
3463}
3464
3465static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3466 wl1271_sysfs_show_hw_pg_ver, NULL);
3467
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003468int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003469{
3470 int ret;
3471
3472 if (wl->mac80211_registered)
3473 return 0;
3474
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003475 ret = wl1271_fetch_nvs(wl);
3476 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003477 /* NOTE: The wl->nvs->nvs element must be first, in
3478 * order to simplify the casting, we assume it is at
3479 * the beginning of the wl->nvs structure.
3480 */
3481 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003482
3483 wl->mac_addr[0] = nvs_ptr[11];
3484 wl->mac_addr[1] = nvs_ptr[10];
3485 wl->mac_addr[2] = nvs_ptr[6];
3486 wl->mac_addr[3] = nvs_ptr[5];
3487 wl->mac_addr[4] = nvs_ptr[4];
3488 wl->mac_addr[5] = nvs_ptr[3];
3489 }
3490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003491 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3492
3493 ret = ieee80211_register_hw(wl->hw);
3494 if (ret < 0) {
3495 wl1271_error("unable to register mac80211 hw: %d", ret);
3496 return ret;
3497 }
3498
3499 wl->mac80211_registered = true;
3500
Eliad Pellerd60080a2010-11-24 12:53:16 +02003501 wl1271_debugfs_init(wl);
3502
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003503 register_netdevice_notifier(&wl1271_dev_notifier);
3504
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505 wl1271_notice("loaded");
3506
3507 return 0;
3508}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003509EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003510
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003511void wl1271_unregister_hw(struct wl1271 *wl)
3512{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003513 if (wl->state == WL1271_STATE_PLT)
3514 __wl1271_plt_stop(wl);
3515
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003516 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003517 ieee80211_unregister_hw(wl->hw);
3518 wl->mac80211_registered = false;
3519
3520}
3521EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3522
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003523int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003524{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003525 static const u32 cipher_suites[] = {
3526 WLAN_CIPHER_SUITE_WEP40,
3527 WLAN_CIPHER_SUITE_WEP104,
3528 WLAN_CIPHER_SUITE_TKIP,
3529 WLAN_CIPHER_SUITE_CCMP,
3530 WL1271_CIPHER_SUITE_GEM,
3531 };
3532
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003533 /* The tx descriptor buffer and the TKIP space. */
3534 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3535 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003536
3537 /* unit us */
3538 /* FIXME: find a proper value */
3539 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003540 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003541
3542 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003543 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003544 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003545 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003546 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003547 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003548 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003549 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003550
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003551 wl->hw->wiphy->cipher_suites = cipher_suites;
3552 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3553
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003554 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003555 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003556 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003557 /*
3558 * Maximum length of elements in scanning probe request templates
3559 * should be the maximum length possible for a template, without
3560 * the IEEE80211 header of the template
3561 */
3562 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3563 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003564
Luciano Coelho4a31c112011-03-21 23:16:14 +02003565 /* make sure all our channels fit in the scanned_ch bitmask */
3566 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3567 ARRAY_SIZE(wl1271_channels_5ghz) >
3568 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003569 /*
3570 * We keep local copies of the band structs because we need to
3571 * modify them on a per-device basis.
3572 */
3573 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3574 sizeof(wl1271_band_2ghz));
3575 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3576 sizeof(wl1271_band_5ghz));
3577
3578 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3579 &wl->bands[IEEE80211_BAND_2GHZ];
3580 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3581 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003582
Kalle Valo12bd8942010-03-18 12:26:33 +02003583 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003584 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003585
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003586 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3587
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003588 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003589
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003590 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3591
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003592 wl->hw->max_rx_aggregation_subframes = 8;
3593
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003594 return 0;
3595}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003596EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003598#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003599
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003600struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003601{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003602 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003603 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003604 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003605 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003606 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003607
3608 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3609 if (!hw) {
3610 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003611 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003612 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003613 }
3614
Julia Lawall929ebd32010-05-15 23:16:39 +02003615 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003616 if (!plat_dev) {
3617 wl1271_error("could not allocate platform_device");
3618 ret = -ENOMEM;
3619 goto err_plat_alloc;
3620 }
3621
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003622 wl = hw->priv;
3623 memset(wl, 0, sizeof(*wl));
3624
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003625 INIT_LIST_HEAD(&wl->list);
3626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003627 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003628 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003629
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003630 for (i = 0; i < NUM_TX_QUEUES; i++)
3631 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003632
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003633 for (i = 0; i < NUM_TX_QUEUES; i++)
3634 for (j = 0; j < AP_MAX_LINKS; j++)
3635 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3636
Ido Yariva6208652011-03-01 15:14:41 +02003637 skb_queue_head_init(&wl->deferred_rx_queue);
3638 skb_queue_head_init(&wl->deferred_tx_queue);
3639
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003640 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003641 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003642 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003643 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3644 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3645 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003646 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003647 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003648 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003649 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003650 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3651 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003652 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003654 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003655 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003656 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003657 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003658 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003659 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003660 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003661 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003662 wl->bss_type = MAX_BSS_TYPE;
3663 wl->set_bss_type = MAX_BSS_TYPE;
3664 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003665 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003666 wl->ap_ps_map = 0;
3667 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003668 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003669 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003670
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003671 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003672 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003673 wl->tx_frames[i] = NULL;
3674
3675 spin_lock_init(&wl->wl_lock);
3676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003677 wl->state = WL1271_STATE_OFF;
3678 mutex_init(&wl->mutex);
3679
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003680 /* Apply default driver configuration. */
3681 wl1271_conf_init(wl);
3682
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003683 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3684 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3685 if (!wl->aggr_buf) {
3686 ret = -ENOMEM;
3687 goto err_hw;
3688 }
3689
Ido Yariv990f5de2011-03-31 10:06:59 +02003690 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3691 if (!wl->dummy_packet) {
3692 ret = -ENOMEM;
3693 goto err_aggr;
3694 }
3695
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003696 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003697 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003698 if (ret) {
3699 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003700 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003701 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003702 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003703
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003704 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003705 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003706 if (ret < 0) {
3707 wl1271_error("failed to create sysfs file bt_coex_state");
3708 goto err_platform;
3709 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003710
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003711 /* Create sysfs file to get HW PG version */
3712 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3713 if (ret < 0) {
3714 wl1271_error("failed to create sysfs file hw_pg_ver");
3715 goto err_bt_coex_state;
3716 }
3717
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003718 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003719
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003720err_bt_coex_state:
3721 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3722
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003723err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003724 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003725
Ido Yariv990f5de2011-03-31 10:06:59 +02003726err_dummy_packet:
3727 dev_kfree_skb(wl->dummy_packet);
3728
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003729err_aggr:
3730 free_pages((unsigned long)wl->aggr_buf, order);
3731
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003732err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003733 wl1271_debugfs_exit(wl);
3734 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003735
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003736err_plat_alloc:
3737 ieee80211_free_hw(hw);
3738
3739err_hw_alloc:
3740
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003741 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003742}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003743EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003744
3745int wl1271_free_hw(struct wl1271 *wl)
3746{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003747 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003748 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003749 free_pages((unsigned long)wl->aggr_buf,
3750 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003751 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003752
3753 wl1271_debugfs_exit(wl);
3754
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003755 vfree(wl->fw);
3756 wl->fw = NULL;
3757 kfree(wl->nvs);
3758 wl->nvs = NULL;
3759
3760 kfree(wl->fw_status);
3761 kfree(wl->tx_res_if);
3762
3763 ieee80211_free_hw(wl->hw);
3764
3765 return 0;
3766}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003767EXPORT_SYMBOL_GPL(wl1271_free_hw);
3768
Guy Eilam491bbd62011-01-12 10:33:29 +01003769u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003770EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003771module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003772MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3773
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003774MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003775MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003776MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");