blob: 53a8e2357ccf0a0029386ff9ecb5c194cafa00db [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
Eliad Pellercb5ae052011-04-07 15:52:05 +03002512 if (changed & BSS_CHANGED_IBSS) {
2513 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2514 bss_conf->ibss_joined);
2515
2516 if (bss_conf->ibss_joined) {
2517 u32 rates = bss_conf->basic_rates;
2518 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2519 rates);
2520 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2521
2522 /* by default, use 11b rates */
2523 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2524 ret = wl1271_acx_sta_rate_policies(wl);
2525 if (ret < 0)
2526 goto out;
2527 }
2528 }
2529
Arik Nemtsove78a2872010-10-16 19:07:21 +02002530 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2531 if (ret < 0)
2532 goto out;
2533out:
2534 return;
2535}
2536
2537/* STA/IBSS mode changes */
2538static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2539 struct ieee80211_vif *vif,
2540 struct ieee80211_bss_conf *bss_conf,
2541 u32 changed)
2542{
2543 bool do_join = false, set_assoc = false;
2544 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002545 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002546 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002547 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002548 bool sta_exists = false;
2549 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002550
2551 if (is_ibss) {
2552 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2553 changed);
2554 if (ret < 0)
2555 goto out;
2556 }
2557
2558 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2559 do_join = true;
2560
2561 /* Need to update the SSID (for filtering etc) */
2562 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2563 do_join = true;
2564
2565 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002566 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2567 bss_conf->enable_beacon ? "enabled" : "disabled");
2568
2569 if (bss_conf->enable_beacon)
2570 wl->set_bss_type = BSS_TYPE_IBSS;
2571 else
2572 wl->set_bss_type = BSS_TYPE_STA_BSS;
2573 do_join = true;
2574 }
2575
Arik Nemtsove78a2872010-10-16 19:07:21 +02002576 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002577 bool enable = false;
2578 if (bss_conf->cqm_rssi_thold)
2579 enable = true;
2580 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2581 bss_conf->cqm_rssi_thold,
2582 bss_conf->cqm_rssi_hyst);
2583 if (ret < 0)
2584 goto out;
2585 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2586 }
2587
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002588 if ((changed & BSS_CHANGED_BSSID) &&
2589 /*
2590 * Now we know the correct bssid, so we send a new join command
2591 * and enable the BSSID filter
2592 */
2593 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002594 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002595
Eliad Pellerfa287b82010-12-26 09:27:50 +01002596 if (!is_zero_ether_addr(wl->bssid)) {
2597 ret = wl1271_cmd_build_null_data(wl);
2598 if (ret < 0)
2599 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002600
Eliad Pellerfa287b82010-12-26 09:27:50 +01002601 ret = wl1271_build_qos_null_data(wl);
2602 if (ret < 0)
2603 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002604
Eliad Pellerfa287b82010-12-26 09:27:50 +01002605 /* filter out all packets not from this BSSID */
2606 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002607
Eliad Pellerfa287b82010-12-26 09:27:50 +01002608 /* Need to update the BSSID (for filtering etc) */
2609 do_join = true;
2610 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002611 }
2612
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002613 rcu_read_lock();
2614 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2615 if (sta) {
2616 /* save the supp_rates of the ap */
2617 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2618 if (sta->ht_cap.ht_supported)
2619 sta_rate_set |=
2620 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002621 sta_ht_cap = sta->ht_cap;
2622 sta_exists = true;
2623 }
2624 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002625
Arik Nemtsova1008852011-02-12 23:24:20 +02002626 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002627 /* handle new association with HT and HT information change */
2628 if ((changed & BSS_CHANGED_HT) &&
2629 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002630 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002631 true);
2632 if (ret < 0) {
2633 wl1271_warning("Set ht cap true failed %d",
2634 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002635 goto out;
2636 }
2637 ret = wl1271_acx_set_ht_information(wl,
2638 bss_conf->ht_operation_mode);
2639 if (ret < 0) {
2640 wl1271_warning("Set ht information failed %d",
2641 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002642 goto out;
2643 }
2644 }
2645 /* handle new association without HT and disassociation */
2646 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002647 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002648 false);
2649 if (ret < 0) {
2650 wl1271_warning("Set ht cap false failed %d",
2651 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002652 goto out;
2653 }
2654 }
2655 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002656
Arik Nemtsove78a2872010-10-16 19:07:21 +02002657 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002659 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002660 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002661 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002662 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002664 wl->ps_poll_failures = 0;
2665
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002666 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002667 * use basic rates from AP, and determine lowest rate
2668 * to use with control frames.
2669 */
2670 rates = bss_conf->basic_rates;
2671 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2672 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002673 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002674 if (sta_rate_set)
2675 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2676 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002677 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002678 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002679 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002680
2681 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002682 * with wl1271, we don't need to update the
2683 * beacon_int and dtim_period, because the firmware
2684 * updates it by itself when the first beacon is
2685 * received after a join.
2686 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2688 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002689 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002691 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002692 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002693 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002694 dev_kfree_skb(wl->probereq);
2695 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2696 ieoffset = offsetof(struct ieee80211_mgmt,
2697 u.probe_req.variable);
2698 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002699
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002700 /* enable the connection monitoring feature */
2701 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704
2705 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002706 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2707 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002708 enum wl1271_cmd_ps_mode mode;
2709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002710 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002711 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002712 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002713 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002714 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002715 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002717 } else {
2718 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002719 bool was_assoc =
2720 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2721 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002722 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002723 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002724
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002725 /* free probe-request template */
2726 dev_kfree_skb(wl->probereq);
2727 wl->probereq = NULL;
2728
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002729 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002730 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002731
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002732 /* revert back to minimum rates for the current band */
2733 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002734 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002735 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002736 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002737 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002738
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002739 /* disable connection monitor features */
2740 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002741
2742 /* Disable the keep-alive feature */
2743 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002744 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002745 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002746
2747 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002748 if (was_assoc) {
2749 wl1271_unjoin(wl);
2750 wl1271_dummy_join(wl);
2751 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752 }
2753 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002754
Arik Nemtsove78a2872010-10-16 19:07:21 +02002755 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2756 if (ret < 0)
2757 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002759 if (changed & BSS_CHANGED_ARP_FILTER) {
2760 __be32 addr = bss_conf->arp_addr_list[0];
2761 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2762
Eliad Pellerc5312772010-12-09 11:31:27 +02002763 if (bss_conf->arp_addr_cnt == 1 &&
2764 bss_conf->arp_filter_enabled) {
2765 /*
2766 * The template should have been configured only upon
2767 * association. however, it seems that the correct ip
2768 * isn't being set (when sending), so we have to
2769 * reconfigure the template upon every ip change.
2770 */
2771 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2772 if (ret < 0) {
2773 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002774 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002775 }
2776
2777 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002778 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002779 addr);
2780 } else
2781 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002782
2783 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002784 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002785 }
2786
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002787 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002788 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002789 if (ret < 0) {
2790 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002791 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002792 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002793 }
2794
Arik Nemtsove78a2872010-10-16 19:07:21 +02002795out:
2796 return;
2797}
2798
2799static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2800 struct ieee80211_vif *vif,
2801 struct ieee80211_bss_conf *bss_conf,
2802 u32 changed)
2803{
2804 struct wl1271 *wl = hw->priv;
2805 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2806 int ret;
2807
2808 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2809 (int)changed);
2810
2811 mutex_lock(&wl->mutex);
2812
2813 if (unlikely(wl->state == WL1271_STATE_OFF))
2814 goto out;
2815
Ido Yariva6208652011-03-01 15:14:41 +02002816 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002817 if (ret < 0)
2818 goto out;
2819
2820 if (is_ap)
2821 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2822 else
2823 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2824
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 wl1271_ps_elp_sleep(wl);
2826
2827out:
2828 mutex_unlock(&wl->mutex);
2829}
2830
Kalle Valoc6999d82010-02-18 13:25:41 +02002831static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2832 const struct ieee80211_tx_queue_params *params)
2833{
2834 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002835 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002836 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002837
2838 mutex_lock(&wl->mutex);
2839
2840 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2841
Kalle Valo4695dc92010-03-18 12:26:38 +02002842 if (params->uapsd)
2843 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2844 else
2845 ps_scheme = CONF_PS_SCHEME_LEGACY;
2846
Arik Nemtsov488fc542010-10-16 20:33:45 +02002847 if (wl->state == WL1271_STATE_OFF) {
2848 /*
2849 * If the state is off, the parameters will be recorded and
2850 * configured on init. This happens in AP-mode.
2851 */
2852 struct conf_tx_ac_category *conf_ac =
2853 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2854 struct conf_tx_tid *conf_tid =
2855 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2856
2857 conf_ac->ac = wl1271_tx_get_queue(queue);
2858 conf_ac->cw_min = (u8)params->cw_min;
2859 conf_ac->cw_max = params->cw_max;
2860 conf_ac->aifsn = params->aifs;
2861 conf_ac->tx_op_limit = params->txop << 5;
2862
2863 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2864 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2865 conf_tid->tsid = wl1271_tx_get_queue(queue);
2866 conf_tid->ps_scheme = ps_scheme;
2867 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2868 conf_tid->apsd_conf[0] = 0;
2869 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002870 goto out;
2871 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002872
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002873 ret = wl1271_ps_elp_wakeup(wl);
2874 if (ret < 0)
2875 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002876
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002877 /*
2878 * the txop is confed in units of 32us by the mac80211,
2879 * we need us
2880 */
2881 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2882 params->cw_min, params->cw_max,
2883 params->aifs, params->txop << 5);
2884 if (ret < 0)
2885 goto out_sleep;
2886
2887 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2888 CONF_CHANNEL_TYPE_EDCF,
2889 wl1271_tx_get_queue(queue),
2890 ps_scheme, CONF_ACK_POLICY_LEGACY,
2891 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002892
2893out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002894 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002895
2896out:
2897 mutex_unlock(&wl->mutex);
2898
2899 return ret;
2900}
2901
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002902static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2903{
2904
2905 struct wl1271 *wl = hw->priv;
2906 u64 mactime = ULLONG_MAX;
2907 int ret;
2908
2909 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2910
2911 mutex_lock(&wl->mutex);
2912
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002913 if (unlikely(wl->state == WL1271_STATE_OFF))
2914 goto out;
2915
Ido Yariva6208652011-03-01 15:14:41 +02002916 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002917 if (ret < 0)
2918 goto out;
2919
2920 ret = wl1271_acx_tsf_info(wl, &mactime);
2921 if (ret < 0)
2922 goto out_sleep;
2923
2924out_sleep:
2925 wl1271_ps_elp_sleep(wl);
2926
2927out:
2928 mutex_unlock(&wl->mutex);
2929 return mactime;
2930}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931
John W. Linvilleece550d2010-07-28 16:41:06 -04002932static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2933 struct survey_info *survey)
2934{
2935 struct wl1271 *wl = hw->priv;
2936 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002937
John W. Linvilleece550d2010-07-28 16:41:06 -04002938 if (idx != 0)
2939 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002940
John W. Linvilleece550d2010-07-28 16:41:06 -04002941 survey->channel = conf->channel;
2942 survey->filled = SURVEY_INFO_NOISE_DBM;
2943 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002944
John W. Linvilleece550d2010-07-28 16:41:06 -04002945 return 0;
2946}
2947
Arik Nemtsov409622e2011-02-23 00:22:29 +02002948static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002949 struct ieee80211_sta *sta,
2950 u8 *hlid)
2951{
2952 struct wl1271_station *wl_sta;
2953 int id;
2954
2955 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2956 if (id >= AP_MAX_STATIONS) {
2957 wl1271_warning("could not allocate HLID - too much stations");
2958 return -EBUSY;
2959 }
2960
2961 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002962 __set_bit(id, wl->ap_hlid_map);
2963 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2964 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002965 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002966 return 0;
2967}
2968
Arik Nemtsov409622e2011-02-23 00:22:29 +02002969static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002970{
2971 int id = hlid - WL1271_AP_STA_HLID_START;
2972
Arik Nemtsov409622e2011-02-23 00:22:29 +02002973 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2974 return;
2975
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002976 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002977 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002978 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002979 __clear_bit(hlid, &wl->ap_ps_map);
2980 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002981}
2982
Arik Nemtsov47684802011-04-26 23:21:51 +03002983bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
2984{
2985 int id = hlid - WL1271_AP_STA_HLID_START;
2986 return test_bit(id, wl->ap_hlid_map);
2987}
2988
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002989static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2990 struct ieee80211_vif *vif,
2991 struct ieee80211_sta *sta)
2992{
2993 struct wl1271 *wl = hw->priv;
2994 int ret = 0;
2995 u8 hlid;
2996
2997 mutex_lock(&wl->mutex);
2998
2999 if (unlikely(wl->state == WL1271_STATE_OFF))
3000 goto out;
3001
3002 if (wl->bss_type != BSS_TYPE_AP_BSS)
3003 goto out;
3004
3005 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3006
Arik Nemtsov409622e2011-02-23 00:22:29 +02003007 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003008 if (ret < 0)
3009 goto out;
3010
Ido Yariva6208652011-03-01 15:14:41 +02003011 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003012 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003013 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003014
3015 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3016 if (ret < 0)
3017 goto out_sleep;
3018
3019out_sleep:
3020 wl1271_ps_elp_sleep(wl);
3021
Arik Nemtsov409622e2011-02-23 00:22:29 +02003022out_free_sta:
3023 if (ret < 0)
3024 wl1271_free_sta(wl, hlid);
3025
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003026out:
3027 mutex_unlock(&wl->mutex);
3028 return ret;
3029}
3030
3031static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3032 struct ieee80211_vif *vif,
3033 struct ieee80211_sta *sta)
3034{
3035 struct wl1271 *wl = hw->priv;
3036 struct wl1271_station *wl_sta;
3037 int ret = 0, id;
3038
3039 mutex_lock(&wl->mutex);
3040
3041 if (unlikely(wl->state == WL1271_STATE_OFF))
3042 goto out;
3043
3044 if (wl->bss_type != BSS_TYPE_AP_BSS)
3045 goto out;
3046
3047 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3048
3049 wl_sta = (struct wl1271_station *)sta->drv_priv;
3050 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3051 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3052 goto out;
3053
Ido Yariva6208652011-03-01 15:14:41 +02003054 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003055 if (ret < 0)
3056 goto out;
3057
3058 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3059 if (ret < 0)
3060 goto out_sleep;
3061
Arik Nemtsov409622e2011-02-23 00:22:29 +02003062 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003063
3064out_sleep:
3065 wl1271_ps_elp_sleep(wl);
3066
3067out:
3068 mutex_unlock(&wl->mutex);
3069 return ret;
3070}
3071
Luciano Coelho4623ec72011-03-21 19:26:41 +02003072static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3073 struct ieee80211_vif *vif,
3074 enum ieee80211_ampdu_mlme_action action,
3075 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3076 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003077{
3078 struct wl1271 *wl = hw->priv;
3079 int ret;
3080
3081 mutex_lock(&wl->mutex);
3082
3083 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3084 ret = -EAGAIN;
3085 goto out;
3086 }
3087
Ido Yariva6208652011-03-01 15:14:41 +02003088 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003089 if (ret < 0)
3090 goto out;
3091
3092 switch (action) {
3093 case IEEE80211_AMPDU_RX_START:
3094 if (wl->ba_support) {
3095 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3096 true);
3097 if (!ret)
3098 wl->ba_rx_bitmap |= BIT(tid);
3099 } else {
3100 ret = -ENOTSUPP;
3101 }
3102 break;
3103
3104 case IEEE80211_AMPDU_RX_STOP:
3105 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3106 if (!ret)
3107 wl->ba_rx_bitmap &= ~BIT(tid);
3108 break;
3109
3110 /*
3111 * The BA initiator session management in FW independently.
3112 * Falling break here on purpose for all TX APDU commands.
3113 */
3114 case IEEE80211_AMPDU_TX_START:
3115 case IEEE80211_AMPDU_TX_STOP:
3116 case IEEE80211_AMPDU_TX_OPERATIONAL:
3117 ret = -EINVAL;
3118 break;
3119
3120 default:
3121 wl1271_error("Incorrect ampdu action id=%x\n", action);
3122 ret = -EINVAL;
3123 }
3124
3125 wl1271_ps_elp_sleep(wl);
3126
3127out:
3128 mutex_unlock(&wl->mutex);
3129
3130 return ret;
3131}
3132
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003133/* can't be const, mac80211 writes to this */
3134static struct ieee80211_rate wl1271_rates[] = {
3135 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003136 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3137 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003138 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003139 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003141 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3142 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003143 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3144 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3146 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003147 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3148 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003149 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3150 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003151 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3152 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003153 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003154 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3155 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003157 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3158 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003160 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3161 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003163 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3164 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003165 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003166 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3167 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003168 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003169 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3170 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003171 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003172 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3173 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003174};
3175
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003176/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003178 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003179 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003180 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3181 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3182 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003183 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003184 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3185 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3186 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003187 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003188 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3189 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3190 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003191 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003192};
3193
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003194/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003195static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003196 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003197 7, /* CONF_HW_RXTX_RATE_MCS7 */
3198 6, /* CONF_HW_RXTX_RATE_MCS6 */
3199 5, /* CONF_HW_RXTX_RATE_MCS5 */
3200 4, /* CONF_HW_RXTX_RATE_MCS4 */
3201 3, /* CONF_HW_RXTX_RATE_MCS3 */
3202 2, /* CONF_HW_RXTX_RATE_MCS2 */
3203 1, /* CONF_HW_RXTX_RATE_MCS1 */
3204 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003205
3206 11, /* CONF_HW_RXTX_RATE_54 */
3207 10, /* CONF_HW_RXTX_RATE_48 */
3208 9, /* CONF_HW_RXTX_RATE_36 */
3209 8, /* CONF_HW_RXTX_RATE_24 */
3210
3211 /* TI-specific rate */
3212 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3213
3214 7, /* CONF_HW_RXTX_RATE_18 */
3215 6, /* CONF_HW_RXTX_RATE_12 */
3216 3, /* CONF_HW_RXTX_RATE_11 */
3217 5, /* CONF_HW_RXTX_RATE_9 */
3218 4, /* CONF_HW_RXTX_RATE_6 */
3219 2, /* CONF_HW_RXTX_RATE_5_5 */
3220 1, /* CONF_HW_RXTX_RATE_2 */
3221 0 /* CONF_HW_RXTX_RATE_1 */
3222};
3223
Shahar Levie8b03a22010-10-13 16:09:39 +02003224/* 11n STA capabilities */
3225#define HW_RX_HIGHEST_RATE 72
3226
Shahar Levi00d20102010-11-08 11:20:10 +00003227#ifdef CONFIG_WL12XX_HT
3228#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003229 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3230 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003231 .ht_supported = true, \
3232 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3233 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3234 .mcs = { \
3235 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3236 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3237 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3238 }, \
3239}
Shahar Levi18357852010-10-13 16:09:41 +02003240#else
Shahar Levi00d20102010-11-08 11:20:10 +00003241#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003242 .ht_supported = false, \
3243}
3244#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003245
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003246/* can't be const, mac80211 writes to this */
3247static struct ieee80211_supported_band wl1271_band_2ghz = {
3248 .channels = wl1271_channels,
3249 .n_channels = ARRAY_SIZE(wl1271_channels),
3250 .bitrates = wl1271_rates,
3251 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003252 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003253};
3254
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003255/* 5 GHz data rates for WL1273 */
3256static struct ieee80211_rate wl1271_rates_5ghz[] = {
3257 { .bitrate = 60,
3258 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3259 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3260 { .bitrate = 90,
3261 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3262 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3263 { .bitrate = 120,
3264 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3265 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3266 { .bitrate = 180,
3267 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3268 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3269 { .bitrate = 240,
3270 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3271 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3272 { .bitrate = 360,
3273 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3274 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3275 { .bitrate = 480,
3276 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3277 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3278 { .bitrate = 540,
3279 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3280 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3281};
3282
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003283/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003284static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003285 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003286 { .hw_value = 8, .center_freq = 5040},
3287 { .hw_value = 9, .center_freq = 5045},
3288 { .hw_value = 11, .center_freq = 5055},
3289 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003290 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003291 { .hw_value = 34, .center_freq = 5170},
3292 { .hw_value = 36, .center_freq = 5180},
3293 { .hw_value = 38, .center_freq = 5190},
3294 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003295 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003296 { .hw_value = 44, .center_freq = 5220},
3297 { .hw_value = 46, .center_freq = 5230},
3298 { .hw_value = 48, .center_freq = 5240},
3299 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003300 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003301 { .hw_value = 60, .center_freq = 5300},
3302 { .hw_value = 64, .center_freq = 5320},
3303 { .hw_value = 100, .center_freq = 5500},
3304 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003305 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003306 { .hw_value = 112, .center_freq = 5560},
3307 { .hw_value = 116, .center_freq = 5580},
3308 { .hw_value = 120, .center_freq = 5600},
3309 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003310 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003311 { .hw_value = 132, .center_freq = 5660},
3312 { .hw_value = 136, .center_freq = 5680},
3313 { .hw_value = 140, .center_freq = 5700},
3314 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003315 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003316 { .hw_value = 157, .center_freq = 5785},
3317 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003318 { .hw_value = 165, .center_freq = 5825},
3319};
3320
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003321/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003322static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003323 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003324 7, /* CONF_HW_RXTX_RATE_MCS7 */
3325 6, /* CONF_HW_RXTX_RATE_MCS6 */
3326 5, /* CONF_HW_RXTX_RATE_MCS5 */
3327 4, /* CONF_HW_RXTX_RATE_MCS4 */
3328 3, /* CONF_HW_RXTX_RATE_MCS3 */
3329 2, /* CONF_HW_RXTX_RATE_MCS2 */
3330 1, /* CONF_HW_RXTX_RATE_MCS1 */
3331 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003332
3333 7, /* CONF_HW_RXTX_RATE_54 */
3334 6, /* CONF_HW_RXTX_RATE_48 */
3335 5, /* CONF_HW_RXTX_RATE_36 */
3336 4, /* CONF_HW_RXTX_RATE_24 */
3337
3338 /* TI-specific rate */
3339 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3340
3341 3, /* CONF_HW_RXTX_RATE_18 */
3342 2, /* CONF_HW_RXTX_RATE_12 */
3343 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3344 1, /* CONF_HW_RXTX_RATE_9 */
3345 0, /* CONF_HW_RXTX_RATE_6 */
3346 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3347 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3348 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3349};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003350
3351static struct ieee80211_supported_band wl1271_band_5ghz = {
3352 .channels = wl1271_channels_5ghz,
3353 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3354 .bitrates = wl1271_rates_5ghz,
3355 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003356 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003357};
3358
Tobias Klausera0ea9492010-05-20 10:38:11 +02003359static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003360 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3361 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3362};
3363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003364static const struct ieee80211_ops wl1271_ops = {
3365 .start = wl1271_op_start,
3366 .stop = wl1271_op_stop,
3367 .add_interface = wl1271_op_add_interface,
3368 .remove_interface = wl1271_op_remove_interface,
3369 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003370 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003371 .configure_filter = wl1271_op_configure_filter,
3372 .tx = wl1271_op_tx,
3373 .set_key = wl1271_op_set_key,
3374 .hw_scan = wl1271_op_hw_scan,
3375 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003376 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003377 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003378 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003379 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003380 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003381 .sta_add = wl1271_op_sta_add,
3382 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003383 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003384 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003385};
3386
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003387
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003388u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003389{
3390 u8 idx;
3391
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003392 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003393
3394 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3395 wl1271_error("Illegal RX rate from HW: %d", rate);
3396 return 0;
3397 }
3398
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003399 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003400 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3401 wl1271_error("Unsupported RX rate from HW: %d", rate);
3402 return 0;
3403 }
3404
3405 return idx;
3406}
3407
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003408static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3409 struct device_attribute *attr,
3410 char *buf)
3411{
3412 struct wl1271 *wl = dev_get_drvdata(dev);
3413 ssize_t len;
3414
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003415 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003416
3417 mutex_lock(&wl->mutex);
3418 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3419 wl->sg_enabled);
3420 mutex_unlock(&wl->mutex);
3421
3422 return len;
3423
3424}
3425
3426static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3427 struct device_attribute *attr,
3428 const char *buf, size_t count)
3429{
3430 struct wl1271 *wl = dev_get_drvdata(dev);
3431 unsigned long res;
3432 int ret;
3433
Luciano Coelho6277ed62011-04-01 17:49:54 +03003434 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003435 if (ret < 0) {
3436 wl1271_warning("incorrect value written to bt_coex_mode");
3437 return count;
3438 }
3439
3440 mutex_lock(&wl->mutex);
3441
3442 res = !!res;
3443
3444 if (res == wl->sg_enabled)
3445 goto out;
3446
3447 wl->sg_enabled = res;
3448
3449 if (wl->state == WL1271_STATE_OFF)
3450 goto out;
3451
Ido Yariva6208652011-03-01 15:14:41 +02003452 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003453 if (ret < 0)
3454 goto out;
3455
3456 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3457 wl1271_ps_elp_sleep(wl);
3458
3459 out:
3460 mutex_unlock(&wl->mutex);
3461 return count;
3462}
3463
3464static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3465 wl1271_sysfs_show_bt_coex_state,
3466 wl1271_sysfs_store_bt_coex_state);
3467
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003468static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3469 struct device_attribute *attr,
3470 char *buf)
3471{
3472 struct wl1271 *wl = dev_get_drvdata(dev);
3473 ssize_t len;
3474
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003475 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003476
3477 mutex_lock(&wl->mutex);
3478 if (wl->hw_pg_ver >= 0)
3479 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3480 else
3481 len = snprintf(buf, len, "n/a\n");
3482 mutex_unlock(&wl->mutex);
3483
3484 return len;
3485}
3486
3487static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3488 wl1271_sysfs_show_hw_pg_ver, NULL);
3489
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003490int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003491{
3492 int ret;
3493
3494 if (wl->mac80211_registered)
3495 return 0;
3496
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003497 ret = wl1271_fetch_nvs(wl);
3498 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003499 /* NOTE: The wl->nvs->nvs element must be first, in
3500 * order to simplify the casting, we assume it is at
3501 * the beginning of the wl->nvs structure.
3502 */
3503 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003504
3505 wl->mac_addr[0] = nvs_ptr[11];
3506 wl->mac_addr[1] = nvs_ptr[10];
3507 wl->mac_addr[2] = nvs_ptr[6];
3508 wl->mac_addr[3] = nvs_ptr[5];
3509 wl->mac_addr[4] = nvs_ptr[4];
3510 wl->mac_addr[5] = nvs_ptr[3];
3511 }
3512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003513 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3514
3515 ret = ieee80211_register_hw(wl->hw);
3516 if (ret < 0) {
3517 wl1271_error("unable to register mac80211 hw: %d", ret);
3518 return ret;
3519 }
3520
3521 wl->mac80211_registered = true;
3522
Eliad Pellerd60080a2010-11-24 12:53:16 +02003523 wl1271_debugfs_init(wl);
3524
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003525 register_netdevice_notifier(&wl1271_dev_notifier);
3526
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003527 wl1271_notice("loaded");
3528
3529 return 0;
3530}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003531EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003533void wl1271_unregister_hw(struct wl1271 *wl)
3534{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003535 if (wl->state == WL1271_STATE_PLT)
3536 __wl1271_plt_stop(wl);
3537
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003538 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003539 ieee80211_unregister_hw(wl->hw);
3540 wl->mac80211_registered = false;
3541
3542}
3543EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3544
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003545int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003546{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003547 static const u32 cipher_suites[] = {
3548 WLAN_CIPHER_SUITE_WEP40,
3549 WLAN_CIPHER_SUITE_WEP104,
3550 WLAN_CIPHER_SUITE_TKIP,
3551 WLAN_CIPHER_SUITE_CCMP,
3552 WL1271_CIPHER_SUITE_GEM,
3553 };
3554
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003555 /* The tx descriptor buffer and the TKIP space. */
3556 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3557 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003558
3559 /* unit us */
3560 /* FIXME: find a proper value */
3561 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003562 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003563
3564 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003565 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003566 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003567 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003568 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003569 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003570 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003571 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003572
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003573 wl->hw->wiphy->cipher_suites = cipher_suites;
3574 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3575
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003576 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003577 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003579 /*
3580 * Maximum length of elements in scanning probe request templates
3581 * should be the maximum length possible for a template, without
3582 * the IEEE80211 header of the template
3583 */
3584 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3585 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003586
Luciano Coelho4a31c112011-03-21 23:16:14 +02003587 /* make sure all our channels fit in the scanned_ch bitmask */
3588 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3589 ARRAY_SIZE(wl1271_channels_5ghz) >
3590 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003591 /*
3592 * We keep local copies of the band structs because we need to
3593 * modify them on a per-device basis.
3594 */
3595 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3596 sizeof(wl1271_band_2ghz));
3597 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3598 sizeof(wl1271_band_5ghz));
3599
3600 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3601 &wl->bands[IEEE80211_BAND_2GHZ];
3602 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3603 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003604
Kalle Valo12bd8942010-03-18 12:26:33 +02003605 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003606 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003607
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003608 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3609
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003610 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003611
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003612 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3613
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003614 wl->hw->max_rx_aggregation_subframes = 8;
3615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003616 return 0;
3617}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003618EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003619
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003620#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003621
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003622struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003623{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003624 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003625 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003626 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003627 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003628 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003629
3630 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3631 if (!hw) {
3632 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003633 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003634 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003635 }
3636
Julia Lawall929ebd32010-05-15 23:16:39 +02003637 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003638 if (!plat_dev) {
3639 wl1271_error("could not allocate platform_device");
3640 ret = -ENOMEM;
3641 goto err_plat_alloc;
3642 }
3643
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003644 wl = hw->priv;
3645 memset(wl, 0, sizeof(*wl));
3646
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003647 INIT_LIST_HEAD(&wl->list);
3648
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003649 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003650 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003651
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003652 for (i = 0; i < NUM_TX_QUEUES; i++)
3653 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003654
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003655 for (i = 0; i < NUM_TX_QUEUES; i++)
3656 for (j = 0; j < AP_MAX_LINKS; j++)
3657 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3658
Ido Yariva6208652011-03-01 15:14:41 +02003659 skb_queue_head_init(&wl->deferred_rx_queue);
3660 skb_queue_head_init(&wl->deferred_tx_queue);
3661
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003662 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003663 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003664 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003665 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3666 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3667 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003668 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003669 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003670 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003671 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003672 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3673 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003674 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003675 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003676 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003677 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003678 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003679 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003680 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003681 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003682 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003683 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003684 wl->bss_type = MAX_BSS_TYPE;
3685 wl->set_bss_type = MAX_BSS_TYPE;
3686 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003687 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003688 wl->ap_ps_map = 0;
3689 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003690 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003691 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003693 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003694 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003695 wl->tx_frames[i] = NULL;
3696
3697 spin_lock_init(&wl->wl_lock);
3698
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699 wl->state = WL1271_STATE_OFF;
3700 mutex_init(&wl->mutex);
3701
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003702 /* Apply default driver configuration. */
3703 wl1271_conf_init(wl);
3704
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003705 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3706 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3707 if (!wl->aggr_buf) {
3708 ret = -ENOMEM;
3709 goto err_hw;
3710 }
3711
Ido Yariv990f5de2011-03-31 10:06:59 +02003712 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3713 if (!wl->dummy_packet) {
3714 ret = -ENOMEM;
3715 goto err_aggr;
3716 }
3717
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003718 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003719 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003720 if (ret) {
3721 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003722 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003723 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003724 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003725
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003726 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003727 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003728 if (ret < 0) {
3729 wl1271_error("failed to create sysfs file bt_coex_state");
3730 goto err_platform;
3731 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003732
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003733 /* Create sysfs file to get HW PG version */
3734 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3735 if (ret < 0) {
3736 wl1271_error("failed to create sysfs file hw_pg_ver");
3737 goto err_bt_coex_state;
3738 }
3739
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003740 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003741
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003742err_bt_coex_state:
3743 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3744
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003745err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003746 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003747
Ido Yariv990f5de2011-03-31 10:06:59 +02003748err_dummy_packet:
3749 dev_kfree_skb(wl->dummy_packet);
3750
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003751err_aggr:
3752 free_pages((unsigned long)wl->aggr_buf, order);
3753
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003754err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003755 wl1271_debugfs_exit(wl);
3756 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003757
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003758err_plat_alloc:
3759 ieee80211_free_hw(hw);
3760
3761err_hw_alloc:
3762
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003763 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003764}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003765EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003766
3767int wl1271_free_hw(struct wl1271 *wl)
3768{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003769 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003770 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003771 free_pages((unsigned long)wl->aggr_buf,
3772 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003773 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003774
3775 wl1271_debugfs_exit(wl);
3776
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003777 vfree(wl->fw);
3778 wl->fw = NULL;
3779 kfree(wl->nvs);
3780 wl->nvs = NULL;
3781
3782 kfree(wl->fw_status);
3783 kfree(wl->tx_res_if);
3784
3785 ieee80211_free_hw(wl->hw);
3786
3787 return 0;
3788}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003789EXPORT_SYMBOL_GPL(wl1271_free_hw);
3790
Guy Eilam491bbd62011-01-12 10:33:29 +01003791u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003792EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003793module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003794MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3795
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003796MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003797MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003798MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");