blob: a8770102a74afa4cbce995e0670b60aaae0ee1d2 [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,
Shahar Levi23708412011-04-13 14:52:50 +0300261 .psm_exit_retries = 16,
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,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300308 .dynamic_memory = 1,
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 },
Shahar Leviff868432011-04-11 15:41:46 +0300323 .fm_coex = {
324 .enable = true,
325 .swallow_period = 5,
326 .n_divider_fref_set_1 = 0xff, /* default */
327 .n_divider_fref_set_2 = 12,
328 .m_divider_fref_set_1 = 148,
329 .m_divider_fref_set_2 = 0xffff, /* default */
330 .coex_pll_stabilization_time = 0xffffffff, /* default */
331 .ldo_stabilization_time = 0xffff, /* default */
332 .fm_disturbed_band_margin = 0xff, /* default */
333 .swallow_clk_diff = 0xff, /* default */
334 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300335 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300336};
337
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200338static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200339static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200340
341
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200342static void wl1271_device_release(struct device *dev)
343{
344
345}
346
347static struct platform_device wl1271_device = {
348 .name = "wl1271",
349 .id = -1,
350
351 /* device model insists to have a release function */
352 .dev = {
353 .release = wl1271_device_release,
354 },
355};
356
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200357static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300358static LIST_HEAD(wl_list);
359
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300360static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
361 void *arg)
362{
363 struct net_device *dev = arg;
364 struct wireless_dev *wdev;
365 struct wiphy *wiphy;
366 struct ieee80211_hw *hw;
367 struct wl1271 *wl;
368 struct wl1271 *wl_temp;
369 int ret = 0;
370
371 /* Check that this notification is for us. */
372 if (what != NETDEV_CHANGE)
373 return NOTIFY_DONE;
374
375 wdev = dev->ieee80211_ptr;
376 if (wdev == NULL)
377 return NOTIFY_DONE;
378
379 wiphy = wdev->wiphy;
380 if (wiphy == NULL)
381 return NOTIFY_DONE;
382
383 hw = wiphy_priv(wiphy);
384 if (hw == NULL)
385 return NOTIFY_DONE;
386
387 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200388 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300389 list_for_each_entry(wl, &wl_list, list) {
390 if (wl == wl_temp)
391 break;
392 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200393 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300394 if (wl != wl_temp)
395 return NOTIFY_DONE;
396
397 mutex_lock(&wl->mutex);
398
399 if (wl->state == WL1271_STATE_OFF)
400 goto out;
401
402 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
403 goto out;
404
Ido Yariva6208652011-03-01 15:14:41 +0200405 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300406 if (ret < 0)
407 goto out;
408
409 if ((dev->operstate == IF_OPER_UP) &&
410 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
411 wl1271_cmd_set_sta_state(wl);
412 wl1271_info("Association completed.");
413 }
414
415 wl1271_ps_elp_sleep(wl);
416
417out:
418 mutex_unlock(&wl->mutex);
419
420 return NOTIFY_OK;
421}
422
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100423static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200424 struct regulatory_request *request)
425{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100426 struct ieee80211_supported_band *band;
427 struct ieee80211_channel *ch;
428 int i;
429
430 band = wiphy->bands[IEEE80211_BAND_5GHZ];
431 for (i = 0; i < band->n_channels; i++) {
432 ch = &band->channels[i];
433 if (ch->flags & IEEE80211_CHAN_DISABLED)
434 continue;
435
436 if (ch->flags & IEEE80211_CHAN_RADAR)
437 ch->flags |= IEEE80211_CHAN_NO_IBSS |
438 IEEE80211_CHAN_PASSIVE_SCAN;
439
440 }
441
442 return 0;
443}
444
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300445static void wl1271_conf_init(struct wl1271 *wl)
446{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300447
448 /*
449 * This function applies the default configuration to the driver. This
450 * function is invoked upon driver load (spi probe.)
451 *
452 * The configuration is stored in a run-time structure in order to
453 * facilitate for run-time adjustment of any of the parameters. Making
454 * changes to the configuration structure will apply the new values on
455 * the next interface up (wl1271_op_start.)
456 */
457
458 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300459 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300460}
461
462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463static int wl1271_plt_init(struct wl1271 *wl)
464{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200465 struct conf_tx_ac_category *conf_ac;
466 struct conf_tx_tid *conf_tid;
467 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300468
Shahar Levi49d750ca2011-03-06 16:32:09 +0200469 if (wl->chip.id == CHIP_ID_1283_PG20)
470 ret = wl128x_cmd_general_parms(wl);
471 else
472 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200473 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200474 return ret;
475
Shahar Levi49d750ca2011-03-06 16:32:09 +0200476 if (wl->chip.id == CHIP_ID_1283_PG20)
477 ret = wl128x_cmd_radio_parms(wl);
478 else
479 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200480 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200481 return ret;
482
Shahar Levi49d750ca2011-03-06 16:32:09 +0200483 if (wl->chip.id != CHIP_ID_1283_PG20) {
484 ret = wl1271_cmd_ext_radio_parms(wl);
485 if (ret < 0)
486 return ret;
487 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200488 if (ret < 0)
489 return ret;
490
Shahar Levi48a61472011-03-06 16:32:08 +0200491 /* Chip-specific initializations */
492 ret = wl1271_chip_specific_init(wl);
493 if (ret < 0)
494 return ret;
495
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200496 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200497 if (ret < 0)
498 return ret;
499
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300500 ret = wl1271_acx_init_mem_config(wl);
501 if (ret < 0)
502 return ret;
503
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 /* PHY layer config */
505 ret = wl1271_init_phy_config(wl);
506 if (ret < 0)
507 goto out_free_memmap;
508
509 ret = wl1271_acx_dco_itrim_params(wl);
510 if (ret < 0)
511 goto out_free_memmap;
512
513 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200514 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200515 if (ret < 0)
516 goto out_free_memmap;
517
518 /* Bluetooth WLAN coexistence */
519 ret = wl1271_init_pta(wl);
520 if (ret < 0)
521 goto out_free_memmap;
522
Shahar Leviff868432011-04-11 15:41:46 +0300523 /* FM WLAN coexistence */
524 ret = wl1271_acx_fm_coex(wl);
525 if (ret < 0)
526 goto out_free_memmap;
527
Luciano Coelho12419cc2010-02-18 13:25:44 +0200528 /* Energy detection */
529 ret = wl1271_init_energy_detection(wl);
530 if (ret < 0)
531 goto out_free_memmap;
532
Gery Kahn1ec610e2011-02-01 03:03:08 -0600533 ret = wl1271_acx_sta_mem_cfg(wl);
534 if (ret < 0)
535 goto out_free_memmap;
536
Luciano Coelho12419cc2010-02-18 13:25:44 +0200537 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100538 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200539 if (ret < 0)
540 goto out_free_memmap;
541
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200542 /* Default TID/AC configuration */
543 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200544 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200545 conf_ac = &wl->conf.tx.ac_conf[i];
546 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
547 conf_ac->cw_max, conf_ac->aifsn,
548 conf_ac->tx_op_limit);
549 if (ret < 0)
550 goto out_free_memmap;
551
Luciano Coelho12419cc2010-02-18 13:25:44 +0200552 conf_tid = &wl->conf.tx.tid_conf[i];
553 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
554 conf_tid->channel_type,
555 conf_tid->tsid,
556 conf_tid->ps_scheme,
557 conf_tid->ack_policy,
558 conf_tid->apsd_conf[0],
559 conf_tid->apsd_conf[1]);
560 if (ret < 0)
561 goto out_free_memmap;
562 }
563
Luciano Coelho12419cc2010-02-18 13:25:44 +0200564 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200565 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300566 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200567 goto out_free_memmap;
568
569 /* Configure for CAM power saving (ie. always active) */
570 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
571 if (ret < 0)
572 goto out_free_memmap;
573
574 /* configure PM */
575 ret = wl1271_acx_pm_config(wl);
576 if (ret < 0)
577 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578
579 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200580
581 out_free_memmap:
582 kfree(wl->target_mem_map);
583 wl->target_mem_map = NULL;
584
585 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300586}
587
Arik Nemtsovb622d992011-02-23 00:22:31 +0200588static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
589{
590 bool fw_ps;
591
592 /* only regulate station links */
593 if (hlid < WL1271_AP_STA_HLID_START)
594 return;
595
596 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
597
598 /*
599 * Wake up from high level PS if the STA is asleep with too little
600 * blocks in FW or if the STA is awake.
601 */
602 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
603 wl1271_ps_link_end(wl, hlid);
604
605 /* Start high-level PS if the STA is asleep with enough blocks in FW */
606 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
607 wl1271_ps_link_start(wl, hlid, true);
608}
609
610static void wl1271_irq_update_links_status(struct wl1271 *wl,
611 struct wl1271_fw_ap_status *status)
612{
613 u32 cur_fw_ps_map;
614 u8 hlid;
615
616 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
617 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
618 wl1271_debug(DEBUG_PSM,
619 "link ps prev 0x%x cur 0x%x changed 0x%x",
620 wl->ap_fw_ps_map, cur_fw_ps_map,
621 wl->ap_fw_ps_map ^ cur_fw_ps_map);
622
623 wl->ap_fw_ps_map = cur_fw_ps_map;
624 }
625
626 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
627 u8 cnt = status->tx_lnk_free_blks[hlid] -
628 wl->links[hlid].prev_freed_blks;
629
630 wl->links[hlid].prev_freed_blks =
631 status->tx_lnk_free_blks[hlid];
632 wl->links[hlid].allocated_blks -= cnt;
633
634 wl1271_irq_ps_regulate_link(wl, hlid,
635 wl->links[hlid].allocated_blks);
636 }
637}
638
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300639static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200640 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200642 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200643 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200644 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200645 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646 int i;
647
Shahar Levi13b107d2011-03-06 16:32:12 +0200648 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200649 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
650 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200651 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200652 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
653 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200654 }
655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
657 "drv_rx_counter = %d, tx_results_counter = %d)",
658 status->intr,
659 status->fw_rx_counter,
660 status->drv_rx_counter,
661 status->tx_results_counter);
662
663 /* update number of available TX blocks */
664 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200665 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
666 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300667
668 wl->tx_blocks_freed[i] =
669 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200670 }
671
Ido Yarivd2f4d472011-03-31 10:07:00 +0200672 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200673
Ido Yarivd2f4d472011-03-31 10:07:00 +0200674 if (wl->bss_type == BSS_TYPE_AP_BSS) {
675 /* Update num of allocated TX blocks per link and ps status */
676 wl1271_irq_update_links_status(wl, &full_status->ap);
677 wl->tx_blocks_available += freed_blocks;
678 } else {
679 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
680
681 /*
682 * The FW might change the total number of TX memblocks before
683 * we get a notification about blocks being released. Thus, the
684 * available blocks calculation might yield a temporary result
685 * which is lower than the actual available blocks. Keeping in
686 * mind that only blocks that were allocated can be moved from
687 * TX to RX, tx_blocks_available should never decrease here.
688 */
689 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
690 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 }
692
Ido Yariva5225502010-10-12 14:49:10 +0200693 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200694 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200695 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696
697 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200698 getnstimeofday(&ts);
699 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
700 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701}
702
Ido Yariva6208652011-03-01 15:14:41 +0200703static void wl1271_flush_deferred_work(struct wl1271 *wl)
704{
705 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200706
Ido Yariva6208652011-03-01 15:14:41 +0200707 /* Pass all received frames to the network stack */
708 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
709 ieee80211_rx_ni(wl->hw, skb);
710
711 /* Return sent skbs to the network stack */
712 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
713 ieee80211_tx_status(wl->hw, skb);
714}
715
716static void wl1271_netstack_work(struct work_struct *work)
717{
718 struct wl1271 *wl =
719 container_of(work, struct wl1271, netstack_work);
720
721 do {
722 wl1271_flush_deferred_work(wl);
723 } while (skb_queue_len(&wl->deferred_rx_queue));
724}
725
726#define WL1271_IRQ_MAX_LOOPS 256
727
728irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300729{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300731 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200732 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200733 struct wl1271 *wl = (struct wl1271 *)cookie;
734 bool done = false;
735 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200736 unsigned long flags;
737
738 /* TX might be handled here, avoid redundant work */
739 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
740 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
Ido Yariv341b7cd2011-03-31 10:07:01 +0200742 /*
743 * In case edge triggered interrupt must be used, we cannot iterate
744 * more than once without introducing race conditions with the hardirq.
745 */
746 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
747 loopcount = 1;
748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300749 mutex_lock(&wl->mutex);
750
751 wl1271_debug(DEBUG_IRQ, "IRQ work");
752
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200753 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 goto out;
755
Ido Yariva6208652011-03-01 15:14:41 +0200756 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757 if (ret < 0)
758 goto out;
759
Ido Yariva6208652011-03-01 15:14:41 +0200760 while (!done && loopcount--) {
761 /*
762 * In order to avoid a race with the hardirq, clear the flag
763 * before acknowledging the chip. Since the mutex is held,
764 * wl1271_ps_elp_wakeup cannot be called concurrently.
765 */
766 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
767 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200768
769 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200770 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200771 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200772 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200773 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200774 continue;
775 }
776
Eliad Pellerccc83b02010-10-27 14:09:57 +0200777 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
778 wl1271_error("watchdog interrupt received! "
779 "starting recovery.");
780 ieee80211_queue_work(wl->hw, &wl->recovery_work);
781
782 /* restarting the chip. ignore any other interrupt. */
783 goto out;
784 }
785
Ido Yariva6208652011-03-01 15:14:41 +0200786 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200787 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
788
Ido Yariv8aad2462011-03-01 15:14:38 +0200789 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200790
Ido Yariva5225502010-10-12 14:49:10 +0200791 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200792 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200793 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200794 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200795 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200796 /*
797 * In order to avoid starvation of the TX path,
798 * call the work function directly.
799 */
800 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200801 } else {
802 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200803 }
804
Ido Yariv8aad2462011-03-01 15:14:38 +0200805 /* check for tx results */
806 if (wl->fw_status->common.tx_results_counter !=
807 (wl->tx_results_count & 0xff))
808 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200809
810 /* Make sure the deferred queues don't get too long */
811 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
812 skb_queue_len(&wl->deferred_rx_queue);
813 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
814 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200815 }
816
817 if (intr & WL1271_ACX_INTR_EVENT_A) {
818 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
819 wl1271_event_handle(wl, 0);
820 }
821
822 if (intr & WL1271_ACX_INTR_EVENT_B) {
823 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
824 wl1271_event_handle(wl, 1);
825 }
826
827 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
828 wl1271_debug(DEBUG_IRQ,
829 "WL1271_ACX_INTR_INIT_COMPLETE");
830
831 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
832 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833 }
834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300835 wl1271_ps_elp_sleep(wl);
836
837out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200838 spin_lock_irqsave(&wl->wl_lock, flags);
839 /* In case TX was not handled here, queue TX work */
840 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
841 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
842 wl->tx_queue_count)
843 ieee80211_queue_work(wl->hw, &wl->tx_work);
844 spin_unlock_irqrestore(&wl->wl_lock, flags);
845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200847
848 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849}
Ido Yariva6208652011-03-01 15:14:41 +0200850EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300852static int wl1271_fetch_firmware(struct wl1271 *wl)
853{
854 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200855 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856 int ret;
857
Arik Nemtsov166d5042010-10-16 21:44:57 +0200858 switch (wl->bss_type) {
859 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200860 if (wl->chip.id == CHIP_ID_1283_PG20)
861 fw_name = WL128X_AP_FW_NAME;
862 else
863 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200864 break;
865 case BSS_TYPE_IBSS:
866 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200867 if (wl->chip.id == CHIP_ID_1283_PG20)
868 fw_name = WL128X_FW_NAME;
869 else
870 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200871 break;
872 default:
873 wl1271_error("no compatible firmware for bss_type %d",
874 wl->bss_type);
875 return -EINVAL;
876 }
877
878 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
879
880 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
882 if (ret < 0) {
883 wl1271_error("could not get firmware: %d", ret);
884 return ret;
885 }
886
887 if (fw->size % 4) {
888 wl1271_error("firmware size is not multiple of 32 bits: %zu",
889 fw->size);
890 ret = -EILSEQ;
891 goto out;
892 }
893
Arik Nemtsov166d5042010-10-16 21:44:57 +0200894 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300896 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897
898 if (!wl->fw) {
899 wl1271_error("could not allocate memory for the firmware");
900 ret = -ENOMEM;
901 goto out;
902 }
903
904 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200905 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300906 ret = 0;
907
908out:
909 release_firmware(fw);
910
911 return ret;
912}
913
914static int wl1271_fetch_nvs(struct wl1271 *wl)
915{
916 const struct firmware *fw;
917 int ret;
918
Shahar Levi5aa42342011-03-06 16:32:07 +0200919 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920
921 if (ret < 0) {
922 wl1271_error("could not get nvs file: %d", ret);
923 return ret;
924 }
925
Shahar Levibc765bf2011-03-06 16:32:10 +0200926 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927
928 if (!wl->nvs) {
929 wl1271_error("could not allocate memory for the nvs file");
930 ret = -ENOMEM;
931 goto out;
932 }
933
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200934 wl->nvs_len = fw->size;
935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936out:
937 release_firmware(fw);
938
939 return ret;
940}
941
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200942static void wl1271_recovery_work(struct work_struct *work)
943{
944 struct wl1271 *wl =
945 container_of(work, struct wl1271, recovery_work);
946
947 mutex_lock(&wl->mutex);
948
949 if (wl->state != WL1271_STATE_ON)
950 goto out;
951
952 wl1271_info("Hardware recovery in progress.");
953
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200954 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
955 ieee80211_connection_loss(wl->vif);
956
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200957 /* reboot the chipset */
958 __wl1271_op_remove_interface(wl);
959 ieee80211_restart_hw(wl->hw);
960
961out:
962 mutex_unlock(&wl->mutex);
963}
964
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965static void wl1271_fw_wakeup(struct wl1271 *wl)
966{
967 u32 elp_reg;
968
969 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300970 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971}
972
973static int wl1271_setup(struct wl1271 *wl)
974{
975 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
976 if (!wl->fw_status)
977 return -ENOMEM;
978
979 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
980 if (!wl->tx_res_if) {
981 kfree(wl->fw_status);
982 return -ENOMEM;
983 }
984
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 return 0;
986}
987
988static int wl1271_chip_wakeup(struct wl1271 *wl)
989{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300990 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 int ret = 0;
992
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200993 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200994 ret = wl1271_power_on(wl);
995 if (ret < 0)
996 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200998 wl1271_io_reset(wl);
999 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000
1001 /* We don't need a real memory partition here, because we only want
1002 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001003 memset(&partition, 0, sizeof(partition));
1004 partition.reg.start = REGISTERS_BASE;
1005 partition.reg.size = REGISTERS_DOWN_SIZE;
1006 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
1008 /* ELP module wake up */
1009 wl1271_fw_wakeup(wl);
1010
1011 /* whal_FwCtrl_BootSm() */
1012
1013 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001014 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015
1016 /* 1. check if chip id is valid */
1017
1018 switch (wl->chip.id) {
1019 case CHIP_ID_1271_PG10:
1020 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1021 wl->chip.id);
1022
1023 ret = wl1271_setup(wl);
1024 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001025 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 break;
1027 case CHIP_ID_1271_PG20:
1028 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1029 wl->chip.id);
1030
Shahar Levi564f5952011-04-04 10:20:39 +03001031 /* end-of-transaction flag should be set in wl127x AP mode */
1032 if (wl->bss_type == BSS_TYPE_AP_BSS)
1033 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035 ret = wl1271_setup(wl);
1036 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001037 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001039 case CHIP_ID_1283_PG20:
1040 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1041 wl->chip.id);
1042
1043 ret = wl1271_setup(wl);
1044 if (ret < 0)
1045 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001046 if (wl1271_set_block_size(wl))
1047 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001048 break;
1049 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001051 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001053 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 }
1055
Arik Nemtsov166d5042010-10-16 21:44:57 +02001056 /* Make sure the firmware type matches the BSS type */
1057 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 ret = wl1271_fetch_firmware(wl);
1059 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001060 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 }
1062
1063 /* No NVS from netlink, try to get it from the filesystem */
1064 if (wl->nvs == NULL) {
1065 ret = wl1271_fetch_nvs(wl);
1066 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001067 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 }
1069
1070out:
1071 return ret;
1072}
1073
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001074static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1075{
1076 unsigned int quirks = 0;
1077 unsigned int *fw_ver = wl->chip.fw_ver;
1078
1079 /* Only for wl127x */
1080 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1081 /* Check STA version */
1082 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1083 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1084 /* Check AP version */
1085 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1086 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1087 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1088
1089 return quirks;
1090}
1091
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092int wl1271_plt_start(struct wl1271 *wl)
1093{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001094 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 int ret;
1096
1097 mutex_lock(&wl->mutex);
1098
1099 wl1271_notice("power up");
1100
1101 if (wl->state != WL1271_STATE_OFF) {
1102 wl1271_error("cannot go into PLT state because not "
1103 "in off state: %d", wl->state);
1104 ret = -EBUSY;
1105 goto out;
1106 }
1107
Arik Nemtsov166d5042010-10-16 21:44:57 +02001108 wl->bss_type = BSS_TYPE_STA_BSS;
1109
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001110 while (retries) {
1111 retries--;
1112 ret = wl1271_chip_wakeup(wl);
1113 if (ret < 0)
1114 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001115
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001116 ret = wl1271_boot(wl);
1117 if (ret < 0)
1118 goto power_off;
1119
1120 ret = wl1271_plt_init(wl);
1121 if (ret < 0)
1122 goto irq_disable;
1123
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001124 wl->state = WL1271_STATE_PLT;
1125 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001126 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001127
1128 /* Check if any quirks are needed with older fw versions */
1129 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130 goto out;
1131
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001132irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001133 mutex_unlock(&wl->mutex);
1134 /* Unlocking the mutex in the middle of handling is
1135 inherently unsafe. In this case we deem it safe to do,
1136 because we need to let any possibly pending IRQ out of
1137 the system (and while we are WL1271_STATE_OFF the IRQ
1138 work function will not do anything.) Also, any other
1139 possible concurrent operations will fail due to the
1140 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001141 wl1271_disable_interrupts(wl);
1142 wl1271_flush_deferred_work(wl);
1143 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001144 mutex_lock(&wl->mutex);
1145power_off:
1146 wl1271_power_off(wl);
1147 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001148
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001149 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1150 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001151out:
1152 mutex_unlock(&wl->mutex);
1153
1154 return ret;
1155}
1156
Luciano Coelho4623ec72011-03-21 19:26:41 +02001157static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158{
1159 int ret = 0;
1160
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161 wl1271_notice("power down");
1162
1163 if (wl->state != WL1271_STATE_PLT) {
1164 wl1271_error("cannot power down because not in PLT "
1165 "state: %d", wl->state);
1166 ret = -EBUSY;
1167 goto out;
1168 }
1169
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170 wl1271_power_off(wl);
1171
1172 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001173 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001176 wl1271_disable_interrupts(wl);
1177 wl1271_flush_deferred_work(wl);
1178 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001179 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001180 mutex_lock(&wl->mutex);
1181out:
1182 return ret;
1183}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001184
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001185int wl1271_plt_stop(struct wl1271 *wl)
1186{
1187 int ret;
1188
1189 mutex_lock(&wl->mutex);
1190 ret = __wl1271_plt_stop(wl);
1191 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 return ret;
1193}
1194
Johannes Berg7bb45682011-02-24 14:42:06 +01001195static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196{
1197 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001198 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001199 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001200 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201
Ido Yarivb07d4032011-03-01 15:14:43 +02001202 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1203
1204 if (wl->bss_type == BSS_TYPE_AP_BSS)
1205 hlid = wl1271_tx_get_hlid(skb);
1206
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001207 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001208
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001209 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001210
1211 /*
1212 * The workqueue is slow to process the tx_queue and we need stop
1213 * the queue here, otherwise the queue will get too long.
1214 */
1215 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1216 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1217 ieee80211_stop_queues(wl->hw);
1218 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1219 }
1220
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001221 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001222 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001223 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1224 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1225 } else {
1226 skb_queue_tail(&wl->tx_queue[q], skb);
1227 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228
1229 /*
1230 * The chip specific setup must run before the first TX packet -
1231 * before that, the tx_work will not be initialized!
1232 */
1233
Ido Yarivb07d4032011-03-01 15:14:43 +02001234 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1235 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001236 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001237
1238 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239}
1240
Shahar Leviae47c452011-03-06 16:32:14 +02001241int wl1271_tx_dummy_packet(struct wl1271 *wl)
1242{
Ido Yariv990f5de2011-03-31 10:06:59 +02001243 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001244
Ido Yariv990f5de2011-03-31 10:06:59 +02001245 spin_lock_irqsave(&wl->wl_lock, flags);
1246 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1247 wl->tx_queue_count++;
1248 spin_unlock_irqrestore(&wl->wl_lock, flags);
1249
1250 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1251 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1252 wl1271_tx_work_locked(wl);
1253
1254 /*
1255 * If the FW TX is busy, TX work will be scheduled by the threaded
1256 * interrupt handler function
1257 */
1258 return 0;
1259}
1260
1261/*
1262 * The size of the dummy packet should be at least 1400 bytes. However, in
1263 * order to minimize the number of bus transactions, aligning it to 512 bytes
1264 * boundaries could be beneficial, performance wise
1265 */
1266#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1267
Luciano Coelhocf27d862011-04-01 21:08:23 +03001268static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001269{
1270 struct sk_buff *skb;
1271 struct ieee80211_hdr_3addr *hdr;
1272 unsigned int dummy_packet_size;
1273
1274 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1275 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1276
1277 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001278 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001279 wl1271_warning("Failed to allocate a dummy packet skb");
1280 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001281 }
1282
1283 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1284
1285 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1286 memset(hdr, 0, sizeof(*hdr));
1287 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001288 IEEE80211_STYPE_NULLFUNC |
1289 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001290
Ido Yariv990f5de2011-03-31 10:06:59 +02001291 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001292
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001293 /* Dummy packets require the TID to be management */
1294 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001295
1296 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001297 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001298 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001299
Ido Yariv990f5de2011-03-31 10:06:59 +02001300 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001301}
1302
Ido Yariv990f5de2011-03-31 10:06:59 +02001303
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001304static struct notifier_block wl1271_dev_notifier = {
1305 .notifier_call = wl1271_dev_notify,
1306};
1307
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308static int wl1271_op_start(struct ieee80211_hw *hw)
1309{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001310 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1311
1312 /*
1313 * We have to delay the booting of the hardware because
1314 * we need to know the local MAC address before downloading and
1315 * initializing the firmware. The MAC address cannot be changed
1316 * after boot, and without the proper MAC address, the firmware
1317 * will not function properly.
1318 *
1319 * The MAC address is first known when the corresponding interface
1320 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001321 *
1322 * In addition, we currently have different firmwares for AP and managed
1323 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001324 */
1325
1326 return 0;
1327}
1328
1329static void wl1271_op_stop(struct ieee80211_hw *hw)
1330{
1331 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1332}
1333
1334static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1335 struct ieee80211_vif *vif)
1336{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001338 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001339 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001341 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001343 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1344 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345
1346 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001347 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001348 wl1271_debug(DEBUG_MAC80211,
1349 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001350 ret = -EBUSY;
1351 goto out;
1352 }
1353
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001354 /*
1355 * in some very corner case HW recovery scenarios its possible to
1356 * get here before __wl1271_op_remove_interface is complete, so
1357 * opt out if that is the case.
1358 */
1359 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1360 ret = -EBUSY;
1361 goto out;
1362 }
1363
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001364 switch (vif->type) {
1365 case NL80211_IFTYPE_STATION:
1366 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001367 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001368 break;
1369 case NL80211_IFTYPE_ADHOC:
1370 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001371 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001372 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001373 case NL80211_IFTYPE_AP:
1374 wl->bss_type = BSS_TYPE_AP_BSS;
1375 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001376 default:
1377 ret = -EOPNOTSUPP;
1378 goto out;
1379 }
1380
1381 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
1383 if (wl->state != WL1271_STATE_OFF) {
1384 wl1271_error("cannot start because not in off state: %d",
1385 wl->state);
1386 ret = -EBUSY;
1387 goto out;
1388 }
1389
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001390 while (retries) {
1391 retries--;
1392 ret = wl1271_chip_wakeup(wl);
1393 if (ret < 0)
1394 goto power_off;
1395
1396 ret = wl1271_boot(wl);
1397 if (ret < 0)
1398 goto power_off;
1399
1400 ret = wl1271_hw_init(wl);
1401 if (ret < 0)
1402 goto irq_disable;
1403
Eliad Peller71125ab2010-10-28 21:46:43 +02001404 booted = true;
1405 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001407irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001408 mutex_unlock(&wl->mutex);
1409 /* Unlocking the mutex in the middle of handling is
1410 inherently unsafe. In this case we deem it safe to do,
1411 because we need to let any possibly pending IRQ out of
1412 the system (and while we are WL1271_STATE_OFF the IRQ
1413 work function will not do anything.) Also, any other
1414 possible concurrent operations will fail due to the
1415 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001416 wl1271_disable_interrupts(wl);
1417 wl1271_flush_deferred_work(wl);
1418 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001419 mutex_lock(&wl->mutex);
1420power_off:
1421 wl1271_power_off(wl);
1422 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423
Eliad Peller71125ab2010-10-28 21:46:43 +02001424 if (!booted) {
1425 wl1271_error("firmware boot failed despite %d retries",
1426 WL1271_BOOT_RETRIES);
1427 goto out;
1428 }
1429
1430 wl->vif = vif;
1431 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001432 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001433 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001434
1435 /* update hw/fw version info in wiphy struct */
1436 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001437 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001438 sizeof(wiphy->fw_version));
1439
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001440 /* Check if any quirks are needed with older fw versions */
1441 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1442
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001443 /*
1444 * Now we know if 11a is supported (info from the NVS), so disable
1445 * 11a channels if not supported
1446 */
1447 if (!wl->enable_11a)
1448 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1449
1450 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1451 wl->enable_11a ? "" : "not ");
1452
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001453out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 mutex_unlock(&wl->mutex);
1455
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001456 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001457 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001458 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001459 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 return ret;
1462}
1463
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001464static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001466 int i;
1467
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001468 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001470 /* because of hardware recovery, we may get here twice */
1471 if (wl->state != WL1271_STATE_ON)
1472 return;
1473
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001474 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001476 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001477 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001478 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001479
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001480 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001481 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001482 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001483
Luciano Coelho08688d62010-07-08 17:50:07 +03001484 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001485 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001486 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001487 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001488 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489 }
1490
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001491 /*
1492 * this must be before the cancel_work calls below, so that the work
1493 * functions don't perform further work.
1494 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 wl->state = WL1271_STATE_OFF;
1496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 mutex_unlock(&wl->mutex);
1498
Ido Yariva6208652011-03-01 15:14:41 +02001499 wl1271_disable_interrupts(wl);
1500 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001501 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001502 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001504 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001505 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506
1507 mutex_lock(&wl->mutex);
1508
1509 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001510 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 wl1271_power_off(wl);
1512
1513 memset(wl->bssid, 0, ETH_ALEN);
1514 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1515 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001517 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001518 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
1520 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001521 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001522 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1523 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001524 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001525 wl->tx_results_count = 0;
1526 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001527 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001528 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 wl->time_offset = 0;
1530 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001531 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001532 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001533 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001534 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001535 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001536 wl->ap_fw_ps_map = 0;
1537 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001538
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001539 /*
1540 * this is performed after the cancel_work calls and the associated
1541 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1542 * get executed before all these vars have been reset.
1543 */
1544 wl->flags = 0;
1545
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546 for (i = 0; i < NUM_TX_QUEUES; i++)
1547 wl->tx_blocks_freed[i] = 0;
1548
1549 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001550
1551 kfree(wl->fw_status);
1552 wl->fw_status = NULL;
1553 kfree(wl->tx_res_if);
1554 wl->tx_res_if = NULL;
1555 kfree(wl->target_mem_map);
1556 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001557}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001558
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001559static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1560 struct ieee80211_vif *vif)
1561{
1562 struct wl1271 *wl = hw->priv;
1563
1564 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001565 /*
1566 * wl->vif can be null here if someone shuts down the interface
1567 * just when hardware recovery has been started.
1568 */
1569 if (wl->vif) {
1570 WARN_ON(wl->vif != vif);
1571 __wl1271_op_remove_interface(wl);
1572 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001573
Juuso Oikarinen67353292010-11-18 15:19:02 +02001574 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001575 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001576}
1577
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001578void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001579{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001580 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001581
1582 /* combine requested filters with current filter config */
1583 filters = wl->filters | filters;
1584
1585 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1586
1587 if (filters & FIF_PROMISC_IN_BSS) {
1588 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1589 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1590 wl->rx_config |= CFG_BSSID_FILTER_EN;
1591 }
1592 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1593 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1594 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1595 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1596 }
1597 if (filters & FIF_OTHER_BSS) {
1598 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1599 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1600 }
1601 if (filters & FIF_CONTROL) {
1602 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1603 wl->rx_filter |= CFG_RX_CTL_EN;
1604 }
1605 if (filters & FIF_FCSFAIL) {
1606 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1607 wl->rx_filter |= CFG_RX_FCS_ERROR;
1608 }
1609}
1610
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001611static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001612{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001613 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001614 /* we need to use a dummy BSSID for now */
1615 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1616 0xad, 0xbe, 0xef };
1617
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001618 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1619
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001620 /* pass through frames from all BSS */
1621 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1622
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001623 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001624 if (ret < 0)
1625 goto out;
1626
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001627 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001628
1629out:
1630 return ret;
1631}
1632
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001633static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001634{
1635 int ret;
1636
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001637 /*
1638 * One of the side effects of the JOIN command is that is clears
1639 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1640 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001641 * Currently the only valid scenario for JOIN during association
1642 * is on roaming, in which case we will also be given new keys.
1643 * Keep the below message for now, unless it starts bothering
1644 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001645 */
1646 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1647 wl1271_info("JOIN while associated.");
1648
1649 if (set_assoc)
1650 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1651
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001652 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1653 if (ret < 0)
1654 goto out;
1655
1656 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1657
1658 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1659 goto out;
1660
1661 /*
1662 * The join command disable the keep-alive mode, shut down its process,
1663 * and also clear the template config, so we need to reset it all after
1664 * the join. The acx_aid starts the keep-alive process, and the order
1665 * of the commands below is relevant.
1666 */
1667 ret = wl1271_acx_keep_alive_mode(wl, true);
1668 if (ret < 0)
1669 goto out;
1670
1671 ret = wl1271_acx_aid(wl, wl->aid);
1672 if (ret < 0)
1673 goto out;
1674
1675 ret = wl1271_cmd_build_klv_null_data(wl);
1676 if (ret < 0)
1677 goto out;
1678
1679 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1680 ACX_KEEP_ALIVE_TPL_VALID);
1681 if (ret < 0)
1682 goto out;
1683
1684out:
1685 return ret;
1686}
1687
1688static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001689{
1690 int ret;
1691
1692 /* to stop listening to a channel, we disconnect */
1693 ret = wl1271_cmd_disconnect(wl);
1694 if (ret < 0)
1695 goto out;
1696
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001697 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001698 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001699
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001700 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001701 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001702
1703out:
1704 return ret;
1705}
1706
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001707static void wl1271_set_band_rate(struct wl1271 *wl)
1708{
1709 if (wl->band == IEEE80211_BAND_2GHZ)
1710 wl->basic_rate_set = wl->conf.tx.basic_rate;
1711 else
1712 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1713}
1714
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001715static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001716{
1717 int ret;
1718
1719 if (idle) {
1720 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1721 ret = wl1271_unjoin(wl);
1722 if (ret < 0)
1723 goto out;
1724 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001725 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001726 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001727 if (ret < 0)
1728 goto out;
1729 ret = wl1271_acx_keep_alive_config(
1730 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1731 ACX_KEEP_ALIVE_TPL_INVALID);
1732 if (ret < 0)
1733 goto out;
1734 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1735 } else {
1736 /* increment the session counter */
1737 wl->session_counter++;
1738 if (wl->session_counter >= SESSION_COUNTER_MAX)
1739 wl->session_counter = 0;
1740 ret = wl1271_dummy_join(wl);
1741 if (ret < 0)
1742 goto out;
1743 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1744 }
1745
1746out:
1747 return ret;
1748}
1749
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1751{
1752 struct wl1271 *wl = hw->priv;
1753 struct ieee80211_conf *conf = &hw->conf;
1754 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001755 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756
1757 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1758
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001759 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1760 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001761 channel,
1762 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001763 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001764 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1765 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001767 /*
1768 * mac80211 will go to idle nearly immediately after transmitting some
1769 * frames, such as the deauth. To make sure those frames reach the air,
1770 * wait here until the TX queue is fully flushed.
1771 */
1772 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1773 (conf->flags & IEEE80211_CONF_IDLE))
1774 wl1271_tx_flush(wl);
1775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001776 mutex_lock(&wl->mutex);
1777
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001778 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001779 /* we support configuring the channel and band while off */
1780 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1781 wl->band = conf->channel->band;
1782 wl->channel = channel;
1783 }
1784
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001785 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001786 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001787
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001788 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1789
Ido Yariva6208652011-03-01 15:14:41 +02001790 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791 if (ret < 0)
1792 goto out;
1793
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001794 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001795 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1796 ((wl->band != conf->channel->band) ||
1797 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001798 wl->band = conf->channel->band;
1799 wl->channel = channel;
1800
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001801 if (!is_ap) {
1802 /*
1803 * FIXME: the mac80211 should really provide a fixed
1804 * rate to use here. for now, just use the smallest
1805 * possible rate for the band as a fixed rate for
1806 * association frames and other control messages.
1807 */
1808 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1809 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001810
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001811 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1812 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001813 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001814 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001815 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001816
1817 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1818 ret = wl1271_join(wl, false);
1819 if (ret < 0)
1820 wl1271_warning("cmd join on channel "
1821 "failed %d", ret);
1822 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001823 }
1824 }
1825
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001826 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1827 ret = wl1271_sta_handle_idle(wl,
1828 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001829 if (ret < 0)
1830 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 }
1832
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001833 /*
1834 * if mac80211 changes the PSM mode, make sure the mode is not
1835 * incorrectly changed after the pspoll failure active window.
1836 */
1837 if (changed & IEEE80211_CONF_CHANGE_PS)
1838 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1839
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001840 if (conf->flags & IEEE80211_CONF_PS &&
1841 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1842 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843
1844 /*
1845 * We enter PSM only if we're already associated.
1846 * If we're not, we'll enter it when joining an SSID,
1847 * through the bss_info_changed() hook.
1848 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001849 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001850 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001851 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001852 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001853 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001855 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001856 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001858 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001860 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001861 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001862 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 }
1864
1865 if (conf->power_level != wl->power_level) {
1866 ret = wl1271_acx_tx_power(wl, conf->power_level);
1867 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001868 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001869
1870 wl->power_level = conf->power_level;
1871 }
1872
1873out_sleep:
1874 wl1271_ps_elp_sleep(wl);
1875
1876out:
1877 mutex_unlock(&wl->mutex);
1878
1879 return ret;
1880}
1881
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001882struct wl1271_filter_params {
1883 bool enabled;
1884 int mc_list_length;
1885 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1886};
1887
Jiri Pirko22bedad2010-04-01 21:22:57 +00001888static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1889 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001890{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001891 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001892 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001893 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001894
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001895 if (unlikely(wl->state == WL1271_STATE_OFF))
1896 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001897
Juuso Oikarinen74441132009-10-13 12:47:53 +03001898 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001899 if (!fp) {
1900 wl1271_error("Out of memory setting filters.");
1901 return 0;
1902 }
1903
1904 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001905 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001906 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1907 fp->enabled = false;
1908 } else {
1909 fp->enabled = true;
1910 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001911 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001912 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001913 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001914 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001915 }
1916
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001917 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001918}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001920#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1921 FIF_ALLMULTI | \
1922 FIF_FCSFAIL | \
1923 FIF_BCN_PRBRESP_PROMISC | \
1924 FIF_CONTROL | \
1925 FIF_OTHER_BSS)
1926
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1928 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001929 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001931 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001933 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934
Arik Nemtsov7d057862010-10-16 19:25:35 +02001935 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1936 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001938 mutex_lock(&wl->mutex);
1939
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001940 *total &= WL1271_SUPPORTED_FILTERS;
1941 changed &= WL1271_SUPPORTED_FILTERS;
1942
1943 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001944 goto out;
1945
Ido Yariva6208652011-03-01 15:14:41 +02001946 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001947 if (ret < 0)
1948 goto out;
1949
Arik Nemtsov7d057862010-10-16 19:25:35 +02001950 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1951 if (*total & FIF_ALLMULTI)
1952 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1953 else if (fp)
1954 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1955 fp->mc_list,
1956 fp->mc_list_length);
1957 if (ret < 0)
1958 goto out_sleep;
1959 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001961 /* determine, whether supported filter values have changed */
1962 if (changed == 0)
1963 goto out_sleep;
1964
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001965 /* configure filters */
1966 wl->filters = *total;
1967 wl1271_configure_filters(wl, 0);
1968
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001969 /* apply configured filters */
1970 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1971 if (ret < 0)
1972 goto out_sleep;
1973
1974out_sleep:
1975 wl1271_ps_elp_sleep(wl);
1976
1977out:
1978 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001979 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980}
1981
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001982static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1983 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1984 u16 tx_seq_16)
1985{
1986 struct wl1271_ap_key *ap_key;
1987 int i;
1988
1989 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1990
1991 if (key_size > MAX_KEY_SIZE)
1992 return -EINVAL;
1993
1994 /*
1995 * Find next free entry in ap_keys. Also check we are not replacing
1996 * an existing key.
1997 */
1998 for (i = 0; i < MAX_NUM_KEYS; i++) {
1999 if (wl->recorded_ap_keys[i] == NULL)
2000 break;
2001
2002 if (wl->recorded_ap_keys[i]->id == id) {
2003 wl1271_warning("trying to record key replacement");
2004 return -EINVAL;
2005 }
2006 }
2007
2008 if (i == MAX_NUM_KEYS)
2009 return -EBUSY;
2010
2011 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2012 if (!ap_key)
2013 return -ENOMEM;
2014
2015 ap_key->id = id;
2016 ap_key->key_type = key_type;
2017 ap_key->key_size = key_size;
2018 memcpy(ap_key->key, key, key_size);
2019 ap_key->hlid = hlid;
2020 ap_key->tx_seq_32 = tx_seq_32;
2021 ap_key->tx_seq_16 = tx_seq_16;
2022
2023 wl->recorded_ap_keys[i] = ap_key;
2024 return 0;
2025}
2026
2027static void wl1271_free_ap_keys(struct wl1271 *wl)
2028{
2029 int i;
2030
2031 for (i = 0; i < MAX_NUM_KEYS; i++) {
2032 kfree(wl->recorded_ap_keys[i]);
2033 wl->recorded_ap_keys[i] = NULL;
2034 }
2035}
2036
2037static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2038{
2039 int i, ret = 0;
2040 struct wl1271_ap_key *key;
2041 bool wep_key_added = false;
2042
2043 for (i = 0; i < MAX_NUM_KEYS; i++) {
2044 if (wl->recorded_ap_keys[i] == NULL)
2045 break;
2046
2047 key = wl->recorded_ap_keys[i];
2048 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2049 key->id, key->key_type,
2050 key->key_size, key->key,
2051 key->hlid, key->tx_seq_32,
2052 key->tx_seq_16);
2053 if (ret < 0)
2054 goto out;
2055
2056 if (key->key_type == KEY_WEP)
2057 wep_key_added = true;
2058 }
2059
2060 if (wep_key_added) {
2061 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2062 if (ret < 0)
2063 goto out;
2064 }
2065
2066out:
2067 wl1271_free_ap_keys(wl);
2068 return ret;
2069}
2070
2071static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2072 u8 key_size, const u8 *key, u32 tx_seq_32,
2073 u16 tx_seq_16, struct ieee80211_sta *sta)
2074{
2075 int ret;
2076 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2077
2078 if (is_ap) {
2079 struct wl1271_station *wl_sta;
2080 u8 hlid;
2081
2082 if (sta) {
2083 wl_sta = (struct wl1271_station *)sta->drv_priv;
2084 hlid = wl_sta->hlid;
2085 } else {
2086 hlid = WL1271_AP_BROADCAST_HLID;
2087 }
2088
2089 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2090 /*
2091 * We do not support removing keys after AP shutdown.
2092 * Pretend we do to make mac80211 happy.
2093 */
2094 if (action != KEY_ADD_OR_REPLACE)
2095 return 0;
2096
2097 ret = wl1271_record_ap_key(wl, id,
2098 key_type, key_size,
2099 key, hlid, tx_seq_32,
2100 tx_seq_16);
2101 } else {
2102 ret = wl1271_cmd_set_ap_key(wl, action,
2103 id, key_type, key_size,
2104 key, hlid, tx_seq_32,
2105 tx_seq_16);
2106 }
2107
2108 if (ret < 0)
2109 return ret;
2110 } else {
2111 const u8 *addr;
2112 static const u8 bcast_addr[ETH_ALEN] = {
2113 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2114 };
2115
2116 addr = sta ? sta->addr : bcast_addr;
2117
2118 if (is_zero_ether_addr(addr)) {
2119 /* We dont support TX only encryption */
2120 return -EOPNOTSUPP;
2121 }
2122
2123 /* The wl1271 does not allow to remove unicast keys - they
2124 will be cleared automatically on next CMD_JOIN. Ignore the
2125 request silently, as we dont want the mac80211 to emit
2126 an error message. */
2127 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2128 return 0;
2129
2130 ret = wl1271_cmd_set_sta_key(wl, action,
2131 id, key_type, key_size,
2132 key, addr, tx_seq_32,
2133 tx_seq_16);
2134 if (ret < 0)
2135 return ret;
2136
2137 /* the default WEP key needs to be configured at least once */
2138 if (key_type == KEY_WEP) {
2139 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2140 wl->default_key);
2141 if (ret < 0)
2142 return ret;
2143 }
2144 }
2145
2146 return 0;
2147}
2148
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2150 struct ieee80211_vif *vif,
2151 struct ieee80211_sta *sta,
2152 struct ieee80211_key_conf *key_conf)
2153{
2154 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002156 u32 tx_seq_32 = 0;
2157 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158 u8 key_type;
2159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2161
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002162 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002164 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 key_conf->keylen, key_conf->flags);
2166 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2167
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168 mutex_lock(&wl->mutex);
2169
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002170 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2171 ret = -EAGAIN;
2172 goto out_unlock;
2173 }
2174
Ido Yariva6208652011-03-01 15:14:41 +02002175 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176 if (ret < 0)
2177 goto out_unlock;
2178
Johannes Berg97359d12010-08-10 09:46:38 +02002179 switch (key_conf->cipher) {
2180 case WLAN_CIPHER_SUITE_WEP40:
2181 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182 key_type = KEY_WEP;
2183
2184 key_conf->hw_key_idx = key_conf->keyidx;
2185 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002186 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002187 key_type = KEY_TKIP;
2188
2189 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002190 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2191 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002193 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194 key_type = KEY_AES;
2195
2196 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002197 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2198 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002200 case WL1271_CIPHER_SUITE_GEM:
2201 key_type = KEY_GEM;
2202 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2203 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2204 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002206 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002207
2208 ret = -EOPNOTSUPP;
2209 goto out_sleep;
2210 }
2211
2212 switch (cmd) {
2213 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002214 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2215 key_conf->keyidx, key_type,
2216 key_conf->keylen, key_conf->key,
2217 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218 if (ret < 0) {
2219 wl1271_error("Could not add or replace key");
2220 goto out_sleep;
2221 }
2222 break;
2223
2224 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002225 ret = wl1271_set_key(wl, KEY_REMOVE,
2226 key_conf->keyidx, key_type,
2227 key_conf->keylen, key_conf->key,
2228 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002229 if (ret < 0) {
2230 wl1271_error("Could not remove key");
2231 goto out_sleep;
2232 }
2233 break;
2234
2235 default:
2236 wl1271_error("Unsupported key cmd 0x%x", cmd);
2237 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002238 break;
2239 }
2240
2241out_sleep:
2242 wl1271_ps_elp_sleep(wl);
2243
2244out_unlock:
2245 mutex_unlock(&wl->mutex);
2246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247 return ret;
2248}
2249
2250static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002251 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002252 struct cfg80211_scan_request *req)
2253{
2254 struct wl1271 *wl = hw->priv;
2255 int ret;
2256 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002257 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258
2259 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2260
2261 if (req->n_ssids) {
2262 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002263 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002264 }
2265
2266 mutex_lock(&wl->mutex);
2267
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002268 if (wl->state == WL1271_STATE_OFF) {
2269 /*
2270 * We cannot return -EBUSY here because cfg80211 will expect
2271 * a call to ieee80211_scan_completed if we do - in this case
2272 * there won't be any call.
2273 */
2274 ret = -EAGAIN;
2275 goto out;
2276 }
2277
Ido Yariva6208652011-03-01 15:14:41 +02002278 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279 if (ret < 0)
2280 goto out;
2281
Luciano Coelho5924f892010-08-04 03:46:22 +03002282 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283
2284 wl1271_ps_elp_sleep(wl);
2285
2286out:
2287 mutex_unlock(&wl->mutex);
2288
2289 return ret;
2290}
2291
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002292static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2293{
2294 struct wl1271 *wl = hw->priv;
2295 int ret = 0;
2296
2297 mutex_lock(&wl->mutex);
2298
2299 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2300 ret = -EAGAIN;
2301 goto out;
2302 }
2303
Ido Yariva6208652011-03-01 15:14:41 +02002304 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002305 if (ret < 0)
2306 goto out;
2307
2308 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2309 if (ret < 0)
2310 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2311
2312 wl1271_ps_elp_sleep(wl);
2313
2314out:
2315 mutex_unlock(&wl->mutex);
2316
2317 return ret;
2318}
2319
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2321{
2322 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002323 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324
2325 mutex_lock(&wl->mutex);
2326
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002327 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2328 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002329 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002330 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002331
Ido Yariva6208652011-03-01 15:14:41 +02002332 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333 if (ret < 0)
2334 goto out;
2335
2336 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2337 if (ret < 0)
2338 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2339
2340 wl1271_ps_elp_sleep(wl);
2341
2342out:
2343 mutex_unlock(&wl->mutex);
2344
2345 return ret;
2346}
2347
Arik Nemtsove78a2872010-10-16 19:07:21 +02002348static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002349 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002350{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002351 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002352
2353 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002354 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002355 if (ptr[0] == WLAN_EID_SSID) {
2356 wl->ssid_len = ptr[1];
2357 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002358 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002359 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002360 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002361 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002362
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002363 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002364 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002365}
2366
Arik Nemtsove78a2872010-10-16 19:07:21 +02002367static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2368 struct ieee80211_bss_conf *bss_conf,
2369 u32 changed)
2370{
2371 int ret = 0;
2372
2373 if (changed & BSS_CHANGED_ERP_SLOT) {
2374 if (bss_conf->use_short_slot)
2375 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2376 else
2377 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2378 if (ret < 0) {
2379 wl1271_warning("Set slot time failed %d", ret);
2380 goto out;
2381 }
2382 }
2383
2384 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2385 if (bss_conf->use_short_preamble)
2386 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2387 else
2388 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2389 }
2390
2391 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2392 if (bss_conf->use_cts_prot)
2393 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2394 else
2395 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2396 if (ret < 0) {
2397 wl1271_warning("Set ctsprotect failed %d", ret);
2398 goto out;
2399 }
2400 }
2401
2402out:
2403 return ret;
2404}
2405
2406static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2407 struct ieee80211_vif *vif,
2408 struct ieee80211_bss_conf *bss_conf,
2409 u32 changed)
2410{
2411 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2412 int ret = 0;
2413
2414 if ((changed & BSS_CHANGED_BEACON_INT)) {
2415 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2416 bss_conf->beacon_int);
2417
2418 wl->beacon_int = bss_conf->beacon_int;
2419 }
2420
2421 if ((changed & BSS_CHANGED_BEACON)) {
2422 struct ieee80211_hdr *hdr;
2423 int ieoffset = offsetof(struct ieee80211_mgmt,
2424 u.beacon.variable);
2425 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2426 u16 tmpl_id;
2427
2428 if (!beacon)
2429 goto out;
2430
2431 wl1271_debug(DEBUG_MASTER, "beacon updated");
2432
2433 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2434 if (ret < 0) {
2435 dev_kfree_skb(beacon);
2436 goto out;
2437 }
2438 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2439 CMD_TEMPL_BEACON;
2440 ret = wl1271_cmd_template_set(wl, tmpl_id,
2441 beacon->data,
2442 beacon->len, 0,
2443 wl1271_tx_min_rate_get(wl));
2444 if (ret < 0) {
2445 dev_kfree_skb(beacon);
2446 goto out;
2447 }
2448
2449 hdr = (struct ieee80211_hdr *) beacon->data;
2450 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2451 IEEE80211_STYPE_PROBE_RESP);
2452
2453 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2454 CMD_TEMPL_PROBE_RESPONSE;
2455 ret = wl1271_cmd_template_set(wl,
2456 tmpl_id,
2457 beacon->data,
2458 beacon->len, 0,
2459 wl1271_tx_min_rate_get(wl));
2460 dev_kfree_skb(beacon);
2461 if (ret < 0)
2462 goto out;
2463 }
2464
2465out:
2466 return ret;
2467}
2468
2469/* AP mode changes */
2470static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471 struct ieee80211_vif *vif,
2472 struct ieee80211_bss_conf *bss_conf,
2473 u32 changed)
2474{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002475 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002476
Arik Nemtsove78a2872010-10-16 19:07:21 +02002477 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2478 u32 rates = bss_conf->basic_rates;
2479 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480
Arik Nemtsove78a2872010-10-16 19:07:21 +02002481 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2482 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2483 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2484 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485
Arik Nemtsove78a2872010-10-16 19:07:21 +02002486 /* update the AP management rate policy with the new rates */
2487 mgmt_rc.enabled_rates = wl->basic_rate_set;
2488 mgmt_rc.long_retry_limit = 10;
2489 mgmt_rc.short_retry_limit = 10;
2490 mgmt_rc.aflags = 0;
2491 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2492 ACX_TX_AP_MODE_MGMT_RATE);
2493 if (ret < 0) {
2494 wl1271_error("AP mgmt policy change failed %d", ret);
2495 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002496 }
2497 }
2498
Arik Nemtsove78a2872010-10-16 19:07:21 +02002499 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2500 if (ret < 0)
2501 goto out;
2502
2503 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2504 if (bss_conf->enable_beacon) {
2505 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2506 ret = wl1271_cmd_start_bss(wl);
2507 if (ret < 0)
2508 goto out;
2509
2510 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2511 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002512
2513 ret = wl1271_ap_init_hwenc(wl);
2514 if (ret < 0)
2515 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002516 }
2517 } else {
2518 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2519 ret = wl1271_cmd_stop_bss(wl);
2520 if (ret < 0)
2521 goto out;
2522
2523 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2524 wl1271_debug(DEBUG_AP, "stopped AP");
2525 }
2526 }
2527 }
2528
Eliad Pellercb5ae052011-04-07 15:52:05 +03002529 if (changed & BSS_CHANGED_IBSS) {
2530 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2531 bss_conf->ibss_joined);
2532
2533 if (bss_conf->ibss_joined) {
2534 u32 rates = bss_conf->basic_rates;
2535 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2536 rates);
2537 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2538
2539 /* by default, use 11b rates */
2540 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2541 ret = wl1271_acx_sta_rate_policies(wl);
2542 if (ret < 0)
2543 goto out;
2544 }
2545 }
2546
Arik Nemtsove78a2872010-10-16 19:07:21 +02002547 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2548 if (ret < 0)
2549 goto out;
2550out:
2551 return;
2552}
2553
2554/* STA/IBSS mode changes */
2555static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2556 struct ieee80211_vif *vif,
2557 struct ieee80211_bss_conf *bss_conf,
2558 u32 changed)
2559{
2560 bool do_join = false, set_assoc = false;
2561 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002562 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002563 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002564 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002565 bool sta_exists = false;
2566 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002567
2568 if (is_ibss) {
2569 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2570 changed);
2571 if (ret < 0)
2572 goto out;
2573 }
2574
2575 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2576 do_join = true;
2577
2578 /* Need to update the SSID (for filtering etc) */
2579 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2580 do_join = true;
2581
2582 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002583 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2584 bss_conf->enable_beacon ? "enabled" : "disabled");
2585
2586 if (bss_conf->enable_beacon)
2587 wl->set_bss_type = BSS_TYPE_IBSS;
2588 else
2589 wl->set_bss_type = BSS_TYPE_STA_BSS;
2590 do_join = true;
2591 }
2592
Arik Nemtsove78a2872010-10-16 19:07:21 +02002593 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002594 bool enable = false;
2595 if (bss_conf->cqm_rssi_thold)
2596 enable = true;
2597 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2598 bss_conf->cqm_rssi_thold,
2599 bss_conf->cqm_rssi_hyst);
2600 if (ret < 0)
2601 goto out;
2602 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2603 }
2604
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002605 if ((changed & BSS_CHANGED_BSSID) &&
2606 /*
2607 * Now we know the correct bssid, so we send a new join command
2608 * and enable the BSSID filter
2609 */
2610 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002611 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002612
Eliad Pellerfa287b82010-12-26 09:27:50 +01002613 if (!is_zero_ether_addr(wl->bssid)) {
2614 ret = wl1271_cmd_build_null_data(wl);
2615 if (ret < 0)
2616 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002617
Eliad Pellerfa287b82010-12-26 09:27:50 +01002618 ret = wl1271_build_qos_null_data(wl);
2619 if (ret < 0)
2620 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002621
Eliad Pellerfa287b82010-12-26 09:27:50 +01002622 /* filter out all packets not from this BSSID */
2623 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002624
Eliad Pellerfa287b82010-12-26 09:27:50 +01002625 /* Need to update the BSSID (for filtering etc) */
2626 do_join = true;
2627 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002628 }
2629
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002630 rcu_read_lock();
2631 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2632 if (sta) {
2633 /* save the supp_rates of the ap */
2634 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2635 if (sta->ht_cap.ht_supported)
2636 sta_rate_set |=
2637 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002638 sta_ht_cap = sta->ht_cap;
2639 sta_exists = true;
2640 }
2641 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002642
Arik Nemtsova1008852011-02-12 23:24:20 +02002643 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002644 /* handle new association with HT and HT information change */
2645 if ((changed & BSS_CHANGED_HT) &&
2646 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
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 true);
2649 if (ret < 0) {
2650 wl1271_warning("Set ht cap true failed %d",
2651 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002652 goto out;
2653 }
2654 ret = wl1271_acx_set_ht_information(wl,
2655 bss_conf->ht_operation_mode);
2656 if (ret < 0) {
2657 wl1271_warning("Set ht information failed %d",
2658 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002659 goto out;
2660 }
2661 }
2662 /* handle new association without HT and disassociation */
2663 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002664 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002665 false);
2666 if (ret < 0) {
2667 wl1271_warning("Set ht cap false failed %d",
2668 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002669 goto out;
2670 }
2671 }
2672 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002673
Arik Nemtsove78a2872010-10-16 19:07:21 +02002674 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002676 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002677 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002679 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002680
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002681 wl->ps_poll_failures = 0;
2682
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002683 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002684 * use basic rates from AP, and determine lowest rate
2685 * to use with control frames.
2686 */
2687 rates = bss_conf->basic_rates;
2688 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2689 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002690 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002691 if (sta_rate_set)
2692 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2693 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002694 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002695 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002696 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002697
2698 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002699 * with wl1271, we don't need to update the
2700 * beacon_int and dtim_period, because the firmware
2701 * updates it by itself when the first beacon is
2702 * received after a join.
2703 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2705 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002706 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002707
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002708 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002709 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002710 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002711 dev_kfree_skb(wl->probereq);
2712 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2713 ieoffset = offsetof(struct ieee80211_mgmt,
2714 u.probe_req.variable);
2715 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002716
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002717 /* enable the connection monitoring feature */
2718 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002720 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721
2722 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002723 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2724 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002725 enum wl1271_cmd_ps_mode mode;
2726
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002727 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002728 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002729 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002730 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002732 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002734 } else {
2735 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002736 bool was_assoc =
2737 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2738 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002739 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002740 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002741
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002742 /* free probe-request template */
2743 dev_kfree_skb(wl->probereq);
2744 wl->probereq = NULL;
2745
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002746 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002747 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002748
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002749 /* revert back to minimum rates for the current band */
2750 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002751 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002752 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002753 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002754 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002755
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002756 /* disable connection monitor features */
2757 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002758
2759 /* Disable the keep-alive feature */
2760 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002761 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002762 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002763
2764 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002765 if (was_assoc) {
2766 wl1271_unjoin(wl);
2767 wl1271_dummy_join(wl);
2768 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002769 }
2770 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002771
Arik Nemtsove78a2872010-10-16 19:07:21 +02002772 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2773 if (ret < 0)
2774 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002775
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002776 if (changed & BSS_CHANGED_ARP_FILTER) {
2777 __be32 addr = bss_conf->arp_addr_list[0];
2778 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2779
Eliad Pellerc5312772010-12-09 11:31:27 +02002780 if (bss_conf->arp_addr_cnt == 1 &&
2781 bss_conf->arp_filter_enabled) {
2782 /*
2783 * The template should have been configured only upon
2784 * association. however, it seems that the correct ip
2785 * isn't being set (when sending), so we have to
2786 * reconfigure the template upon every ip change.
2787 */
2788 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2789 if (ret < 0) {
2790 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002791 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002792 }
2793
2794 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002795 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002796 addr);
2797 } else
2798 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002799
2800 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002801 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002802 }
2803
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002804 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002805 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002806 if (ret < 0) {
2807 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002808 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002809 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002810 }
2811
Arik Nemtsove78a2872010-10-16 19:07:21 +02002812out:
2813 return;
2814}
2815
2816static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2817 struct ieee80211_vif *vif,
2818 struct ieee80211_bss_conf *bss_conf,
2819 u32 changed)
2820{
2821 struct wl1271 *wl = hw->priv;
2822 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2823 int ret;
2824
2825 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2826 (int)changed);
2827
2828 mutex_lock(&wl->mutex);
2829
2830 if (unlikely(wl->state == WL1271_STATE_OFF))
2831 goto out;
2832
Ido Yariva6208652011-03-01 15:14:41 +02002833 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002834 if (ret < 0)
2835 goto out;
2836
2837 if (is_ap)
2838 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2839 else
2840 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002842 wl1271_ps_elp_sleep(wl);
2843
2844out:
2845 mutex_unlock(&wl->mutex);
2846}
2847
Kalle Valoc6999d82010-02-18 13:25:41 +02002848static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2849 const struct ieee80211_tx_queue_params *params)
2850{
2851 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002852 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002853 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002854
2855 mutex_lock(&wl->mutex);
2856
2857 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2858
Kalle Valo4695dc92010-03-18 12:26:38 +02002859 if (params->uapsd)
2860 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2861 else
2862 ps_scheme = CONF_PS_SCHEME_LEGACY;
2863
Arik Nemtsov488fc542010-10-16 20:33:45 +02002864 if (wl->state == WL1271_STATE_OFF) {
2865 /*
2866 * If the state is off, the parameters will be recorded and
2867 * configured on init. This happens in AP-mode.
2868 */
2869 struct conf_tx_ac_category *conf_ac =
2870 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2871 struct conf_tx_tid *conf_tid =
2872 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2873
2874 conf_ac->ac = wl1271_tx_get_queue(queue);
2875 conf_ac->cw_min = (u8)params->cw_min;
2876 conf_ac->cw_max = params->cw_max;
2877 conf_ac->aifsn = params->aifs;
2878 conf_ac->tx_op_limit = params->txop << 5;
2879
2880 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2881 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2882 conf_tid->tsid = wl1271_tx_get_queue(queue);
2883 conf_tid->ps_scheme = ps_scheme;
2884 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2885 conf_tid->apsd_conf[0] = 0;
2886 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002887 goto out;
2888 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002889
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002890 ret = wl1271_ps_elp_wakeup(wl);
2891 if (ret < 0)
2892 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002893
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002894 /*
2895 * the txop is confed in units of 32us by the mac80211,
2896 * we need us
2897 */
2898 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2899 params->cw_min, params->cw_max,
2900 params->aifs, params->txop << 5);
2901 if (ret < 0)
2902 goto out_sleep;
2903
2904 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2905 CONF_CHANNEL_TYPE_EDCF,
2906 wl1271_tx_get_queue(queue),
2907 ps_scheme, CONF_ACK_POLICY_LEGACY,
2908 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002909
2910out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002911 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002912
2913out:
2914 mutex_unlock(&wl->mutex);
2915
2916 return ret;
2917}
2918
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002919static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2920{
2921
2922 struct wl1271 *wl = hw->priv;
2923 u64 mactime = ULLONG_MAX;
2924 int ret;
2925
2926 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2927
2928 mutex_lock(&wl->mutex);
2929
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002930 if (unlikely(wl->state == WL1271_STATE_OFF))
2931 goto out;
2932
Ido Yariva6208652011-03-01 15:14:41 +02002933 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002934 if (ret < 0)
2935 goto out;
2936
2937 ret = wl1271_acx_tsf_info(wl, &mactime);
2938 if (ret < 0)
2939 goto out_sleep;
2940
2941out_sleep:
2942 wl1271_ps_elp_sleep(wl);
2943
2944out:
2945 mutex_unlock(&wl->mutex);
2946 return mactime;
2947}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948
John W. Linvilleece550d2010-07-28 16:41:06 -04002949static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2950 struct survey_info *survey)
2951{
2952 struct wl1271 *wl = hw->priv;
2953 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002954
John W. Linvilleece550d2010-07-28 16:41:06 -04002955 if (idx != 0)
2956 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002957
John W. Linvilleece550d2010-07-28 16:41:06 -04002958 survey->channel = conf->channel;
2959 survey->filled = SURVEY_INFO_NOISE_DBM;
2960 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002961
John W. Linvilleece550d2010-07-28 16:41:06 -04002962 return 0;
2963}
2964
Arik Nemtsov409622e2011-02-23 00:22:29 +02002965static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002966 struct ieee80211_sta *sta,
2967 u8 *hlid)
2968{
2969 struct wl1271_station *wl_sta;
2970 int id;
2971
2972 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2973 if (id >= AP_MAX_STATIONS) {
2974 wl1271_warning("could not allocate HLID - too much stations");
2975 return -EBUSY;
2976 }
2977
2978 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002979 __set_bit(id, wl->ap_hlid_map);
2980 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2981 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002982 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002983 return 0;
2984}
2985
Arik Nemtsov409622e2011-02-23 00:22:29 +02002986static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002987{
2988 int id = hlid - WL1271_AP_STA_HLID_START;
2989
Arik Nemtsov409622e2011-02-23 00:22:29 +02002990 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2991 return;
2992
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002993 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002994 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002995 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002996 __clear_bit(hlid, &wl->ap_ps_map);
2997 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002998}
2999
Arik Nemtsov47684802011-04-26 23:21:51 +03003000bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3001{
3002 int id = hlid - WL1271_AP_STA_HLID_START;
3003 return test_bit(id, wl->ap_hlid_map);
3004}
3005
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003006static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3007 struct ieee80211_vif *vif,
3008 struct ieee80211_sta *sta)
3009{
3010 struct wl1271 *wl = hw->priv;
3011 int ret = 0;
3012 u8 hlid;
3013
3014 mutex_lock(&wl->mutex);
3015
3016 if (unlikely(wl->state == WL1271_STATE_OFF))
3017 goto out;
3018
3019 if (wl->bss_type != BSS_TYPE_AP_BSS)
3020 goto out;
3021
3022 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3023
Arik Nemtsov409622e2011-02-23 00:22:29 +02003024 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003025 if (ret < 0)
3026 goto out;
3027
Ido Yariva6208652011-03-01 15:14:41 +02003028 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003029 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003030 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003031
3032 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3033 if (ret < 0)
3034 goto out_sleep;
3035
3036out_sleep:
3037 wl1271_ps_elp_sleep(wl);
3038
Arik Nemtsov409622e2011-02-23 00:22:29 +02003039out_free_sta:
3040 if (ret < 0)
3041 wl1271_free_sta(wl, hlid);
3042
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003043out:
3044 mutex_unlock(&wl->mutex);
3045 return ret;
3046}
3047
3048static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3049 struct ieee80211_vif *vif,
3050 struct ieee80211_sta *sta)
3051{
3052 struct wl1271 *wl = hw->priv;
3053 struct wl1271_station *wl_sta;
3054 int ret = 0, id;
3055
3056 mutex_lock(&wl->mutex);
3057
3058 if (unlikely(wl->state == WL1271_STATE_OFF))
3059 goto out;
3060
3061 if (wl->bss_type != BSS_TYPE_AP_BSS)
3062 goto out;
3063
3064 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3065
3066 wl_sta = (struct wl1271_station *)sta->drv_priv;
3067 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3068 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3069 goto out;
3070
Ido Yariva6208652011-03-01 15:14:41 +02003071 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003072 if (ret < 0)
3073 goto out;
3074
3075 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3076 if (ret < 0)
3077 goto out_sleep;
3078
Arik Nemtsov409622e2011-02-23 00:22:29 +02003079 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003080
3081out_sleep:
3082 wl1271_ps_elp_sleep(wl);
3083
3084out:
3085 mutex_unlock(&wl->mutex);
3086 return ret;
3087}
3088
Luciano Coelho4623ec72011-03-21 19:26:41 +02003089static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3090 struct ieee80211_vif *vif,
3091 enum ieee80211_ampdu_mlme_action action,
3092 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3093 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003094{
3095 struct wl1271 *wl = hw->priv;
3096 int ret;
3097
3098 mutex_lock(&wl->mutex);
3099
3100 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3101 ret = -EAGAIN;
3102 goto out;
3103 }
3104
Ido Yariva6208652011-03-01 15:14:41 +02003105 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003106 if (ret < 0)
3107 goto out;
3108
3109 switch (action) {
3110 case IEEE80211_AMPDU_RX_START:
3111 if (wl->ba_support) {
3112 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3113 true);
3114 if (!ret)
3115 wl->ba_rx_bitmap |= BIT(tid);
3116 } else {
3117 ret = -ENOTSUPP;
3118 }
3119 break;
3120
3121 case IEEE80211_AMPDU_RX_STOP:
3122 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3123 if (!ret)
3124 wl->ba_rx_bitmap &= ~BIT(tid);
3125 break;
3126
3127 /*
3128 * The BA initiator session management in FW independently.
3129 * Falling break here on purpose for all TX APDU commands.
3130 */
3131 case IEEE80211_AMPDU_TX_START:
3132 case IEEE80211_AMPDU_TX_STOP:
3133 case IEEE80211_AMPDU_TX_OPERATIONAL:
3134 ret = -EINVAL;
3135 break;
3136
3137 default:
3138 wl1271_error("Incorrect ampdu action id=%x\n", action);
3139 ret = -EINVAL;
3140 }
3141
3142 wl1271_ps_elp_sleep(wl);
3143
3144out:
3145 mutex_unlock(&wl->mutex);
3146
3147 return ret;
3148}
3149
Arik Nemtsov33437892011-04-26 23:35:39 +03003150static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3151{
3152 struct wl1271 *wl = hw->priv;
3153 bool ret = false;
3154
3155 mutex_lock(&wl->mutex);
3156
3157 if (unlikely(wl->state == WL1271_STATE_OFF))
3158 goto out;
3159
3160 /* packets are considered pending if in the TX queue or the FW */
3161 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3162
3163 /* the above is appropriate for STA mode for PS purposes */
3164 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3165
3166out:
3167 mutex_unlock(&wl->mutex);
3168
3169 return ret;
3170}
3171
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003172/* can't be const, mac80211 writes to this */
3173static struct ieee80211_rate wl1271_rates[] = {
3174 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003175 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3176 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003178 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3179 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003180 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3181 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003182 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3183 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003184 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3185 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003186 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3187 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003188 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3189 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003190 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3191 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003192 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003193 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3194 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003195 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003196 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3197 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003198 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003199 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3200 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003201 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003202 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3203 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003204 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003205 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3206 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003207 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003208 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3209 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003210 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003211 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3212 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213};
3214
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003215/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003217 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003218 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003219 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3220 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3221 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003222 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003223 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3224 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3225 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003226 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003227 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3228 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3229 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003230 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231};
3232
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003233/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003234static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003235 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003236 7, /* CONF_HW_RXTX_RATE_MCS7 */
3237 6, /* CONF_HW_RXTX_RATE_MCS6 */
3238 5, /* CONF_HW_RXTX_RATE_MCS5 */
3239 4, /* CONF_HW_RXTX_RATE_MCS4 */
3240 3, /* CONF_HW_RXTX_RATE_MCS3 */
3241 2, /* CONF_HW_RXTX_RATE_MCS2 */
3242 1, /* CONF_HW_RXTX_RATE_MCS1 */
3243 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003244
3245 11, /* CONF_HW_RXTX_RATE_54 */
3246 10, /* CONF_HW_RXTX_RATE_48 */
3247 9, /* CONF_HW_RXTX_RATE_36 */
3248 8, /* CONF_HW_RXTX_RATE_24 */
3249
3250 /* TI-specific rate */
3251 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3252
3253 7, /* CONF_HW_RXTX_RATE_18 */
3254 6, /* CONF_HW_RXTX_RATE_12 */
3255 3, /* CONF_HW_RXTX_RATE_11 */
3256 5, /* CONF_HW_RXTX_RATE_9 */
3257 4, /* CONF_HW_RXTX_RATE_6 */
3258 2, /* CONF_HW_RXTX_RATE_5_5 */
3259 1, /* CONF_HW_RXTX_RATE_2 */
3260 0 /* CONF_HW_RXTX_RATE_1 */
3261};
3262
Shahar Levie8b03a22010-10-13 16:09:39 +02003263/* 11n STA capabilities */
3264#define HW_RX_HIGHEST_RATE 72
3265
Shahar Levi00d20102010-11-08 11:20:10 +00003266#ifdef CONFIG_WL12XX_HT
3267#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003268 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3269 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003270 .ht_supported = true, \
3271 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3272 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3273 .mcs = { \
3274 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3275 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3276 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3277 }, \
3278}
Shahar Levi18357852010-10-13 16:09:41 +02003279#else
Shahar Levi00d20102010-11-08 11:20:10 +00003280#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003281 .ht_supported = false, \
3282}
3283#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003285/* can't be const, mac80211 writes to this */
3286static struct ieee80211_supported_band wl1271_band_2ghz = {
3287 .channels = wl1271_channels,
3288 .n_channels = ARRAY_SIZE(wl1271_channels),
3289 .bitrates = wl1271_rates,
3290 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003291 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003292};
3293
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003294/* 5 GHz data rates for WL1273 */
3295static struct ieee80211_rate wl1271_rates_5ghz[] = {
3296 { .bitrate = 60,
3297 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3298 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3299 { .bitrate = 90,
3300 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3301 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3302 { .bitrate = 120,
3303 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3304 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3305 { .bitrate = 180,
3306 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3307 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3308 { .bitrate = 240,
3309 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3310 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3311 { .bitrate = 360,
3312 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3313 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3314 { .bitrate = 480,
3315 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3316 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3317 { .bitrate = 540,
3318 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3319 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3320};
3321
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003322/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003323static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003324 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003325 { .hw_value = 8, .center_freq = 5040},
3326 { .hw_value = 9, .center_freq = 5045},
3327 { .hw_value = 11, .center_freq = 5055},
3328 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003329 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003330 { .hw_value = 34, .center_freq = 5170},
3331 { .hw_value = 36, .center_freq = 5180},
3332 { .hw_value = 38, .center_freq = 5190},
3333 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003334 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003335 { .hw_value = 44, .center_freq = 5220},
3336 { .hw_value = 46, .center_freq = 5230},
3337 { .hw_value = 48, .center_freq = 5240},
3338 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003339 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003340 { .hw_value = 60, .center_freq = 5300},
3341 { .hw_value = 64, .center_freq = 5320},
3342 { .hw_value = 100, .center_freq = 5500},
3343 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003344 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003345 { .hw_value = 112, .center_freq = 5560},
3346 { .hw_value = 116, .center_freq = 5580},
3347 { .hw_value = 120, .center_freq = 5600},
3348 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003349 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003350 { .hw_value = 132, .center_freq = 5660},
3351 { .hw_value = 136, .center_freq = 5680},
3352 { .hw_value = 140, .center_freq = 5700},
3353 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003354 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003355 { .hw_value = 157, .center_freq = 5785},
3356 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003357 { .hw_value = 165, .center_freq = 5825},
3358};
3359
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003360/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003361static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003362 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003363 7, /* CONF_HW_RXTX_RATE_MCS7 */
3364 6, /* CONF_HW_RXTX_RATE_MCS6 */
3365 5, /* CONF_HW_RXTX_RATE_MCS5 */
3366 4, /* CONF_HW_RXTX_RATE_MCS4 */
3367 3, /* CONF_HW_RXTX_RATE_MCS3 */
3368 2, /* CONF_HW_RXTX_RATE_MCS2 */
3369 1, /* CONF_HW_RXTX_RATE_MCS1 */
3370 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003371
3372 7, /* CONF_HW_RXTX_RATE_54 */
3373 6, /* CONF_HW_RXTX_RATE_48 */
3374 5, /* CONF_HW_RXTX_RATE_36 */
3375 4, /* CONF_HW_RXTX_RATE_24 */
3376
3377 /* TI-specific rate */
3378 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3379
3380 3, /* CONF_HW_RXTX_RATE_18 */
3381 2, /* CONF_HW_RXTX_RATE_12 */
3382 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3383 1, /* CONF_HW_RXTX_RATE_9 */
3384 0, /* CONF_HW_RXTX_RATE_6 */
3385 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3386 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3387 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3388};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003389
3390static struct ieee80211_supported_band wl1271_band_5ghz = {
3391 .channels = wl1271_channels_5ghz,
3392 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3393 .bitrates = wl1271_rates_5ghz,
3394 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003395 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003396};
3397
Tobias Klausera0ea9492010-05-20 10:38:11 +02003398static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003399 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3400 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3401};
3402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003403static const struct ieee80211_ops wl1271_ops = {
3404 .start = wl1271_op_start,
3405 .stop = wl1271_op_stop,
3406 .add_interface = wl1271_op_add_interface,
3407 .remove_interface = wl1271_op_remove_interface,
3408 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003409 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003410 .configure_filter = wl1271_op_configure_filter,
3411 .tx = wl1271_op_tx,
3412 .set_key = wl1271_op_set_key,
3413 .hw_scan = wl1271_op_hw_scan,
3414 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003415 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003416 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003417 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003418 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003419 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003420 .sta_add = wl1271_op_sta_add,
3421 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003422 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003423 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003424 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003425};
3426
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003427
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003428u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003429{
3430 u8 idx;
3431
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003432 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003433
3434 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3435 wl1271_error("Illegal RX rate from HW: %d", rate);
3436 return 0;
3437 }
3438
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003439 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003440 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3441 wl1271_error("Unsupported RX rate from HW: %d", rate);
3442 return 0;
3443 }
3444
3445 return idx;
3446}
3447
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003448static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3449 struct device_attribute *attr,
3450 char *buf)
3451{
3452 struct wl1271 *wl = dev_get_drvdata(dev);
3453 ssize_t len;
3454
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003455 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003456
3457 mutex_lock(&wl->mutex);
3458 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3459 wl->sg_enabled);
3460 mutex_unlock(&wl->mutex);
3461
3462 return len;
3463
3464}
3465
3466static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3467 struct device_attribute *attr,
3468 const char *buf, size_t count)
3469{
3470 struct wl1271 *wl = dev_get_drvdata(dev);
3471 unsigned long res;
3472 int ret;
3473
Luciano Coelho6277ed62011-04-01 17:49:54 +03003474 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003475 if (ret < 0) {
3476 wl1271_warning("incorrect value written to bt_coex_mode");
3477 return count;
3478 }
3479
3480 mutex_lock(&wl->mutex);
3481
3482 res = !!res;
3483
3484 if (res == wl->sg_enabled)
3485 goto out;
3486
3487 wl->sg_enabled = res;
3488
3489 if (wl->state == WL1271_STATE_OFF)
3490 goto out;
3491
Ido Yariva6208652011-03-01 15:14:41 +02003492 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003493 if (ret < 0)
3494 goto out;
3495
3496 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3497 wl1271_ps_elp_sleep(wl);
3498
3499 out:
3500 mutex_unlock(&wl->mutex);
3501 return count;
3502}
3503
3504static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3505 wl1271_sysfs_show_bt_coex_state,
3506 wl1271_sysfs_store_bt_coex_state);
3507
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003508static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3509 struct device_attribute *attr,
3510 char *buf)
3511{
3512 struct wl1271 *wl = dev_get_drvdata(dev);
3513 ssize_t len;
3514
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003515 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003516
3517 mutex_lock(&wl->mutex);
3518 if (wl->hw_pg_ver >= 0)
3519 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3520 else
3521 len = snprintf(buf, len, "n/a\n");
3522 mutex_unlock(&wl->mutex);
3523
3524 return len;
3525}
3526
3527static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3528 wl1271_sysfs_show_hw_pg_ver, NULL);
3529
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003530int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003531{
3532 int ret;
3533
3534 if (wl->mac80211_registered)
3535 return 0;
3536
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003537 ret = wl1271_fetch_nvs(wl);
3538 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003539 /* NOTE: The wl->nvs->nvs element must be first, in
3540 * order to simplify the casting, we assume it is at
3541 * the beginning of the wl->nvs structure.
3542 */
3543 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003544
3545 wl->mac_addr[0] = nvs_ptr[11];
3546 wl->mac_addr[1] = nvs_ptr[10];
3547 wl->mac_addr[2] = nvs_ptr[6];
3548 wl->mac_addr[3] = nvs_ptr[5];
3549 wl->mac_addr[4] = nvs_ptr[4];
3550 wl->mac_addr[5] = nvs_ptr[3];
3551 }
3552
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003553 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3554
3555 ret = ieee80211_register_hw(wl->hw);
3556 if (ret < 0) {
3557 wl1271_error("unable to register mac80211 hw: %d", ret);
3558 return ret;
3559 }
3560
3561 wl->mac80211_registered = true;
3562
Eliad Pellerd60080a2010-11-24 12:53:16 +02003563 wl1271_debugfs_init(wl);
3564
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003565 register_netdevice_notifier(&wl1271_dev_notifier);
3566
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003567 wl1271_notice("loaded");
3568
3569 return 0;
3570}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003571EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003572
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003573void wl1271_unregister_hw(struct wl1271 *wl)
3574{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003575 if (wl->state == WL1271_STATE_PLT)
3576 __wl1271_plt_stop(wl);
3577
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003578 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003579 ieee80211_unregister_hw(wl->hw);
3580 wl->mac80211_registered = false;
3581
3582}
3583EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3584
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003585int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003586{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003587 static const u32 cipher_suites[] = {
3588 WLAN_CIPHER_SUITE_WEP40,
3589 WLAN_CIPHER_SUITE_WEP104,
3590 WLAN_CIPHER_SUITE_TKIP,
3591 WLAN_CIPHER_SUITE_CCMP,
3592 WL1271_CIPHER_SUITE_GEM,
3593 };
3594
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003595 /* The tx descriptor buffer and the TKIP space. */
3596 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3597 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003598
3599 /* unit us */
3600 /* FIXME: find a proper value */
3601 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003602 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003603
3604 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003605 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003606 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003607 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003608 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003609 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003610 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003611 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003612
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003613 wl->hw->wiphy->cipher_suites = cipher_suites;
3614 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3615
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003616 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003617 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003618 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003619 /*
3620 * Maximum length of elements in scanning probe request templates
3621 * should be the maximum length possible for a template, without
3622 * the IEEE80211 header of the template
3623 */
3624 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3625 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003626
Luciano Coelho4a31c112011-03-21 23:16:14 +02003627 /* make sure all our channels fit in the scanned_ch bitmask */
3628 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3629 ARRAY_SIZE(wl1271_channels_5ghz) >
3630 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003631 /*
3632 * We keep local copies of the band structs because we need to
3633 * modify them on a per-device basis.
3634 */
3635 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3636 sizeof(wl1271_band_2ghz));
3637 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3638 sizeof(wl1271_band_5ghz));
3639
3640 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3641 &wl->bands[IEEE80211_BAND_2GHZ];
3642 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3643 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003644
Kalle Valo12bd8942010-03-18 12:26:33 +02003645 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003646 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003647
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003648 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3649
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003650 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003651
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003652 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3653
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003654 wl->hw->max_rx_aggregation_subframes = 8;
3655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003656 return 0;
3657}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003658EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003660#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003661
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003662struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003663{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003664 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003665 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003666 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003667 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003668 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003669
3670 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3671 if (!hw) {
3672 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003673 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003674 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003675 }
3676
Julia Lawall929ebd32010-05-15 23:16:39 +02003677 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003678 if (!plat_dev) {
3679 wl1271_error("could not allocate platform_device");
3680 ret = -ENOMEM;
3681 goto err_plat_alloc;
3682 }
3683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003684 wl = hw->priv;
3685 memset(wl, 0, sizeof(*wl));
3686
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003687 INIT_LIST_HEAD(&wl->list);
3688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003689 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003690 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003691
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003692 for (i = 0; i < NUM_TX_QUEUES; i++)
3693 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003694
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003695 for (i = 0; i < NUM_TX_QUEUES; i++)
3696 for (j = 0; j < AP_MAX_LINKS; j++)
3697 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3698
Ido Yariva6208652011-03-01 15:14:41 +02003699 skb_queue_head_init(&wl->deferred_rx_queue);
3700 skb_queue_head_init(&wl->deferred_tx_queue);
3701
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003702 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003703 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003704 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003705 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3706 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3707 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003708 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003709 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003711 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003712 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3713 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003714 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003716 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003717 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003718 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003719 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003720 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003721 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003722 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003723 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003724 wl->bss_type = MAX_BSS_TYPE;
3725 wl->set_bss_type = MAX_BSS_TYPE;
3726 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003727 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003728 wl->ap_ps_map = 0;
3729 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003730 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003731 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003732
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003733 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003734 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003735 wl->tx_frames[i] = NULL;
3736
3737 spin_lock_init(&wl->wl_lock);
3738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003739 wl->state = WL1271_STATE_OFF;
3740 mutex_init(&wl->mutex);
3741
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003742 /* Apply default driver configuration. */
3743 wl1271_conf_init(wl);
3744
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003745 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3746 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3747 if (!wl->aggr_buf) {
3748 ret = -ENOMEM;
3749 goto err_hw;
3750 }
3751
Ido Yariv990f5de2011-03-31 10:06:59 +02003752 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3753 if (!wl->dummy_packet) {
3754 ret = -ENOMEM;
3755 goto err_aggr;
3756 }
3757
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003758 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003759 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003760 if (ret) {
3761 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003762 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003763 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003764 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003765
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003766 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003767 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003768 if (ret < 0) {
3769 wl1271_error("failed to create sysfs file bt_coex_state");
3770 goto err_platform;
3771 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003772
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003773 /* Create sysfs file to get HW PG version */
3774 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3775 if (ret < 0) {
3776 wl1271_error("failed to create sysfs file hw_pg_ver");
3777 goto err_bt_coex_state;
3778 }
3779
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003780 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003781
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003782err_bt_coex_state:
3783 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3784
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003785err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003786 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003787
Ido Yariv990f5de2011-03-31 10:06:59 +02003788err_dummy_packet:
3789 dev_kfree_skb(wl->dummy_packet);
3790
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003791err_aggr:
3792 free_pages((unsigned long)wl->aggr_buf, order);
3793
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003794err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003795 wl1271_debugfs_exit(wl);
3796 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003797
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003798err_plat_alloc:
3799 ieee80211_free_hw(hw);
3800
3801err_hw_alloc:
3802
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003803 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003804}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003805EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003806
3807int wl1271_free_hw(struct wl1271 *wl)
3808{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003809 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003810 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003811 free_pages((unsigned long)wl->aggr_buf,
3812 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003813 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003814
3815 wl1271_debugfs_exit(wl);
3816
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003817 vfree(wl->fw);
3818 wl->fw = NULL;
3819 kfree(wl->nvs);
3820 wl->nvs = NULL;
3821
3822 kfree(wl->fw_status);
3823 kfree(wl->tx_res_if);
3824
3825 ieee80211_free_hw(wl->hw);
3826
3827 return 0;
3828}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003829EXPORT_SYMBOL_GPL(wl1271_free_hw);
3830
Guy Eilam491bbd62011-01-12 10:33:29 +01003831u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003832EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003833module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003834MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3835
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003836MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003837MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003838MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");