blob: 1dd735cc38b1c427ccc863943dc26a42d210231c [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 Oikarinen65cddbf2010-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 Oikarinen65cddbf2010-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 */
Eliad Peller30df14d2011-04-05 19:13:28 +03002701 bool was_assoc =
2702 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2703 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002704 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002705 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002706
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002707 /* free probe-request template */
2708 dev_kfree_skb(wl->probereq);
2709 wl->probereq = NULL;
2710
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002711 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002712 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002713
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002714 /* revert back to minimum rates for the current band */
2715 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002716 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002717 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002718 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002719 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002720
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002721 /* disable connection monitor features */
2722 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002723
2724 /* Disable the keep-alive feature */
2725 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002726 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002727 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002728
2729 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002730 if (was_assoc) {
2731 wl1271_unjoin(wl);
2732 wl1271_dummy_join(wl);
2733 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 }
2735 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002736
Arik Nemtsove78a2872010-10-16 19:07:21 +02002737 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2738 if (ret < 0)
2739 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002741 if (changed & BSS_CHANGED_ARP_FILTER) {
2742 __be32 addr = bss_conf->arp_addr_list[0];
2743 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2744
Eliad Pellerc5312772010-12-09 11:31:27 +02002745 if (bss_conf->arp_addr_cnt == 1 &&
2746 bss_conf->arp_filter_enabled) {
2747 /*
2748 * The template should have been configured only upon
2749 * association. however, it seems that the correct ip
2750 * isn't being set (when sending), so we have to
2751 * reconfigure the template upon every ip change.
2752 */
2753 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2754 if (ret < 0) {
2755 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002756 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002757 }
2758
2759 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002760 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002761 addr);
2762 } else
2763 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002764
2765 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002766 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002767 }
2768
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002769 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002770 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002771 if (ret < 0) {
2772 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002773 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002774 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002775 }
2776
Arik Nemtsove78a2872010-10-16 19:07:21 +02002777out:
2778 return;
2779}
2780
2781static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2782 struct ieee80211_vif *vif,
2783 struct ieee80211_bss_conf *bss_conf,
2784 u32 changed)
2785{
2786 struct wl1271 *wl = hw->priv;
2787 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2788 int ret;
2789
2790 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2791 (int)changed);
2792
2793 mutex_lock(&wl->mutex);
2794
2795 if (unlikely(wl->state == WL1271_STATE_OFF))
2796 goto out;
2797
Ido Yariva6208652011-03-01 15:14:41 +02002798 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002799 if (ret < 0)
2800 goto out;
2801
2802 if (is_ap)
2803 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2804 else
2805 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 wl1271_ps_elp_sleep(wl);
2808
2809out:
2810 mutex_unlock(&wl->mutex);
2811}
2812
Kalle Valoc6999d82010-02-18 13:25:41 +02002813static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2814 const struct ieee80211_tx_queue_params *params)
2815{
2816 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002817 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002818 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002819
2820 mutex_lock(&wl->mutex);
2821
2822 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2823
Kalle Valo4695dc92010-03-18 12:26:38 +02002824 if (params->uapsd)
2825 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2826 else
2827 ps_scheme = CONF_PS_SCHEME_LEGACY;
2828
Arik Nemtsov488fc542010-10-16 20:33:45 +02002829 if (wl->state == WL1271_STATE_OFF) {
2830 /*
2831 * If the state is off, the parameters will be recorded and
2832 * configured on init. This happens in AP-mode.
2833 */
2834 struct conf_tx_ac_category *conf_ac =
2835 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2836 struct conf_tx_tid *conf_tid =
2837 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2838
2839 conf_ac->ac = wl1271_tx_get_queue(queue);
2840 conf_ac->cw_min = (u8)params->cw_min;
2841 conf_ac->cw_max = params->cw_max;
2842 conf_ac->aifsn = params->aifs;
2843 conf_ac->tx_op_limit = params->txop << 5;
2844
2845 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2846 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2847 conf_tid->tsid = wl1271_tx_get_queue(queue);
2848 conf_tid->ps_scheme = ps_scheme;
2849 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2850 conf_tid->apsd_conf[0] = 0;
2851 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002852 goto out;
2853 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002854
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002855 ret = wl1271_ps_elp_wakeup(wl);
2856 if (ret < 0)
2857 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002858
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002859 /*
2860 * the txop is confed in units of 32us by the mac80211,
2861 * we need us
2862 */
2863 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2864 params->cw_min, params->cw_max,
2865 params->aifs, params->txop << 5);
2866 if (ret < 0)
2867 goto out_sleep;
2868
2869 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2870 CONF_CHANNEL_TYPE_EDCF,
2871 wl1271_tx_get_queue(queue),
2872 ps_scheme, CONF_ACK_POLICY_LEGACY,
2873 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002874
2875out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002876 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002877
2878out:
2879 mutex_unlock(&wl->mutex);
2880
2881 return ret;
2882}
2883
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002884static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2885{
2886
2887 struct wl1271 *wl = hw->priv;
2888 u64 mactime = ULLONG_MAX;
2889 int ret;
2890
2891 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2892
2893 mutex_lock(&wl->mutex);
2894
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002895 if (unlikely(wl->state == WL1271_STATE_OFF))
2896 goto out;
2897
Ido Yariva6208652011-03-01 15:14:41 +02002898 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002899 if (ret < 0)
2900 goto out;
2901
2902 ret = wl1271_acx_tsf_info(wl, &mactime);
2903 if (ret < 0)
2904 goto out_sleep;
2905
2906out_sleep:
2907 wl1271_ps_elp_sleep(wl);
2908
2909out:
2910 mutex_unlock(&wl->mutex);
2911 return mactime;
2912}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913
John W. Linvilleece550d2010-07-28 16:41:06 -04002914static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2915 struct survey_info *survey)
2916{
2917 struct wl1271 *wl = hw->priv;
2918 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002919
John W. Linvilleece550d2010-07-28 16:41:06 -04002920 if (idx != 0)
2921 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002922
John W. Linvilleece550d2010-07-28 16:41:06 -04002923 survey->channel = conf->channel;
2924 survey->filled = SURVEY_INFO_NOISE_DBM;
2925 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002926
John W. Linvilleece550d2010-07-28 16:41:06 -04002927 return 0;
2928}
2929
Arik Nemtsov409622e2011-02-23 00:22:29 +02002930static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002931 struct ieee80211_sta *sta,
2932 u8 *hlid)
2933{
2934 struct wl1271_station *wl_sta;
2935 int id;
2936
2937 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2938 if (id >= AP_MAX_STATIONS) {
2939 wl1271_warning("could not allocate HLID - too much stations");
2940 return -EBUSY;
2941 }
2942
2943 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002944 __set_bit(id, wl->ap_hlid_map);
2945 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2946 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002947 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002948 return 0;
2949}
2950
Arik Nemtsov409622e2011-02-23 00:22:29 +02002951static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002952{
2953 int id = hlid - WL1271_AP_STA_HLID_START;
2954
Arik Nemtsov409622e2011-02-23 00:22:29 +02002955 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2956 return;
2957
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002958 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002959 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002960 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002961 __clear_bit(hlid, &wl->ap_ps_map);
2962 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002963}
2964
Arik Nemtsov47684802011-04-26 23:21:51 +03002965bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
2966{
2967 int id = hlid - WL1271_AP_STA_HLID_START;
2968 return test_bit(id, wl->ap_hlid_map);
2969}
2970
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002971static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2972 struct ieee80211_vif *vif,
2973 struct ieee80211_sta *sta)
2974{
2975 struct wl1271 *wl = hw->priv;
2976 int ret = 0;
2977 u8 hlid;
2978
2979 mutex_lock(&wl->mutex);
2980
2981 if (unlikely(wl->state == WL1271_STATE_OFF))
2982 goto out;
2983
2984 if (wl->bss_type != BSS_TYPE_AP_BSS)
2985 goto out;
2986
2987 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2988
Arik Nemtsov409622e2011-02-23 00:22:29 +02002989 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002990 if (ret < 0)
2991 goto out;
2992
Ido Yariva6208652011-03-01 15:14:41 +02002993 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002994 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002995 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002996
2997 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2998 if (ret < 0)
2999 goto out_sleep;
3000
3001out_sleep:
3002 wl1271_ps_elp_sleep(wl);
3003
Arik Nemtsov409622e2011-02-23 00:22:29 +02003004out_free_sta:
3005 if (ret < 0)
3006 wl1271_free_sta(wl, hlid);
3007
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003008out:
3009 mutex_unlock(&wl->mutex);
3010 return ret;
3011}
3012
3013static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3014 struct ieee80211_vif *vif,
3015 struct ieee80211_sta *sta)
3016{
3017 struct wl1271 *wl = hw->priv;
3018 struct wl1271_station *wl_sta;
3019 int ret = 0, id;
3020
3021 mutex_lock(&wl->mutex);
3022
3023 if (unlikely(wl->state == WL1271_STATE_OFF))
3024 goto out;
3025
3026 if (wl->bss_type != BSS_TYPE_AP_BSS)
3027 goto out;
3028
3029 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3030
3031 wl_sta = (struct wl1271_station *)sta->drv_priv;
3032 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3033 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3034 goto out;
3035
Ido Yariva6208652011-03-01 15:14:41 +02003036 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003037 if (ret < 0)
3038 goto out;
3039
3040 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3041 if (ret < 0)
3042 goto out_sleep;
3043
Arik Nemtsov409622e2011-02-23 00:22:29 +02003044 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003045
3046out_sleep:
3047 wl1271_ps_elp_sleep(wl);
3048
3049out:
3050 mutex_unlock(&wl->mutex);
3051 return ret;
3052}
3053
Luciano Coelho4623ec72011-03-21 19:26:41 +02003054static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3055 struct ieee80211_vif *vif,
3056 enum ieee80211_ampdu_mlme_action action,
3057 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3058 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003059{
3060 struct wl1271 *wl = hw->priv;
3061 int ret;
3062
3063 mutex_lock(&wl->mutex);
3064
3065 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3066 ret = -EAGAIN;
3067 goto out;
3068 }
3069
Ido Yariva6208652011-03-01 15:14:41 +02003070 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003071 if (ret < 0)
3072 goto out;
3073
3074 switch (action) {
3075 case IEEE80211_AMPDU_RX_START:
3076 if (wl->ba_support) {
3077 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3078 true);
3079 if (!ret)
3080 wl->ba_rx_bitmap |= BIT(tid);
3081 } else {
3082 ret = -ENOTSUPP;
3083 }
3084 break;
3085
3086 case IEEE80211_AMPDU_RX_STOP:
3087 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3088 if (!ret)
3089 wl->ba_rx_bitmap &= ~BIT(tid);
3090 break;
3091
3092 /*
3093 * The BA initiator session management in FW independently.
3094 * Falling break here on purpose for all TX APDU commands.
3095 */
3096 case IEEE80211_AMPDU_TX_START:
3097 case IEEE80211_AMPDU_TX_STOP:
3098 case IEEE80211_AMPDU_TX_OPERATIONAL:
3099 ret = -EINVAL;
3100 break;
3101
3102 default:
3103 wl1271_error("Incorrect ampdu action id=%x\n", action);
3104 ret = -EINVAL;
3105 }
3106
3107 wl1271_ps_elp_sleep(wl);
3108
3109out:
3110 mutex_unlock(&wl->mutex);
3111
3112 return ret;
3113}
3114
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003115/* can't be const, mac80211 writes to this */
3116static struct ieee80211_rate wl1271_rates[] = {
3117 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003118 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3119 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003120 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003121 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3122 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3124 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003125 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3126 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003127 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3128 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003129 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3130 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3132 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003133 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3134 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003135 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003136 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3137 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003138 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003139 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003141 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003142 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3143 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003144 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003145 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3146 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003147 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003148 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3149 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003150 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003151 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3152 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003153 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003154 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3155 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156};
3157
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003158/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003160 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003161 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003162 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3163 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3164 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003165 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003166 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3167 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3168 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003169 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003170 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3171 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3172 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003173 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003174};
3175
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003176/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003177static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003178 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003179 7, /* CONF_HW_RXTX_RATE_MCS7 */
3180 6, /* CONF_HW_RXTX_RATE_MCS6 */
3181 5, /* CONF_HW_RXTX_RATE_MCS5 */
3182 4, /* CONF_HW_RXTX_RATE_MCS4 */
3183 3, /* CONF_HW_RXTX_RATE_MCS3 */
3184 2, /* CONF_HW_RXTX_RATE_MCS2 */
3185 1, /* CONF_HW_RXTX_RATE_MCS1 */
3186 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003187
3188 11, /* CONF_HW_RXTX_RATE_54 */
3189 10, /* CONF_HW_RXTX_RATE_48 */
3190 9, /* CONF_HW_RXTX_RATE_36 */
3191 8, /* CONF_HW_RXTX_RATE_24 */
3192
3193 /* TI-specific rate */
3194 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3195
3196 7, /* CONF_HW_RXTX_RATE_18 */
3197 6, /* CONF_HW_RXTX_RATE_12 */
3198 3, /* CONF_HW_RXTX_RATE_11 */
3199 5, /* CONF_HW_RXTX_RATE_9 */
3200 4, /* CONF_HW_RXTX_RATE_6 */
3201 2, /* CONF_HW_RXTX_RATE_5_5 */
3202 1, /* CONF_HW_RXTX_RATE_2 */
3203 0 /* CONF_HW_RXTX_RATE_1 */
3204};
3205
Shahar Levie8b03a22010-10-13 16:09:39 +02003206/* 11n STA capabilities */
3207#define HW_RX_HIGHEST_RATE 72
3208
Shahar Levi00d20102010-11-08 11:20:10 +00003209#ifdef CONFIG_WL12XX_HT
3210#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003211 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3212 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003213 .ht_supported = true, \
3214 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3215 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3216 .mcs = { \
3217 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3218 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3219 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3220 }, \
3221}
Shahar Levi18357852010-10-13 16:09:41 +02003222#else
Shahar Levi00d20102010-11-08 11:20:10 +00003223#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003224 .ht_supported = false, \
3225}
3226#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003227
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228/* can't be const, mac80211 writes to this */
3229static struct ieee80211_supported_band wl1271_band_2ghz = {
3230 .channels = wl1271_channels,
3231 .n_channels = ARRAY_SIZE(wl1271_channels),
3232 .bitrates = wl1271_rates,
3233 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003234 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235};
3236
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003237/* 5 GHz data rates for WL1273 */
3238static struct ieee80211_rate wl1271_rates_5ghz[] = {
3239 { .bitrate = 60,
3240 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3241 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3242 { .bitrate = 90,
3243 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3244 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3245 { .bitrate = 120,
3246 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3247 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3248 { .bitrate = 180,
3249 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3250 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3251 { .bitrate = 240,
3252 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3253 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3254 { .bitrate = 360,
3255 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3256 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3257 { .bitrate = 480,
3258 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3259 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3260 { .bitrate = 540,
3261 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3262 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3263};
3264
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003265/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003266static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003267 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003268 { .hw_value = 8, .center_freq = 5040},
3269 { .hw_value = 9, .center_freq = 5045},
3270 { .hw_value = 11, .center_freq = 5055},
3271 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003272 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003273 { .hw_value = 34, .center_freq = 5170},
3274 { .hw_value = 36, .center_freq = 5180},
3275 { .hw_value = 38, .center_freq = 5190},
3276 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003277 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003278 { .hw_value = 44, .center_freq = 5220},
3279 { .hw_value = 46, .center_freq = 5230},
3280 { .hw_value = 48, .center_freq = 5240},
3281 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003282 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003283 { .hw_value = 60, .center_freq = 5300},
3284 { .hw_value = 64, .center_freq = 5320},
3285 { .hw_value = 100, .center_freq = 5500},
3286 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003287 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003288 { .hw_value = 112, .center_freq = 5560},
3289 { .hw_value = 116, .center_freq = 5580},
3290 { .hw_value = 120, .center_freq = 5600},
3291 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003292 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003293 { .hw_value = 132, .center_freq = 5660},
3294 { .hw_value = 136, .center_freq = 5680},
3295 { .hw_value = 140, .center_freq = 5700},
3296 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003297 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003298 { .hw_value = 157, .center_freq = 5785},
3299 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003300 { .hw_value = 165, .center_freq = 5825},
3301};
3302
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003303/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003304static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003305 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003306 7, /* CONF_HW_RXTX_RATE_MCS7 */
3307 6, /* CONF_HW_RXTX_RATE_MCS6 */
3308 5, /* CONF_HW_RXTX_RATE_MCS5 */
3309 4, /* CONF_HW_RXTX_RATE_MCS4 */
3310 3, /* CONF_HW_RXTX_RATE_MCS3 */
3311 2, /* CONF_HW_RXTX_RATE_MCS2 */
3312 1, /* CONF_HW_RXTX_RATE_MCS1 */
3313 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003314
3315 7, /* CONF_HW_RXTX_RATE_54 */
3316 6, /* CONF_HW_RXTX_RATE_48 */
3317 5, /* CONF_HW_RXTX_RATE_36 */
3318 4, /* CONF_HW_RXTX_RATE_24 */
3319
3320 /* TI-specific rate */
3321 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3322
3323 3, /* CONF_HW_RXTX_RATE_18 */
3324 2, /* CONF_HW_RXTX_RATE_12 */
3325 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3326 1, /* CONF_HW_RXTX_RATE_9 */
3327 0, /* CONF_HW_RXTX_RATE_6 */
3328 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3329 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3330 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3331};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003332
3333static struct ieee80211_supported_band wl1271_band_5ghz = {
3334 .channels = wl1271_channels_5ghz,
3335 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3336 .bitrates = wl1271_rates_5ghz,
3337 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003338 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003339};
3340
Tobias Klausera0ea9492010-05-20 10:38:11 +02003341static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003342 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3343 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3344};
3345
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346static const struct ieee80211_ops wl1271_ops = {
3347 .start = wl1271_op_start,
3348 .stop = wl1271_op_stop,
3349 .add_interface = wl1271_op_add_interface,
3350 .remove_interface = wl1271_op_remove_interface,
3351 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003352 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003353 .configure_filter = wl1271_op_configure_filter,
3354 .tx = wl1271_op_tx,
3355 .set_key = wl1271_op_set_key,
3356 .hw_scan = wl1271_op_hw_scan,
3357 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003358 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003360 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003361 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003362 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003363 .sta_add = wl1271_op_sta_add,
3364 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003365 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003366 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003367};
3368
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003369
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003370u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003371{
3372 u8 idx;
3373
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003374 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003375
3376 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3377 wl1271_error("Illegal RX rate from HW: %d", rate);
3378 return 0;
3379 }
3380
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003381 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003382 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3383 wl1271_error("Unsupported RX rate from HW: %d", rate);
3384 return 0;
3385 }
3386
3387 return idx;
3388}
3389
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003390static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3391 struct device_attribute *attr,
3392 char *buf)
3393{
3394 struct wl1271 *wl = dev_get_drvdata(dev);
3395 ssize_t len;
3396
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003397 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003398
3399 mutex_lock(&wl->mutex);
3400 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3401 wl->sg_enabled);
3402 mutex_unlock(&wl->mutex);
3403
3404 return len;
3405
3406}
3407
3408static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3409 struct device_attribute *attr,
3410 const char *buf, size_t count)
3411{
3412 struct wl1271 *wl = dev_get_drvdata(dev);
3413 unsigned long res;
3414 int ret;
3415
Luciano Coelho6277ed62011-04-01 17:49:54 +03003416 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003417 if (ret < 0) {
3418 wl1271_warning("incorrect value written to bt_coex_mode");
3419 return count;
3420 }
3421
3422 mutex_lock(&wl->mutex);
3423
3424 res = !!res;
3425
3426 if (res == wl->sg_enabled)
3427 goto out;
3428
3429 wl->sg_enabled = res;
3430
3431 if (wl->state == WL1271_STATE_OFF)
3432 goto out;
3433
Ido Yariva6208652011-03-01 15:14:41 +02003434 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003435 if (ret < 0)
3436 goto out;
3437
3438 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3439 wl1271_ps_elp_sleep(wl);
3440
3441 out:
3442 mutex_unlock(&wl->mutex);
3443 return count;
3444}
3445
3446static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3447 wl1271_sysfs_show_bt_coex_state,
3448 wl1271_sysfs_store_bt_coex_state);
3449
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003450static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3451 struct device_attribute *attr,
3452 char *buf)
3453{
3454 struct wl1271 *wl = dev_get_drvdata(dev);
3455 ssize_t len;
3456
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003457 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003458
3459 mutex_lock(&wl->mutex);
3460 if (wl->hw_pg_ver >= 0)
3461 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3462 else
3463 len = snprintf(buf, len, "n/a\n");
3464 mutex_unlock(&wl->mutex);
3465
3466 return len;
3467}
3468
3469static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3470 wl1271_sysfs_show_hw_pg_ver, NULL);
3471
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003472int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003473{
3474 int ret;
3475
3476 if (wl->mac80211_registered)
3477 return 0;
3478
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003479 ret = wl1271_fetch_nvs(wl);
3480 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003481 /* NOTE: The wl->nvs->nvs element must be first, in
3482 * order to simplify the casting, we assume it is at
3483 * the beginning of the wl->nvs structure.
3484 */
3485 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003486
3487 wl->mac_addr[0] = nvs_ptr[11];
3488 wl->mac_addr[1] = nvs_ptr[10];
3489 wl->mac_addr[2] = nvs_ptr[6];
3490 wl->mac_addr[3] = nvs_ptr[5];
3491 wl->mac_addr[4] = nvs_ptr[4];
3492 wl->mac_addr[5] = nvs_ptr[3];
3493 }
3494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3496
3497 ret = ieee80211_register_hw(wl->hw);
3498 if (ret < 0) {
3499 wl1271_error("unable to register mac80211 hw: %d", ret);
3500 return ret;
3501 }
3502
3503 wl->mac80211_registered = true;
3504
Eliad Pellerd60080a2010-11-24 12:53:16 +02003505 wl1271_debugfs_init(wl);
3506
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003507 register_netdevice_notifier(&wl1271_dev_notifier);
3508
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003509 wl1271_notice("loaded");
3510
3511 return 0;
3512}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003513EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003515void wl1271_unregister_hw(struct wl1271 *wl)
3516{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003517 if (wl->state == WL1271_STATE_PLT)
3518 __wl1271_plt_stop(wl);
3519
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003520 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003521 ieee80211_unregister_hw(wl->hw);
3522 wl->mac80211_registered = false;
3523
3524}
3525EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3526
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003527int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003529 static const u32 cipher_suites[] = {
3530 WLAN_CIPHER_SUITE_WEP40,
3531 WLAN_CIPHER_SUITE_WEP104,
3532 WLAN_CIPHER_SUITE_TKIP,
3533 WLAN_CIPHER_SUITE_CCMP,
3534 WL1271_CIPHER_SUITE_GEM,
3535 };
3536
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003537 /* The tx descriptor buffer and the TKIP space. */
3538 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3539 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540
3541 /* unit us */
3542 /* FIXME: find a proper value */
3543 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003544 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003545
3546 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003547 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003548 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003549 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003550 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003551 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003552 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003553 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003554
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003555 wl->hw->wiphy->cipher_suites = cipher_suites;
3556 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3557
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003558 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003559 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003560 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003561 /*
3562 * Maximum length of elements in scanning probe request templates
3563 * should be the maximum length possible for a template, without
3564 * the IEEE80211 header of the template
3565 */
3566 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3567 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003568
Luciano Coelho4a31c112011-03-21 23:16:14 +02003569 /* make sure all our channels fit in the scanned_ch bitmask */
3570 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3571 ARRAY_SIZE(wl1271_channels_5ghz) >
3572 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003573 /*
3574 * We keep local copies of the band structs because we need to
3575 * modify them on a per-device basis.
3576 */
3577 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3578 sizeof(wl1271_band_2ghz));
3579 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3580 sizeof(wl1271_band_5ghz));
3581
3582 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3583 &wl->bands[IEEE80211_BAND_2GHZ];
3584 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3585 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003586
Kalle Valo12bd8942010-03-18 12:26:33 +02003587 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003588 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003589
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003590 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3591
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003592 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003593
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003594 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3595
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003596 wl->hw->max_rx_aggregation_subframes = 8;
3597
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003598 return 0;
3599}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003600EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003602#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003603
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003604struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003605{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003606 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003607 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003608 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003609 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003610 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003611
3612 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3613 if (!hw) {
3614 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003615 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003616 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003617 }
3618
Julia Lawall929ebd32010-05-15 23:16:39 +02003619 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003620 if (!plat_dev) {
3621 wl1271_error("could not allocate platform_device");
3622 ret = -ENOMEM;
3623 goto err_plat_alloc;
3624 }
3625
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003626 wl = hw->priv;
3627 memset(wl, 0, sizeof(*wl));
3628
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003629 INIT_LIST_HEAD(&wl->list);
3630
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003631 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003632 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003633
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003634 for (i = 0; i < NUM_TX_QUEUES; i++)
3635 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003636
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003637 for (i = 0; i < NUM_TX_QUEUES; i++)
3638 for (j = 0; j < AP_MAX_LINKS; j++)
3639 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3640
Ido Yariva6208652011-03-01 15:14:41 +02003641 skb_queue_head_init(&wl->deferred_rx_queue);
3642 skb_queue_head_init(&wl->deferred_tx_queue);
3643
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003644 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003645 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003646 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003647 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3648 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3649 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003650 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003651 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003652 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003654 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3655 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003656 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003657 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003658 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003659 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003660 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003661 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003662 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003663 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003664 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003665 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003666 wl->bss_type = MAX_BSS_TYPE;
3667 wl->set_bss_type = MAX_BSS_TYPE;
3668 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003669 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003670 wl->ap_ps_map = 0;
3671 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003672 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003673 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003674
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003675 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003676 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003677 wl->tx_frames[i] = NULL;
3678
3679 spin_lock_init(&wl->wl_lock);
3680
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003681 wl->state = WL1271_STATE_OFF;
3682 mutex_init(&wl->mutex);
3683
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003684 /* Apply default driver configuration. */
3685 wl1271_conf_init(wl);
3686
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003687 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3688 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3689 if (!wl->aggr_buf) {
3690 ret = -ENOMEM;
3691 goto err_hw;
3692 }
3693
Ido Yariv990f5de2011-03-31 10:06:59 +02003694 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3695 if (!wl->dummy_packet) {
3696 ret = -ENOMEM;
3697 goto err_aggr;
3698 }
3699
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003700 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003701 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003702 if (ret) {
3703 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003704 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003705 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003706 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003707
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003708 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003709 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003710 if (ret < 0) {
3711 wl1271_error("failed to create sysfs file bt_coex_state");
3712 goto err_platform;
3713 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003714
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003715 /* Create sysfs file to get HW PG version */
3716 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3717 if (ret < 0) {
3718 wl1271_error("failed to create sysfs file hw_pg_ver");
3719 goto err_bt_coex_state;
3720 }
3721
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003722 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003723
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003724err_bt_coex_state:
3725 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3726
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003727err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003728 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003729
Ido Yariv990f5de2011-03-31 10:06:59 +02003730err_dummy_packet:
3731 dev_kfree_skb(wl->dummy_packet);
3732
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003733err_aggr:
3734 free_pages((unsigned long)wl->aggr_buf, order);
3735
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003736err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003737 wl1271_debugfs_exit(wl);
3738 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003739
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003740err_plat_alloc:
3741 ieee80211_free_hw(hw);
3742
3743err_hw_alloc:
3744
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003745 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003746}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003747EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003748
3749int wl1271_free_hw(struct wl1271 *wl)
3750{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003751 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003752 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003753 free_pages((unsigned long)wl->aggr_buf,
3754 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003755 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003756
3757 wl1271_debugfs_exit(wl);
3758
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003759 vfree(wl->fw);
3760 wl->fw = NULL;
3761 kfree(wl->nvs);
3762 wl->nvs = NULL;
3763
3764 kfree(wl->fw_status);
3765 kfree(wl->tx_res_if);
3766
3767 ieee80211_free_hw(wl->hw);
3768
3769 return 0;
3770}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003771EXPORT_SYMBOL_GPL(wl1271_free_hw);
3772
Guy Eilam491bbd62011-01-12 10:33:29 +01003773u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003774EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003775module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003776MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3777
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003778MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003779MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003780MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");