blob: 65e8a0cc92d058d73206183ae697b7f7825df404 [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>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200259 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_nullfunc_retries = 3,
261 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300262 .keep_alive_interval = 55000,
263 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200265 .itrim = {
266 .enable = false,
267 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200268 },
269 .pm_config = {
270 .host_clk_settling_time = 5000,
271 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300272 },
273 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 .trigger_pacing = 1,
275 .avg_weight_rssi_beacon = 20,
276 .avg_weight_rssi_data = 10,
277 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100278 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200279 },
280 .scan = {
281 .min_dwell_time_active = 7500,
282 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100283 .min_dwell_time_passive = 100000,
284 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200285 .num_probe_reqs = 2,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
300 },
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .mem = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 70,
305 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200306 .dynamic_memory = 0,
307 .min_req_tx_blocks = 104,
308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
310 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311};
312
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200313static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200314static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200315
316
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200317static void wl1271_device_release(struct device *dev)
318{
319
320}
321
322static struct platform_device wl1271_device = {
323 .name = "wl1271",
324 .id = -1,
325
326 /* device model insists to have a release function */
327 .dev = {
328 .release = wl1271_device_release,
329 },
330};
331
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300332static LIST_HEAD(wl_list);
333
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300334static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
335 void *arg)
336{
337 struct net_device *dev = arg;
338 struct wireless_dev *wdev;
339 struct wiphy *wiphy;
340 struct ieee80211_hw *hw;
341 struct wl1271 *wl;
342 struct wl1271 *wl_temp;
343 int ret = 0;
344
345 /* Check that this notification is for us. */
346 if (what != NETDEV_CHANGE)
347 return NOTIFY_DONE;
348
349 wdev = dev->ieee80211_ptr;
350 if (wdev == NULL)
351 return NOTIFY_DONE;
352
353 wiphy = wdev->wiphy;
354 if (wiphy == NULL)
355 return NOTIFY_DONE;
356
357 hw = wiphy_priv(wiphy);
358 if (hw == NULL)
359 return NOTIFY_DONE;
360
361 wl_temp = hw->priv;
362 list_for_each_entry(wl, &wl_list, list) {
363 if (wl == wl_temp)
364 break;
365 }
366 if (wl != wl_temp)
367 return NOTIFY_DONE;
368
369 mutex_lock(&wl->mutex);
370
371 if (wl->state == WL1271_STATE_OFF)
372 goto out;
373
374 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
375 goto out;
376
377 ret = wl1271_ps_elp_wakeup(wl, false);
378 if (ret < 0)
379 goto out;
380
381 if ((dev->operstate == IF_OPER_UP) &&
382 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
383 wl1271_cmd_set_sta_state(wl);
384 wl1271_info("Association completed.");
385 }
386
387 wl1271_ps_elp_sleep(wl);
388
389out:
390 mutex_unlock(&wl->mutex);
391
392 return NOTIFY_OK;
393}
394
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100395static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200396 struct regulatory_request *request)
397{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100398 struct ieee80211_supported_band *band;
399 struct ieee80211_channel *ch;
400 int i;
401
402 band = wiphy->bands[IEEE80211_BAND_5GHZ];
403 for (i = 0; i < band->n_channels; i++) {
404 ch = &band->channels[i];
405 if (ch->flags & IEEE80211_CHAN_DISABLED)
406 continue;
407
408 if (ch->flags & IEEE80211_CHAN_RADAR)
409 ch->flags |= IEEE80211_CHAN_NO_IBSS |
410 IEEE80211_CHAN_PASSIVE_SCAN;
411
412 }
413
414 return 0;
415}
416
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417static void wl1271_conf_init(struct wl1271 *wl)
418{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300419
420 /*
421 * This function applies the default configuration to the driver. This
422 * function is invoked upon driver load (spi probe.)
423 *
424 * The configuration is stored in a run-time structure in order to
425 * facilitate for run-time adjustment of any of the parameters. Making
426 * changes to the configuration structure will apply the new values on
427 * the next interface up (wl1271_op_start.)
428 */
429
430 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300431 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300432}
433
434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435static int wl1271_plt_init(struct wl1271 *wl)
436{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 struct conf_tx_ac_category *conf_ac;
438 struct conf_tx_tid *conf_tid;
439 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200441 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200442 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200443 return ret;
444
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200445 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200446 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200447 return ret;
448
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200449 ret = wl1271_cmd_ext_radio_parms(wl);
450 if (ret < 0)
451 return ret;
452
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200453 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200454 if (ret < 0)
455 return ret;
456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457 ret = wl1271_acx_init_mem_config(wl);
458 if (ret < 0)
459 return ret;
460
Luciano Coelho12419cc2010-02-18 13:25:44 +0200461 /* PHY layer config */
462 ret = wl1271_init_phy_config(wl);
463 if (ret < 0)
464 goto out_free_memmap;
465
466 ret = wl1271_acx_dco_itrim_params(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200471 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
475 /* Bluetooth WLAN coexistence */
476 ret = wl1271_init_pta(wl);
477 if (ret < 0)
478 goto out_free_memmap;
479
480 /* Energy detection */
481 ret = wl1271_init_energy_detection(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
Gery Kahn1ec610e2011-02-01 03:03:08 -0600485 ret = wl1271_acx_sta_mem_cfg(wl);
486 if (ret < 0)
487 goto out_free_memmap;
488
Luciano Coelho12419cc2010-02-18 13:25:44 +0200489 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100490 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200491 if (ret < 0)
492 goto out_free_memmap;
493
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200494 /* Default TID/AC configuration */
495 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200497 conf_ac = &wl->conf.tx.ac_conf[i];
498 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
499 conf_ac->cw_max, conf_ac->aifsn,
500 conf_ac->tx_op_limit);
501 if (ret < 0)
502 goto out_free_memmap;
503
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 conf_tid = &wl->conf.tx.tid_conf[i];
505 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
506 conf_tid->channel_type,
507 conf_tid->tsid,
508 conf_tid->ps_scheme,
509 conf_tid->ack_policy,
510 conf_tid->apsd_conf[0],
511 conf_tid->apsd_conf[1]);
512 if (ret < 0)
513 goto out_free_memmap;
514 }
515
Luciano Coelho12419cc2010-02-18 13:25:44 +0200516 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200517 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200519 goto out_free_memmap;
520
521 /* Configure for CAM power saving (ie. always active) */
522 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
523 if (ret < 0)
524 goto out_free_memmap;
525
526 /* configure PM */
527 ret = wl1271_acx_pm_config(wl);
528 if (ret < 0)
529 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530
531 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200532
533 out_free_memmap:
534 kfree(wl->target_mem_map);
535 wl->target_mem_map = NULL;
536
537 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538}
539
Arik Nemtsovb622d992011-02-23 00:22:31 +0200540static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
541{
542 bool fw_ps;
543
544 /* only regulate station links */
545 if (hlid < WL1271_AP_STA_HLID_START)
546 return;
547
548 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
549
550 /*
551 * Wake up from high level PS if the STA is asleep with too little
552 * blocks in FW or if the STA is awake.
553 */
554 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
555 wl1271_ps_link_end(wl, hlid);
556
557 /* Start high-level PS if the STA is asleep with enough blocks in FW */
558 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
559 wl1271_ps_link_start(wl, hlid, true);
560}
561
562static void wl1271_irq_update_links_status(struct wl1271 *wl,
563 struct wl1271_fw_ap_status *status)
564{
565 u32 cur_fw_ps_map;
566 u8 hlid;
567
568 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
569 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
570 wl1271_debug(DEBUG_PSM,
571 "link ps prev 0x%x cur 0x%x changed 0x%x",
572 wl->ap_fw_ps_map, cur_fw_ps_map,
573 wl->ap_fw_ps_map ^ cur_fw_ps_map);
574
575 wl->ap_fw_ps_map = cur_fw_ps_map;
576 }
577
578 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
579 u8 cnt = status->tx_lnk_free_blks[hlid] -
580 wl->links[hlid].prev_freed_blks;
581
582 wl->links[hlid].prev_freed_blks =
583 status->tx_lnk_free_blks[hlid];
584 wl->links[hlid].allocated_blks -= cnt;
585
586 wl1271_irq_ps_regulate_link(wl, hlid,
587 wl->links[hlid].allocated_blks);
588 }
589}
590
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300591static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200592 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200594 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200595 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596 u32 total = 0;
597 int i;
598
Eliad Pellerc8bde242011-02-02 09:59:35 +0200599 if (wl->bss_type == BSS_TYPE_AP_BSS)
600 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
601 sizeof(struct wl1271_fw_ap_status), false);
602 else
603 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
604 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300605
606 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
607 "drv_rx_counter = %d, tx_results_counter = %d)",
608 status->intr,
609 status->fw_rx_counter,
610 status->drv_rx_counter,
611 status->tx_results_counter);
612
613 /* update number of available TX blocks */
614 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300615 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
616 wl->tx_blocks_freed[i];
617
618 wl->tx_blocks_freed[i] =
619 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620 wl->tx_blocks_available += cnt;
621 total += cnt;
622 }
623
Ido Yariva5225502010-10-12 14:49:10 +0200624 /* if more blocks are available now, tx work can be scheduled */
625 if (total)
626 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627
Arik Nemtsovb622d992011-02-23 00:22:31 +0200628 /* for AP update num of allocated TX blocks per link and ps status */
629 if (wl->bss_type == BSS_TYPE_AP_BSS)
630 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200631
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200633 getnstimeofday(&ts);
634 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
635 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636}
637
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200638#define WL1271_IRQ_MAX_LOOPS 10
639
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640static void wl1271_irq_work(struct work_struct *work)
641{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300643 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200644 int loopcount = WL1271_IRQ_MAX_LOOPS;
645 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300646 struct wl1271 *wl =
647 container_of(work, struct wl1271, irq_work);
648
649 mutex_lock(&wl->mutex);
650
651 wl1271_debug(DEBUG_IRQ, "IRQ work");
652
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200653 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654 goto out;
655
656 ret = wl1271_ps_elp_wakeup(wl, true);
657 if (ret < 0)
658 goto out;
659
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200660 spin_lock_irqsave(&wl->wl_lock, flags);
661 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
662 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
663 spin_unlock_irqrestore(&wl->wl_lock, flags);
664 loopcount--;
665
666 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200667 intr = le32_to_cpu(wl->fw_status->common.intr);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200668 if (!intr) {
669 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200670 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200671 continue;
672 }
673
674 intr &= WL1271_INTR_MASK;
675
Eliad Pellerccc83b02010-10-27 14:09:57 +0200676 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
677 wl1271_error("watchdog interrupt received! "
678 "starting recovery.");
679 ieee80211_queue_work(wl->hw, &wl->recovery_work);
680
681 /* restarting the chip. ignore any other interrupt. */
682 goto out;
683 }
684
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200685 if (intr & WL1271_ACX_INTR_DATA) {
686 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
687
Ido Yariv8aad2462011-03-01 15:14:38 +0200688 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200689
Ido Yariva5225502010-10-12 14:49:10 +0200690 /* Check if any tx blocks were freed */
691 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200692 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200693 /*
694 * In order to avoid starvation of the TX path,
695 * call the work function directly.
696 */
697 wl1271_tx_work_locked(wl);
698 }
699
Ido Yariv8aad2462011-03-01 15:14:38 +0200700 /* check for tx results */
701 if (wl->fw_status->common.tx_results_counter !=
702 (wl->tx_results_count & 0xff))
703 wl1271_tx_complete(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200704 }
705
706 if (intr & WL1271_ACX_INTR_EVENT_A) {
707 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
708 wl1271_event_handle(wl, 0);
709 }
710
711 if (intr & WL1271_ACX_INTR_EVENT_B) {
712 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
713 wl1271_event_handle(wl, 1);
714 }
715
716 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
717 wl1271_debug(DEBUG_IRQ,
718 "WL1271_ACX_INTR_INIT_COMPLETE");
719
720 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
721 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
722
723 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 }
725
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200726 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
727 ieee80211_queue_work(wl->hw, &wl->irq_work);
728 else
729 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
730 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 wl1271_ps_elp_sleep(wl);
733
734out:
735 mutex_unlock(&wl->mutex);
736}
737
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738static int wl1271_fetch_firmware(struct wl1271 *wl)
739{
740 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200741 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742 int ret;
743
Arik Nemtsov166d5042010-10-16 21:44:57 +0200744 switch (wl->bss_type) {
745 case BSS_TYPE_AP_BSS:
746 fw_name = WL1271_AP_FW_NAME;
747 break;
748 case BSS_TYPE_IBSS:
749 case BSS_TYPE_STA_BSS:
750 fw_name = WL1271_FW_NAME;
751 break;
752 default:
753 wl1271_error("no compatible firmware for bss_type %d",
754 wl->bss_type);
755 return -EINVAL;
756 }
757
758 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
759
760 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761
762 if (ret < 0) {
763 wl1271_error("could not get firmware: %d", ret);
764 return ret;
765 }
766
767 if (fw->size % 4) {
768 wl1271_error("firmware size is not multiple of 32 bits: %zu",
769 fw->size);
770 ret = -EILSEQ;
771 goto out;
772 }
773
Arik Nemtsov166d5042010-10-16 21:44:57 +0200774 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300776 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777
778 if (!wl->fw) {
779 wl1271_error("could not allocate memory for the firmware");
780 ret = -ENOMEM;
781 goto out;
782 }
783
784 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200785 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786 ret = 0;
787
788out:
789 release_firmware(fw);
790
791 return ret;
792}
793
794static int wl1271_fetch_nvs(struct wl1271 *wl)
795{
796 const struct firmware *fw;
797 int ret;
798
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200799 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 if (ret < 0) {
802 wl1271_error("could not get nvs file: %d", ret);
803 return ret;
804 }
805
Julia Lawall929ebd32010-05-15 23:16:39 +0200806 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
808 if (!wl->nvs) {
809 wl1271_error("could not allocate memory for the nvs file");
810 ret = -ENOMEM;
811 goto out;
812 }
813
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200814 wl->nvs_len = fw->size;
815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816out:
817 release_firmware(fw);
818
819 return ret;
820}
821
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200822static void wl1271_recovery_work(struct work_struct *work)
823{
824 struct wl1271 *wl =
825 container_of(work, struct wl1271, recovery_work);
826
827 mutex_lock(&wl->mutex);
828
829 if (wl->state != WL1271_STATE_ON)
830 goto out;
831
832 wl1271_info("Hardware recovery in progress.");
833
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200834 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
835 ieee80211_connection_loss(wl->vif);
836
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200837 /* reboot the chipset */
838 __wl1271_op_remove_interface(wl);
839 ieee80211_restart_hw(wl->hw);
840
841out:
842 mutex_unlock(&wl->mutex);
843}
844
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845static void wl1271_fw_wakeup(struct wl1271 *wl)
846{
847 u32 elp_reg;
848
849 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300850 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851}
852
853static int wl1271_setup(struct wl1271 *wl)
854{
855 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
856 if (!wl->fw_status)
857 return -ENOMEM;
858
859 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
860 if (!wl->tx_res_if) {
861 kfree(wl->fw_status);
862 return -ENOMEM;
863 }
864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865 return 0;
866}
867
868static int wl1271_chip_wakeup(struct wl1271 *wl)
869{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300870 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871 int ret = 0;
872
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200873 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200874 ret = wl1271_power_on(wl);
875 if (ret < 0)
876 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200878 wl1271_io_reset(wl);
879 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880
881 /* We don't need a real memory partition here, because we only want
882 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300883 memset(&partition, 0, sizeof(partition));
884 partition.reg.start = REGISTERS_BASE;
885 partition.reg.size = REGISTERS_DOWN_SIZE;
886 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887
888 /* ELP module wake up */
889 wl1271_fw_wakeup(wl);
890
891 /* whal_FwCtrl_BootSm() */
892
893 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200894 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
896 /* 1. check if chip id is valid */
897
898 switch (wl->chip.id) {
899 case CHIP_ID_1271_PG10:
900 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
901 wl->chip.id);
902
903 ret = wl1271_setup(wl);
904 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200905 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300906 break;
907 case CHIP_ID_1271_PG20:
908 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
909 wl->chip.id);
910
911 ret = wl1271_setup(wl);
912 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200913 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914 break;
915 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200916 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200918 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 }
920
Arik Nemtsov166d5042010-10-16 21:44:57 +0200921 /* Make sure the firmware type matches the BSS type */
922 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923 ret = wl1271_fetch_firmware(wl);
924 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200925 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 }
927
928 /* No NVS from netlink, try to get it from the filesystem */
929 if (wl->nvs == NULL) {
930 ret = wl1271_fetch_nvs(wl);
931 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200932 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933 }
934
935out:
936 return ret;
937}
938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939int wl1271_plt_start(struct wl1271 *wl)
940{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200941 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 int ret;
943
944 mutex_lock(&wl->mutex);
945
946 wl1271_notice("power up");
947
948 if (wl->state != WL1271_STATE_OFF) {
949 wl1271_error("cannot go into PLT state because not "
950 "in off state: %d", wl->state);
951 ret = -EBUSY;
952 goto out;
953 }
954
Arik Nemtsov166d5042010-10-16 21:44:57 +0200955 wl->bss_type = BSS_TYPE_STA_BSS;
956
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200957 while (retries) {
958 retries--;
959 ret = wl1271_chip_wakeup(wl);
960 if (ret < 0)
961 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963 ret = wl1271_boot(wl);
964 if (ret < 0)
965 goto power_off;
966
967 ret = wl1271_plt_init(wl);
968 if (ret < 0)
969 goto irq_disable;
970
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200971 wl->state = WL1271_STATE_PLT;
972 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100973 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 goto out;
975
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200976irq_disable:
977 wl1271_disable_interrupts(wl);
978 mutex_unlock(&wl->mutex);
979 /* Unlocking the mutex in the middle of handling is
980 inherently unsafe. In this case we deem it safe to do,
981 because we need to let any possibly pending IRQ out of
982 the system (and while we are WL1271_STATE_OFF the IRQ
983 work function will not do anything.) Also, any other
984 possible concurrent operations will fail due to the
985 current state, hence the wl1271 struct should be safe. */
986 cancel_work_sync(&wl->irq_work);
987 mutex_lock(&wl->mutex);
988power_off:
989 wl1271_power_off(wl);
990 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200992 wl1271_error("firmware boot in PLT mode failed despite %d retries",
993 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994out:
995 mutex_unlock(&wl->mutex);
996
997 return ret;
998}
999
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001000int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001{
1002 int ret = 0;
1003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 wl1271_notice("power down");
1005
1006 if (wl->state != WL1271_STATE_PLT) {
1007 wl1271_error("cannot power down because not in PLT "
1008 "state: %d", wl->state);
1009 ret = -EBUSY;
1010 goto out;
1011 }
1012
1013 wl1271_disable_interrupts(wl);
1014 wl1271_power_off(wl);
1015
1016 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001017 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001020 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001021 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001022 mutex_lock(&wl->mutex);
1023out:
1024 return ret;
1025}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001026
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001027int wl1271_plt_stop(struct wl1271 *wl)
1028{
1029 int ret;
1030
1031 mutex_lock(&wl->mutex);
1032 ret = __wl1271_plt_stop(wl);
1033 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 return ret;
1035}
1036
Johannes Berg7bb45682011-02-24 14:42:06 +01001037static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038{
1039 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001040 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001041 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001042 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001044 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001045 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001046
1047 /*
1048 * The workqueue is slow to process the tx_queue and we need stop
1049 * the queue here, otherwise the queue will get too long.
1050 */
1051 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1052 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1053 ieee80211_stop_queues(wl->hw);
1054 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1055 }
1056
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001057 spin_unlock_irqrestore(&wl->wl_lock, flags);
1058
1059 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001060 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001061 if (wl->bss_type == BSS_TYPE_AP_BSS) {
1062 hlid = wl1271_tx_get_hlid(skb);
1063 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1064 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1065 } else {
1066 skb_queue_tail(&wl->tx_queue[q], skb);
1067 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 /*
1070 * The chip specific setup must run before the first TX packet -
1071 * before that, the tx_work will not be initialized!
1072 */
1073
Ido Yariva5225502010-10-12 14:49:10 +02001074 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1075 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076}
1077
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001078static struct notifier_block wl1271_dev_notifier = {
1079 .notifier_call = wl1271_dev_notify,
1080};
1081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082static int wl1271_op_start(struct ieee80211_hw *hw)
1083{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001084 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1085
1086 /*
1087 * We have to delay the booting of the hardware because
1088 * we need to know the local MAC address before downloading and
1089 * initializing the firmware. The MAC address cannot be changed
1090 * after boot, and without the proper MAC address, the firmware
1091 * will not function properly.
1092 *
1093 * The MAC address is first known when the corresponding interface
1094 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001095 *
1096 * In addition, we currently have different firmwares for AP and managed
1097 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001098 */
1099
1100 return 0;
1101}
1102
1103static void wl1271_op_stop(struct ieee80211_hw *hw)
1104{
1105 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1106}
1107
1108static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1109 struct ieee80211_vif *vif)
1110{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001112 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001113 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001114 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001115 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001117 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1118 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119
1120 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001121 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001122 wl1271_debug(DEBUG_MAC80211,
1123 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001124 ret = -EBUSY;
1125 goto out;
1126 }
1127
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001128 switch (vif->type) {
1129 case NL80211_IFTYPE_STATION:
1130 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001131 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001132 break;
1133 case NL80211_IFTYPE_ADHOC:
1134 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001135 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001136 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001137 case NL80211_IFTYPE_AP:
1138 wl->bss_type = BSS_TYPE_AP_BSS;
1139 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001140 default:
1141 ret = -EOPNOTSUPP;
1142 goto out;
1143 }
1144
1145 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146
1147 if (wl->state != WL1271_STATE_OFF) {
1148 wl1271_error("cannot start because not in off state: %d",
1149 wl->state);
1150 ret = -EBUSY;
1151 goto out;
1152 }
1153
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001154 while (retries) {
1155 retries--;
1156 ret = wl1271_chip_wakeup(wl);
1157 if (ret < 0)
1158 goto power_off;
1159
1160 ret = wl1271_boot(wl);
1161 if (ret < 0)
1162 goto power_off;
1163
1164 ret = wl1271_hw_init(wl);
1165 if (ret < 0)
1166 goto irq_disable;
1167
Eliad Peller71125ab2010-10-28 21:46:43 +02001168 booted = true;
1169 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001171irq_disable:
1172 wl1271_disable_interrupts(wl);
1173 mutex_unlock(&wl->mutex);
1174 /* Unlocking the mutex in the middle of handling is
1175 inherently unsafe. In this case we deem it safe to do,
1176 because we need to let any possibly pending IRQ out of
1177 the system (and while we are WL1271_STATE_OFF the IRQ
1178 work function will not do anything.) Also, any other
1179 possible concurrent operations will fail due to the
1180 current state, hence the wl1271 struct should be safe. */
1181 cancel_work_sync(&wl->irq_work);
1182 mutex_lock(&wl->mutex);
1183power_off:
1184 wl1271_power_off(wl);
1185 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186
Eliad Peller71125ab2010-10-28 21:46:43 +02001187 if (!booted) {
1188 wl1271_error("firmware boot failed despite %d retries",
1189 WL1271_BOOT_RETRIES);
1190 goto out;
1191 }
1192
1193 wl->vif = vif;
1194 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001195 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001196
1197 /* update hw/fw version info in wiphy struct */
1198 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001199 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001200 sizeof(wiphy->fw_version));
1201
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001202 /*
1203 * Now we know if 11a is supported (info from the NVS), so disable
1204 * 11a channels if not supported
1205 */
1206 if (!wl->enable_11a)
1207 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1208
1209 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1210 wl->enable_11a ? "" : "not ");
1211
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001212out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213 mutex_unlock(&wl->mutex);
1214
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001215 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001216 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 return ret;
1219}
1220
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001221static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 int i;
1224
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001225 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001227 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001229 list_del(&wl->list);
1230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001231 WARN_ON(wl->state != WL1271_STATE_ON);
1232
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001233 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001234 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001235 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001236
Luciano Coelho08688d62010-07-08 17:50:07 +03001237 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001238 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1239 kfree(wl->scan.scanned_ch);
1240 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001241 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001242 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243 }
1244
1245 wl->state = WL1271_STATE_OFF;
1246
1247 wl1271_disable_interrupts(wl);
1248
1249 mutex_unlock(&wl->mutex);
1250
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001251 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 cancel_work_sync(&wl->irq_work);
1253 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001254 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001255 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
1257 mutex_lock(&wl->mutex);
1258
1259 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001260 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261 wl1271_power_off(wl);
1262
1263 memset(wl->bssid, 0, ETH_ALEN);
1264 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1265 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001267 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001268 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
1270 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001271 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1273 wl->tx_blocks_available = 0;
1274 wl->tx_results_count = 0;
1275 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001276 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001277 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 wl->time_offset = 0;
1279 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001280 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001281 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001282 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001283 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001284 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001285 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001286 wl->ap_fw_ps_map = 0;
1287 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001288
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 for (i = 0; i < NUM_TX_QUEUES; i++)
1290 wl->tx_blocks_freed[i] = 0;
1291
1292 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001293
1294 kfree(wl->fw_status);
1295 wl->fw_status = NULL;
1296 kfree(wl->tx_res_if);
1297 wl->tx_res_if = NULL;
1298 kfree(wl->target_mem_map);
1299 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001300}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001301
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001302static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1303 struct ieee80211_vif *vif)
1304{
1305 struct wl1271 *wl = hw->priv;
1306
1307 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001308 /*
1309 * wl->vif can be null here if someone shuts down the interface
1310 * just when hardware recovery has been started.
1311 */
1312 if (wl->vif) {
1313 WARN_ON(wl->vif != vif);
1314 __wl1271_op_remove_interface(wl);
1315 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001316
Juuso Oikarinen67353292010-11-18 15:19:02 +02001317 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001318 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319}
1320
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001321static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1322{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001323 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001324
1325 /* combine requested filters with current filter config */
1326 filters = wl->filters | filters;
1327
1328 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1329
1330 if (filters & FIF_PROMISC_IN_BSS) {
1331 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1332 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1333 wl->rx_config |= CFG_BSSID_FILTER_EN;
1334 }
1335 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1336 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1337 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1338 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1339 }
1340 if (filters & FIF_OTHER_BSS) {
1341 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1342 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1343 }
1344 if (filters & FIF_CONTROL) {
1345 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1346 wl->rx_filter |= CFG_RX_CTL_EN;
1347 }
1348 if (filters & FIF_FCSFAIL) {
1349 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1350 wl->rx_filter |= CFG_RX_FCS_ERROR;
1351 }
1352}
1353
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001354static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001355{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001356 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001357 /* we need to use a dummy BSSID for now */
1358 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1359 0xad, 0xbe, 0xef };
1360
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001361 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1362
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001363 /* pass through frames from all BSS */
1364 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1365
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001366 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001367 if (ret < 0)
1368 goto out;
1369
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001370 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001371
1372out:
1373 return ret;
1374}
1375
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001376static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001377{
1378 int ret;
1379
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001380 /*
1381 * One of the side effects of the JOIN command is that is clears
1382 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1383 * to a WPA/WPA2 access point will therefore kill the data-path.
1384 * Currently there is no supported scenario for JOIN during
1385 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1386 * must be handled somehow.
1387 *
1388 */
1389 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1390 wl1271_info("JOIN while associated.");
1391
1392 if (set_assoc)
1393 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1394
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001395 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1396 if (ret < 0)
1397 goto out;
1398
1399 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1400
1401 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1402 goto out;
1403
1404 /*
1405 * The join command disable the keep-alive mode, shut down its process,
1406 * and also clear the template config, so we need to reset it all after
1407 * the join. The acx_aid starts the keep-alive process, and the order
1408 * of the commands below is relevant.
1409 */
1410 ret = wl1271_acx_keep_alive_mode(wl, true);
1411 if (ret < 0)
1412 goto out;
1413
1414 ret = wl1271_acx_aid(wl, wl->aid);
1415 if (ret < 0)
1416 goto out;
1417
1418 ret = wl1271_cmd_build_klv_null_data(wl);
1419 if (ret < 0)
1420 goto out;
1421
1422 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1423 ACX_KEEP_ALIVE_TPL_VALID);
1424 if (ret < 0)
1425 goto out;
1426
1427out:
1428 return ret;
1429}
1430
1431static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001432{
1433 int ret;
1434
1435 /* to stop listening to a channel, we disconnect */
1436 ret = wl1271_cmd_disconnect(wl);
1437 if (ret < 0)
1438 goto out;
1439
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001440 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001441 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001442
1443 /* stop filterting packets based on bssid */
1444 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001445
1446out:
1447 return ret;
1448}
1449
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001450static void wl1271_set_band_rate(struct wl1271 *wl)
1451{
1452 if (wl->band == IEEE80211_BAND_2GHZ)
1453 wl->basic_rate_set = wl->conf.tx.basic_rate;
1454 else
1455 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1456}
1457
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001458static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001459{
1460 int ret;
1461
1462 if (idle) {
1463 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1464 ret = wl1271_unjoin(wl);
1465 if (ret < 0)
1466 goto out;
1467 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001468 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001469 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001470 if (ret < 0)
1471 goto out;
1472 ret = wl1271_acx_keep_alive_config(
1473 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1474 ACX_KEEP_ALIVE_TPL_INVALID);
1475 if (ret < 0)
1476 goto out;
1477 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1478 } else {
1479 /* increment the session counter */
1480 wl->session_counter++;
1481 if (wl->session_counter >= SESSION_COUNTER_MAX)
1482 wl->session_counter = 0;
1483 ret = wl1271_dummy_join(wl);
1484 if (ret < 0)
1485 goto out;
1486 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1487 }
1488
1489out:
1490 return ret;
1491}
1492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1494{
1495 struct wl1271 *wl = hw->priv;
1496 struct ieee80211_conf *conf = &hw->conf;
1497 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001498 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499
1500 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1501
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001502 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1503 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 channel,
1505 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001506 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001507 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1508 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001510 /*
1511 * mac80211 will go to idle nearly immediately after transmitting some
1512 * frames, such as the deauth. To make sure those frames reach the air,
1513 * wait here until the TX queue is fully flushed.
1514 */
1515 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1516 (conf->flags & IEEE80211_CONF_IDLE))
1517 wl1271_tx_flush(wl);
1518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519 mutex_lock(&wl->mutex);
1520
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001521 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1522 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001523 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001524 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001525
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001526 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1527
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 ret = wl1271_ps_elp_wakeup(wl, false);
1529 if (ret < 0)
1530 goto out;
1531
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001532 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001533 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1534 ((wl->band != conf->channel->band) ||
1535 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001536 wl->band = conf->channel->band;
1537 wl->channel = channel;
1538
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001539 if (!is_ap) {
1540 /*
1541 * FIXME: the mac80211 should really provide a fixed
1542 * rate to use here. for now, just use the smallest
1543 * possible rate for the band as a fixed rate for
1544 * association frames and other control messages.
1545 */
1546 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1547 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001548
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001549 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1550 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001551 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001552 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001553 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001554
1555 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1556 ret = wl1271_join(wl, false);
1557 if (ret < 0)
1558 wl1271_warning("cmd join on channel "
1559 "failed %d", ret);
1560 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001561 }
1562 }
1563
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001564 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1565 ret = wl1271_sta_handle_idle(wl,
1566 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001567 if (ret < 0)
1568 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 }
1570
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001571 /*
1572 * if mac80211 changes the PSM mode, make sure the mode is not
1573 * incorrectly changed after the pspoll failure active window.
1574 */
1575 if (changed & IEEE80211_CONF_CHANGE_PS)
1576 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1577
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001578 if (conf->flags & IEEE80211_CONF_PS &&
1579 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1580 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001581
1582 /*
1583 * We enter PSM only if we're already associated.
1584 * If we're not, we'll enter it when joining an SSID,
1585 * through the bss_info_changed() hook.
1586 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001587 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001588 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001589 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001590 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001591 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001593 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001594 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001596 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001598 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001599 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001600 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601 }
1602
1603 if (conf->power_level != wl->power_level) {
1604 ret = wl1271_acx_tx_power(wl, conf->power_level);
1605 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001606 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607
1608 wl->power_level = conf->power_level;
1609 }
1610
1611out_sleep:
1612 wl1271_ps_elp_sleep(wl);
1613
1614out:
1615 mutex_unlock(&wl->mutex);
1616
1617 return ret;
1618}
1619
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001620struct wl1271_filter_params {
1621 bool enabled;
1622 int mc_list_length;
1623 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1624};
1625
Jiri Pirko22bedad2010-04-01 21:22:57 +00001626static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1627 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001628{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001629 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001630 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001631 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001632
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001633 if (unlikely(wl->state == WL1271_STATE_OFF))
1634 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001635
Juuso Oikarinen74441132009-10-13 12:47:53 +03001636 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001637 if (!fp) {
1638 wl1271_error("Out of memory setting filters.");
1639 return 0;
1640 }
1641
1642 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001643 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001644 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1645 fp->enabled = false;
1646 } else {
1647 fp->enabled = true;
1648 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001649 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001650 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001651 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001652 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001653 }
1654
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001655 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001656}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001658#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1659 FIF_ALLMULTI | \
1660 FIF_FCSFAIL | \
1661 FIF_BCN_PRBRESP_PROMISC | \
1662 FIF_CONTROL | \
1663 FIF_OTHER_BSS)
1664
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1666 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001667 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001669 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001671 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672
Arik Nemtsov7d057862010-10-16 19:25:35 +02001673 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1674 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001676 mutex_lock(&wl->mutex);
1677
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001678 *total &= WL1271_SUPPORTED_FILTERS;
1679 changed &= WL1271_SUPPORTED_FILTERS;
1680
1681 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001682 goto out;
1683
1684 ret = wl1271_ps_elp_wakeup(wl, false);
1685 if (ret < 0)
1686 goto out;
1687
Arik Nemtsov7d057862010-10-16 19:25:35 +02001688 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1689 if (*total & FIF_ALLMULTI)
1690 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1691 else if (fp)
1692 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1693 fp->mc_list,
1694 fp->mc_list_length);
1695 if (ret < 0)
1696 goto out_sleep;
1697 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001699 /* determine, whether supported filter values have changed */
1700 if (changed == 0)
1701 goto out_sleep;
1702
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001703 /* configure filters */
1704 wl->filters = *total;
1705 wl1271_configure_filters(wl, 0);
1706
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001707 /* apply configured filters */
1708 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1709 if (ret < 0)
1710 goto out_sleep;
1711
1712out_sleep:
1713 wl1271_ps_elp_sleep(wl);
1714
1715out:
1716 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001717 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718}
1719
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001720static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1721 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1722 u16 tx_seq_16)
1723{
1724 struct wl1271_ap_key *ap_key;
1725 int i;
1726
1727 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1728
1729 if (key_size > MAX_KEY_SIZE)
1730 return -EINVAL;
1731
1732 /*
1733 * Find next free entry in ap_keys. Also check we are not replacing
1734 * an existing key.
1735 */
1736 for (i = 0; i < MAX_NUM_KEYS; i++) {
1737 if (wl->recorded_ap_keys[i] == NULL)
1738 break;
1739
1740 if (wl->recorded_ap_keys[i]->id == id) {
1741 wl1271_warning("trying to record key replacement");
1742 return -EINVAL;
1743 }
1744 }
1745
1746 if (i == MAX_NUM_KEYS)
1747 return -EBUSY;
1748
1749 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1750 if (!ap_key)
1751 return -ENOMEM;
1752
1753 ap_key->id = id;
1754 ap_key->key_type = key_type;
1755 ap_key->key_size = key_size;
1756 memcpy(ap_key->key, key, key_size);
1757 ap_key->hlid = hlid;
1758 ap_key->tx_seq_32 = tx_seq_32;
1759 ap_key->tx_seq_16 = tx_seq_16;
1760
1761 wl->recorded_ap_keys[i] = ap_key;
1762 return 0;
1763}
1764
1765static void wl1271_free_ap_keys(struct wl1271 *wl)
1766{
1767 int i;
1768
1769 for (i = 0; i < MAX_NUM_KEYS; i++) {
1770 kfree(wl->recorded_ap_keys[i]);
1771 wl->recorded_ap_keys[i] = NULL;
1772 }
1773}
1774
1775static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1776{
1777 int i, ret = 0;
1778 struct wl1271_ap_key *key;
1779 bool wep_key_added = false;
1780
1781 for (i = 0; i < MAX_NUM_KEYS; i++) {
1782 if (wl->recorded_ap_keys[i] == NULL)
1783 break;
1784
1785 key = wl->recorded_ap_keys[i];
1786 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1787 key->id, key->key_type,
1788 key->key_size, key->key,
1789 key->hlid, key->tx_seq_32,
1790 key->tx_seq_16);
1791 if (ret < 0)
1792 goto out;
1793
1794 if (key->key_type == KEY_WEP)
1795 wep_key_added = true;
1796 }
1797
1798 if (wep_key_added) {
1799 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1800 if (ret < 0)
1801 goto out;
1802 }
1803
1804out:
1805 wl1271_free_ap_keys(wl);
1806 return ret;
1807}
1808
1809static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1810 u8 key_size, const u8 *key, u32 tx_seq_32,
1811 u16 tx_seq_16, struct ieee80211_sta *sta)
1812{
1813 int ret;
1814 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1815
1816 if (is_ap) {
1817 struct wl1271_station *wl_sta;
1818 u8 hlid;
1819
1820 if (sta) {
1821 wl_sta = (struct wl1271_station *)sta->drv_priv;
1822 hlid = wl_sta->hlid;
1823 } else {
1824 hlid = WL1271_AP_BROADCAST_HLID;
1825 }
1826
1827 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1828 /*
1829 * We do not support removing keys after AP shutdown.
1830 * Pretend we do to make mac80211 happy.
1831 */
1832 if (action != KEY_ADD_OR_REPLACE)
1833 return 0;
1834
1835 ret = wl1271_record_ap_key(wl, id,
1836 key_type, key_size,
1837 key, hlid, tx_seq_32,
1838 tx_seq_16);
1839 } else {
1840 ret = wl1271_cmd_set_ap_key(wl, action,
1841 id, key_type, key_size,
1842 key, hlid, tx_seq_32,
1843 tx_seq_16);
1844 }
1845
1846 if (ret < 0)
1847 return ret;
1848 } else {
1849 const u8 *addr;
1850 static const u8 bcast_addr[ETH_ALEN] = {
1851 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1852 };
1853
1854 addr = sta ? sta->addr : bcast_addr;
1855
1856 if (is_zero_ether_addr(addr)) {
1857 /* We dont support TX only encryption */
1858 return -EOPNOTSUPP;
1859 }
1860
1861 /* The wl1271 does not allow to remove unicast keys - they
1862 will be cleared automatically on next CMD_JOIN. Ignore the
1863 request silently, as we dont want the mac80211 to emit
1864 an error message. */
1865 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1866 return 0;
1867
1868 ret = wl1271_cmd_set_sta_key(wl, action,
1869 id, key_type, key_size,
1870 key, addr, tx_seq_32,
1871 tx_seq_16);
1872 if (ret < 0)
1873 return ret;
1874
1875 /* the default WEP key needs to be configured at least once */
1876 if (key_type == KEY_WEP) {
1877 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1878 wl->default_key);
1879 if (ret < 0)
1880 return ret;
1881 }
1882 }
1883
1884 return 0;
1885}
1886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1888 struct ieee80211_vif *vif,
1889 struct ieee80211_sta *sta,
1890 struct ieee80211_key_conf *key_conf)
1891{
1892 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001893 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001894 u32 tx_seq_32 = 0;
1895 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 u8 key_type;
1897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001898 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1899
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001900 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001901 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001902 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001903 key_conf->keylen, key_conf->flags);
1904 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1905
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 mutex_lock(&wl->mutex);
1907
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001908 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1909 ret = -EAGAIN;
1910 goto out_unlock;
1911 }
1912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913 ret = wl1271_ps_elp_wakeup(wl, false);
1914 if (ret < 0)
1915 goto out_unlock;
1916
Johannes Berg97359d12010-08-10 09:46:38 +02001917 switch (key_conf->cipher) {
1918 case WLAN_CIPHER_SUITE_WEP40:
1919 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920 key_type = KEY_WEP;
1921
1922 key_conf->hw_key_idx = key_conf->keyidx;
1923 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001924 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001925 key_type = KEY_TKIP;
1926
1927 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001928 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1929 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001931 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 key_type = KEY_AES;
1933
1934 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001935 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1936 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001938 case WL1271_CIPHER_SUITE_GEM:
1939 key_type = KEY_GEM;
1940 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1941 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1942 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001944 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945
1946 ret = -EOPNOTSUPP;
1947 goto out_sleep;
1948 }
1949
1950 switch (cmd) {
1951 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001952 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1953 key_conf->keyidx, key_type,
1954 key_conf->keylen, key_conf->key,
1955 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 if (ret < 0) {
1957 wl1271_error("Could not add or replace key");
1958 goto out_sleep;
1959 }
1960 break;
1961
1962 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001963 ret = wl1271_set_key(wl, KEY_REMOVE,
1964 key_conf->keyidx, key_type,
1965 key_conf->keylen, key_conf->key,
1966 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 if (ret < 0) {
1968 wl1271_error("Could not remove key");
1969 goto out_sleep;
1970 }
1971 break;
1972
1973 default:
1974 wl1271_error("Unsupported key cmd 0x%x", cmd);
1975 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976 break;
1977 }
1978
1979out_sleep:
1980 wl1271_ps_elp_sleep(wl);
1981
1982out_unlock:
1983 mutex_unlock(&wl->mutex);
1984
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985 return ret;
1986}
1987
1988static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001989 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990 struct cfg80211_scan_request *req)
1991{
1992 struct wl1271 *wl = hw->priv;
1993 int ret;
1994 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001995 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996
1997 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1998
1999 if (req->n_ssids) {
2000 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002001 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002002 }
2003
2004 mutex_lock(&wl->mutex);
2005
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002006 if (wl->state == WL1271_STATE_OFF) {
2007 /*
2008 * We cannot return -EBUSY here because cfg80211 will expect
2009 * a call to ieee80211_scan_completed if we do - in this case
2010 * there won't be any call.
2011 */
2012 ret = -EAGAIN;
2013 goto out;
2014 }
2015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 ret = wl1271_ps_elp_wakeup(wl, false);
2017 if (ret < 0)
2018 goto out;
2019
Luciano Coelho5924f892010-08-04 03:46:22 +03002020 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021
2022 wl1271_ps_elp_sleep(wl);
2023
2024out:
2025 mutex_unlock(&wl->mutex);
2026
2027 return ret;
2028}
2029
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002030static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2031{
2032 struct wl1271 *wl = hw->priv;
2033 int ret = 0;
2034
2035 mutex_lock(&wl->mutex);
2036
2037 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2038 ret = -EAGAIN;
2039 goto out;
2040 }
2041
2042 ret = wl1271_ps_elp_wakeup(wl, false);
2043 if (ret < 0)
2044 goto out;
2045
2046 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2047 if (ret < 0)
2048 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2049
2050 wl1271_ps_elp_sleep(wl);
2051
2052out:
2053 mutex_unlock(&wl->mutex);
2054
2055 return ret;
2056}
2057
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2059{
2060 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002061 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
2063 mutex_lock(&wl->mutex);
2064
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002065 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2066 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002067 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002068 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002069
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070 ret = wl1271_ps_elp_wakeup(wl, false);
2071 if (ret < 0)
2072 goto out;
2073
2074 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2075 if (ret < 0)
2076 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2077
2078 wl1271_ps_elp_sleep(wl);
2079
2080out:
2081 mutex_unlock(&wl->mutex);
2082
2083 return ret;
2084}
2085
Arik Nemtsove78a2872010-10-16 19:07:21 +02002086static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002087 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002088{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002089 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002090
2091 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002092 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002093 if (ptr[0] == WLAN_EID_SSID) {
2094 wl->ssid_len = ptr[1];
2095 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002096 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002097 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002098 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002099 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002100
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002101 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002102 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002103}
2104
Arik Nemtsove78a2872010-10-16 19:07:21 +02002105static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2106 struct ieee80211_bss_conf *bss_conf,
2107 u32 changed)
2108{
2109 int ret = 0;
2110
2111 if (changed & BSS_CHANGED_ERP_SLOT) {
2112 if (bss_conf->use_short_slot)
2113 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2114 else
2115 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2116 if (ret < 0) {
2117 wl1271_warning("Set slot time failed %d", ret);
2118 goto out;
2119 }
2120 }
2121
2122 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2123 if (bss_conf->use_short_preamble)
2124 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2125 else
2126 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2127 }
2128
2129 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2130 if (bss_conf->use_cts_prot)
2131 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2132 else
2133 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2134 if (ret < 0) {
2135 wl1271_warning("Set ctsprotect failed %d", ret);
2136 goto out;
2137 }
2138 }
2139
2140out:
2141 return ret;
2142}
2143
2144static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2145 struct ieee80211_vif *vif,
2146 struct ieee80211_bss_conf *bss_conf,
2147 u32 changed)
2148{
2149 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2150 int ret = 0;
2151
2152 if ((changed & BSS_CHANGED_BEACON_INT)) {
2153 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2154 bss_conf->beacon_int);
2155
2156 wl->beacon_int = bss_conf->beacon_int;
2157 }
2158
2159 if ((changed & BSS_CHANGED_BEACON)) {
2160 struct ieee80211_hdr *hdr;
2161 int ieoffset = offsetof(struct ieee80211_mgmt,
2162 u.beacon.variable);
2163 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2164 u16 tmpl_id;
2165
2166 if (!beacon)
2167 goto out;
2168
2169 wl1271_debug(DEBUG_MASTER, "beacon updated");
2170
2171 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2172 if (ret < 0) {
2173 dev_kfree_skb(beacon);
2174 goto out;
2175 }
2176 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2177 CMD_TEMPL_BEACON;
2178 ret = wl1271_cmd_template_set(wl, tmpl_id,
2179 beacon->data,
2180 beacon->len, 0,
2181 wl1271_tx_min_rate_get(wl));
2182 if (ret < 0) {
2183 dev_kfree_skb(beacon);
2184 goto out;
2185 }
2186
2187 hdr = (struct ieee80211_hdr *) beacon->data;
2188 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2189 IEEE80211_STYPE_PROBE_RESP);
2190
2191 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2192 CMD_TEMPL_PROBE_RESPONSE;
2193 ret = wl1271_cmd_template_set(wl,
2194 tmpl_id,
2195 beacon->data,
2196 beacon->len, 0,
2197 wl1271_tx_min_rate_get(wl));
2198 dev_kfree_skb(beacon);
2199 if (ret < 0)
2200 goto out;
2201 }
2202
2203out:
2204 return ret;
2205}
2206
2207/* AP mode changes */
2208static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209 struct ieee80211_vif *vif,
2210 struct ieee80211_bss_conf *bss_conf,
2211 u32 changed)
2212{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002213 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214
Arik Nemtsove78a2872010-10-16 19:07:21 +02002215 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2216 u32 rates = bss_conf->basic_rates;
2217 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218
Arik Nemtsove78a2872010-10-16 19:07:21 +02002219 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2220 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2221 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2222 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223
Arik Nemtsove78a2872010-10-16 19:07:21 +02002224 /* update the AP management rate policy with the new rates */
2225 mgmt_rc.enabled_rates = wl->basic_rate_set;
2226 mgmt_rc.long_retry_limit = 10;
2227 mgmt_rc.short_retry_limit = 10;
2228 mgmt_rc.aflags = 0;
2229 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2230 ACX_TX_AP_MODE_MGMT_RATE);
2231 if (ret < 0) {
2232 wl1271_error("AP mgmt policy change failed %d", ret);
2233 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002234 }
2235 }
2236
Arik Nemtsove78a2872010-10-16 19:07:21 +02002237 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2238 if (ret < 0)
2239 goto out;
2240
2241 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2242 if (bss_conf->enable_beacon) {
2243 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2244 ret = wl1271_cmd_start_bss(wl);
2245 if (ret < 0)
2246 goto out;
2247
2248 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2249 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002250
2251 ret = wl1271_ap_init_hwenc(wl);
2252 if (ret < 0)
2253 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002254 }
2255 } else {
2256 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2257 ret = wl1271_cmd_stop_bss(wl);
2258 if (ret < 0)
2259 goto out;
2260
2261 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2262 wl1271_debug(DEBUG_AP, "stopped AP");
2263 }
2264 }
2265 }
2266
2267 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2268 if (ret < 0)
2269 goto out;
2270out:
2271 return;
2272}
2273
2274/* STA/IBSS mode changes */
2275static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2276 struct ieee80211_vif *vif,
2277 struct ieee80211_bss_conf *bss_conf,
2278 u32 changed)
2279{
2280 bool do_join = false, set_assoc = false;
2281 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002282 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002283 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002284 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002285 bool sta_exists = false;
2286 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002287
2288 if (is_ibss) {
2289 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2290 changed);
2291 if (ret < 0)
2292 goto out;
2293 }
2294
2295 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2296 do_join = true;
2297
2298 /* Need to update the SSID (for filtering etc) */
2299 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2300 do_join = true;
2301
2302 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002303 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2304 bss_conf->enable_beacon ? "enabled" : "disabled");
2305
2306 if (bss_conf->enable_beacon)
2307 wl->set_bss_type = BSS_TYPE_IBSS;
2308 else
2309 wl->set_bss_type = BSS_TYPE_STA_BSS;
2310 do_join = true;
2311 }
2312
Arik Nemtsove78a2872010-10-16 19:07:21 +02002313 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002314 bool enable = false;
2315 if (bss_conf->cqm_rssi_thold)
2316 enable = true;
2317 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2318 bss_conf->cqm_rssi_thold,
2319 bss_conf->cqm_rssi_hyst);
2320 if (ret < 0)
2321 goto out;
2322 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2323 }
2324
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002325 if ((changed & BSS_CHANGED_BSSID) &&
2326 /*
2327 * Now we know the correct bssid, so we send a new join command
2328 * and enable the BSSID filter
2329 */
2330 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002331 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002332
Eliad Pellerfa287b82010-12-26 09:27:50 +01002333 if (!is_zero_ether_addr(wl->bssid)) {
2334 ret = wl1271_cmd_build_null_data(wl);
2335 if (ret < 0)
2336 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002337
Eliad Pellerfa287b82010-12-26 09:27:50 +01002338 ret = wl1271_build_qos_null_data(wl);
2339 if (ret < 0)
2340 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002341
Eliad Pellerfa287b82010-12-26 09:27:50 +01002342 /* filter out all packets not from this BSSID */
2343 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002344
Eliad Pellerfa287b82010-12-26 09:27:50 +01002345 /* Need to update the BSSID (for filtering etc) */
2346 do_join = true;
2347 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002348 }
2349
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002350 rcu_read_lock();
2351 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2352 if (sta) {
2353 /* save the supp_rates of the ap */
2354 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2355 if (sta->ht_cap.ht_supported)
2356 sta_rate_set |=
2357 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002358 sta_ht_cap = sta->ht_cap;
2359 sta_exists = true;
2360 }
2361 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002362
Arik Nemtsova1008852011-02-12 23:24:20 +02002363 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002364 /* handle new association with HT and HT information change */
2365 if ((changed & BSS_CHANGED_HT) &&
2366 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002367 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002368 true);
2369 if (ret < 0) {
2370 wl1271_warning("Set ht cap true failed %d",
2371 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002372 goto out;
2373 }
2374 ret = wl1271_acx_set_ht_information(wl,
2375 bss_conf->ht_operation_mode);
2376 if (ret < 0) {
2377 wl1271_warning("Set ht information failed %d",
2378 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002379 goto out;
2380 }
2381 }
2382 /* handle new association without HT and disassociation */
2383 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002384 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002385 false);
2386 if (ret < 0) {
2387 wl1271_warning("Set ht cap false failed %d",
2388 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002389 goto out;
2390 }
2391 }
2392 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002393
Arik Nemtsove78a2872010-10-16 19:07:21 +02002394 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002397 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002399 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002401 wl->ps_poll_failures = 0;
2402
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002403 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002404 * use basic rates from AP, and determine lowest rate
2405 * to use with control frames.
2406 */
2407 rates = bss_conf->basic_rates;
2408 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2409 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002410 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002411 if (sta_rate_set)
2412 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2413 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002414 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002415 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002416 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002417
2418 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002419 * with wl1271, we don't need to update the
2420 * beacon_int and dtim_period, because the firmware
2421 * updates it by itself when the first beacon is
2422 * received after a join.
2423 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002424 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2425 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002426 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002428 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002429 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002430 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002431 dev_kfree_skb(wl->probereq);
2432 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2433 ieoffset = offsetof(struct ieee80211_mgmt,
2434 u.probe_req.variable);
2435 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002436
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002437 /* enable the connection monitoring feature */
2438 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002440 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002441
2442 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002443 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2444 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002445 enum wl1271_cmd_ps_mode mode;
2446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002448 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002449 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002450 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002451 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002452 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002454 } else {
2455 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002456 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002457 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002458 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002459
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002460 /* free probe-request template */
2461 dev_kfree_skb(wl->probereq);
2462 wl->probereq = NULL;
2463
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002464 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002465 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002466
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002467 /* revert back to minimum rates for the current band */
2468 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002469 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002470 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002472 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002474 /* disable connection monitor features */
2475 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002476
2477 /* Disable the keep-alive feature */
2478 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002479 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002480 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002481
2482 /* restore the bssid filter and go to dummy bssid */
2483 wl1271_unjoin(wl);
2484 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485 }
2486 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002487
Arik Nemtsove78a2872010-10-16 19:07:21 +02002488 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2489 if (ret < 0)
2490 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002492 if (changed & BSS_CHANGED_ARP_FILTER) {
2493 __be32 addr = bss_conf->arp_addr_list[0];
2494 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2495
Eliad Pellerc5312772010-12-09 11:31:27 +02002496 if (bss_conf->arp_addr_cnt == 1 &&
2497 bss_conf->arp_filter_enabled) {
2498 /*
2499 * The template should have been configured only upon
2500 * association. however, it seems that the correct ip
2501 * isn't being set (when sending), so we have to
2502 * reconfigure the template upon every ip change.
2503 */
2504 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2505 if (ret < 0) {
2506 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002507 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002508 }
2509
2510 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002511 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002512 addr);
2513 } else
2514 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002515
2516 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002517 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002518 }
2519
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002520 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002521 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002522 if (ret < 0) {
2523 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002524 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002525 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002526 }
2527
Arik Nemtsove78a2872010-10-16 19:07:21 +02002528out:
2529 return;
2530}
2531
2532static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2533 struct ieee80211_vif *vif,
2534 struct ieee80211_bss_conf *bss_conf,
2535 u32 changed)
2536{
2537 struct wl1271 *wl = hw->priv;
2538 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2539 int ret;
2540
2541 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2542 (int)changed);
2543
2544 mutex_lock(&wl->mutex);
2545
2546 if (unlikely(wl->state == WL1271_STATE_OFF))
2547 goto out;
2548
2549 ret = wl1271_ps_elp_wakeup(wl, false);
2550 if (ret < 0)
2551 goto out;
2552
2553 if (is_ap)
2554 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2555 else
2556 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2557
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002558 wl1271_ps_elp_sleep(wl);
2559
2560out:
2561 mutex_unlock(&wl->mutex);
2562}
2563
Kalle Valoc6999d82010-02-18 13:25:41 +02002564static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2565 const struct ieee80211_tx_queue_params *params)
2566{
2567 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002568 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002569 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002570
2571 mutex_lock(&wl->mutex);
2572
2573 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2574
Kalle Valo4695dc92010-03-18 12:26:38 +02002575 if (params->uapsd)
2576 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2577 else
2578 ps_scheme = CONF_PS_SCHEME_LEGACY;
2579
Arik Nemtsov488fc542010-10-16 20:33:45 +02002580 if (wl->state == WL1271_STATE_OFF) {
2581 /*
2582 * If the state is off, the parameters will be recorded and
2583 * configured on init. This happens in AP-mode.
2584 */
2585 struct conf_tx_ac_category *conf_ac =
2586 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2587 struct conf_tx_tid *conf_tid =
2588 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2589
2590 conf_ac->ac = wl1271_tx_get_queue(queue);
2591 conf_ac->cw_min = (u8)params->cw_min;
2592 conf_ac->cw_max = params->cw_max;
2593 conf_ac->aifsn = params->aifs;
2594 conf_ac->tx_op_limit = params->txop << 5;
2595
2596 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2597 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2598 conf_tid->tsid = wl1271_tx_get_queue(queue);
2599 conf_tid->ps_scheme = ps_scheme;
2600 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2601 conf_tid->apsd_conf[0] = 0;
2602 conf_tid->apsd_conf[1] = 0;
2603 } else {
2604 ret = wl1271_ps_elp_wakeup(wl, false);
2605 if (ret < 0)
2606 goto out;
2607
2608 /*
2609 * the txop is confed in units of 32us by the mac80211,
2610 * we need us
2611 */
2612 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2613 params->cw_min, params->cw_max,
2614 params->aifs, params->txop << 5);
2615 if (ret < 0)
2616 goto out_sleep;
2617
2618 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2619 CONF_CHANNEL_TYPE_EDCF,
2620 wl1271_tx_get_queue(queue),
2621 ps_scheme, CONF_ACK_POLICY_LEGACY,
2622 0, 0);
2623 if (ret < 0)
2624 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002625
2626out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002627 wl1271_ps_elp_sleep(wl);
2628 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002629
2630out:
2631 mutex_unlock(&wl->mutex);
2632
2633 return ret;
2634}
2635
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002636static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2637{
2638
2639 struct wl1271 *wl = hw->priv;
2640 u64 mactime = ULLONG_MAX;
2641 int ret;
2642
2643 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2644
2645 mutex_lock(&wl->mutex);
2646
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002647 if (unlikely(wl->state == WL1271_STATE_OFF))
2648 goto out;
2649
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002650 ret = wl1271_ps_elp_wakeup(wl, false);
2651 if (ret < 0)
2652 goto out;
2653
2654 ret = wl1271_acx_tsf_info(wl, &mactime);
2655 if (ret < 0)
2656 goto out_sleep;
2657
2658out_sleep:
2659 wl1271_ps_elp_sleep(wl);
2660
2661out:
2662 mutex_unlock(&wl->mutex);
2663 return mactime;
2664}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665
John W. Linvilleece550d2010-07-28 16:41:06 -04002666static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2667 struct survey_info *survey)
2668{
2669 struct wl1271 *wl = hw->priv;
2670 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002671
John W. Linvilleece550d2010-07-28 16:41:06 -04002672 if (idx != 0)
2673 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002674
John W. Linvilleece550d2010-07-28 16:41:06 -04002675 survey->channel = conf->channel;
2676 survey->filled = SURVEY_INFO_NOISE_DBM;
2677 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002678
John W. Linvilleece550d2010-07-28 16:41:06 -04002679 return 0;
2680}
2681
Arik Nemtsov409622e2011-02-23 00:22:29 +02002682static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002683 struct ieee80211_sta *sta,
2684 u8 *hlid)
2685{
2686 struct wl1271_station *wl_sta;
2687 int id;
2688
2689 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2690 if (id >= AP_MAX_STATIONS) {
2691 wl1271_warning("could not allocate HLID - too much stations");
2692 return -EBUSY;
2693 }
2694
2695 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002696 __set_bit(id, wl->ap_hlid_map);
2697 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2698 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002699 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002700 return 0;
2701}
2702
Arik Nemtsov409622e2011-02-23 00:22:29 +02002703static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002704{
2705 int id = hlid - WL1271_AP_STA_HLID_START;
2706
Arik Nemtsov409622e2011-02-23 00:22:29 +02002707 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2708 return;
2709
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002710 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002711 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002712 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002713 __clear_bit(hlid, &wl->ap_ps_map);
2714 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002715}
2716
2717static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2718 struct ieee80211_vif *vif,
2719 struct ieee80211_sta *sta)
2720{
2721 struct wl1271 *wl = hw->priv;
2722 int ret = 0;
2723 u8 hlid;
2724
2725 mutex_lock(&wl->mutex);
2726
2727 if (unlikely(wl->state == WL1271_STATE_OFF))
2728 goto out;
2729
2730 if (wl->bss_type != BSS_TYPE_AP_BSS)
2731 goto out;
2732
2733 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2734
Arik Nemtsov409622e2011-02-23 00:22:29 +02002735 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002736 if (ret < 0)
2737 goto out;
2738
2739 ret = wl1271_ps_elp_wakeup(wl, false);
2740 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002741 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002742
2743 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2744 if (ret < 0)
2745 goto out_sleep;
2746
2747out_sleep:
2748 wl1271_ps_elp_sleep(wl);
2749
Arik Nemtsov409622e2011-02-23 00:22:29 +02002750out_free_sta:
2751 if (ret < 0)
2752 wl1271_free_sta(wl, hlid);
2753
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002754out:
2755 mutex_unlock(&wl->mutex);
2756 return ret;
2757}
2758
2759static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2760 struct ieee80211_vif *vif,
2761 struct ieee80211_sta *sta)
2762{
2763 struct wl1271 *wl = hw->priv;
2764 struct wl1271_station *wl_sta;
2765 int ret = 0, id;
2766
2767 mutex_lock(&wl->mutex);
2768
2769 if (unlikely(wl->state == WL1271_STATE_OFF))
2770 goto out;
2771
2772 if (wl->bss_type != BSS_TYPE_AP_BSS)
2773 goto out;
2774
2775 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2776
2777 wl_sta = (struct wl1271_station *)sta->drv_priv;
2778 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2779 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2780 goto out;
2781
2782 ret = wl1271_ps_elp_wakeup(wl, false);
2783 if (ret < 0)
2784 goto out;
2785
2786 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2787 if (ret < 0)
2788 goto out_sleep;
2789
Arik Nemtsov409622e2011-02-23 00:22:29 +02002790 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002791
2792out_sleep:
2793 wl1271_ps_elp_sleep(wl);
2794
2795out:
2796 mutex_unlock(&wl->mutex);
2797 return ret;
2798}
2799
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002800int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002801 enum ieee80211_ampdu_mlme_action action,
2802 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2803 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002804{
2805 struct wl1271 *wl = hw->priv;
2806 int ret;
2807
2808 mutex_lock(&wl->mutex);
2809
2810 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2811 ret = -EAGAIN;
2812 goto out;
2813 }
2814
2815 ret = wl1271_ps_elp_wakeup(wl, false);
2816 if (ret < 0)
2817 goto out;
2818
2819 switch (action) {
2820 case IEEE80211_AMPDU_RX_START:
2821 if (wl->ba_support) {
2822 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2823 true);
2824 if (!ret)
2825 wl->ba_rx_bitmap |= BIT(tid);
2826 } else {
2827 ret = -ENOTSUPP;
2828 }
2829 break;
2830
2831 case IEEE80211_AMPDU_RX_STOP:
2832 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2833 if (!ret)
2834 wl->ba_rx_bitmap &= ~BIT(tid);
2835 break;
2836
2837 /*
2838 * The BA initiator session management in FW independently.
2839 * Falling break here on purpose for all TX APDU commands.
2840 */
2841 case IEEE80211_AMPDU_TX_START:
2842 case IEEE80211_AMPDU_TX_STOP:
2843 case IEEE80211_AMPDU_TX_OPERATIONAL:
2844 ret = -EINVAL;
2845 break;
2846
2847 default:
2848 wl1271_error("Incorrect ampdu action id=%x\n", action);
2849 ret = -EINVAL;
2850 }
2851
2852 wl1271_ps_elp_sleep(wl);
2853
2854out:
2855 mutex_unlock(&wl->mutex);
2856
2857 return ret;
2858}
2859
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002860/* can't be const, mac80211 writes to this */
2861static struct ieee80211_rate wl1271_rates[] = {
2862 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002863 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2864 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002865 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002866 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2867 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002868 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2869 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002870 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2871 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002872 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2873 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002874 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2875 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002876 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2877 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002878 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2879 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002880 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002881 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2882 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002883 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002884 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2885 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002886 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002887 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2888 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002889 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002890 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2891 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002892 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002893 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2894 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002895 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002896 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2897 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002899 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2900 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002901};
2902
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002903/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002905 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002906 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002907 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2908 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2909 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002910 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002911 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2912 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2913 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002914 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002915 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2916 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2917 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002918 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002919};
2920
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002921/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002922static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002923 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002924 7, /* CONF_HW_RXTX_RATE_MCS7 */
2925 6, /* CONF_HW_RXTX_RATE_MCS6 */
2926 5, /* CONF_HW_RXTX_RATE_MCS5 */
2927 4, /* CONF_HW_RXTX_RATE_MCS4 */
2928 3, /* CONF_HW_RXTX_RATE_MCS3 */
2929 2, /* CONF_HW_RXTX_RATE_MCS2 */
2930 1, /* CONF_HW_RXTX_RATE_MCS1 */
2931 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002932
2933 11, /* CONF_HW_RXTX_RATE_54 */
2934 10, /* CONF_HW_RXTX_RATE_48 */
2935 9, /* CONF_HW_RXTX_RATE_36 */
2936 8, /* CONF_HW_RXTX_RATE_24 */
2937
2938 /* TI-specific rate */
2939 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2940
2941 7, /* CONF_HW_RXTX_RATE_18 */
2942 6, /* CONF_HW_RXTX_RATE_12 */
2943 3, /* CONF_HW_RXTX_RATE_11 */
2944 5, /* CONF_HW_RXTX_RATE_9 */
2945 4, /* CONF_HW_RXTX_RATE_6 */
2946 2, /* CONF_HW_RXTX_RATE_5_5 */
2947 1, /* CONF_HW_RXTX_RATE_2 */
2948 0 /* CONF_HW_RXTX_RATE_1 */
2949};
2950
Shahar Levie8b03a22010-10-13 16:09:39 +02002951/* 11n STA capabilities */
2952#define HW_RX_HIGHEST_RATE 72
2953
Shahar Levi00d20102010-11-08 11:20:10 +00002954#ifdef CONFIG_WL12XX_HT
2955#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002956 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2957 .ht_supported = true, \
2958 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2959 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2960 .mcs = { \
2961 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2962 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2963 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2964 }, \
2965}
Shahar Levi18357852010-10-13 16:09:41 +02002966#else
Shahar Levi00d20102010-11-08 11:20:10 +00002967#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002968 .ht_supported = false, \
2969}
2970#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972/* can't be const, mac80211 writes to this */
2973static struct ieee80211_supported_band wl1271_band_2ghz = {
2974 .channels = wl1271_channels,
2975 .n_channels = ARRAY_SIZE(wl1271_channels),
2976 .bitrates = wl1271_rates,
2977 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002978 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979};
2980
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002981/* 5 GHz data rates for WL1273 */
2982static struct ieee80211_rate wl1271_rates_5ghz[] = {
2983 { .bitrate = 60,
2984 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2985 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2986 { .bitrate = 90,
2987 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2988 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2989 { .bitrate = 120,
2990 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2991 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2992 { .bitrate = 180,
2993 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2994 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2995 { .bitrate = 240,
2996 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2997 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2998 { .bitrate = 360,
2999 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3000 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3001 { .bitrate = 480,
3002 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3003 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3004 { .bitrate = 540,
3005 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3006 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3007};
3008
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003009/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003010static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003011 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003012 { .hw_value = 8, .center_freq = 5040},
3013 { .hw_value = 9, .center_freq = 5045},
3014 { .hw_value = 11, .center_freq = 5055},
3015 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003016 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003017 { .hw_value = 34, .center_freq = 5170},
3018 { .hw_value = 36, .center_freq = 5180},
3019 { .hw_value = 38, .center_freq = 5190},
3020 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003021 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003022 { .hw_value = 44, .center_freq = 5220},
3023 { .hw_value = 46, .center_freq = 5230},
3024 { .hw_value = 48, .center_freq = 5240},
3025 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003026 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003027 { .hw_value = 60, .center_freq = 5300},
3028 { .hw_value = 64, .center_freq = 5320},
3029 { .hw_value = 100, .center_freq = 5500},
3030 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003031 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003032 { .hw_value = 112, .center_freq = 5560},
3033 { .hw_value = 116, .center_freq = 5580},
3034 { .hw_value = 120, .center_freq = 5600},
3035 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003036 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003037 { .hw_value = 132, .center_freq = 5660},
3038 { .hw_value = 136, .center_freq = 5680},
3039 { .hw_value = 140, .center_freq = 5700},
3040 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003041 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003042 { .hw_value = 157, .center_freq = 5785},
3043 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003044 { .hw_value = 165, .center_freq = 5825},
3045};
3046
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003047/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003048static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003049 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003050 7, /* CONF_HW_RXTX_RATE_MCS7 */
3051 6, /* CONF_HW_RXTX_RATE_MCS6 */
3052 5, /* CONF_HW_RXTX_RATE_MCS5 */
3053 4, /* CONF_HW_RXTX_RATE_MCS4 */
3054 3, /* CONF_HW_RXTX_RATE_MCS3 */
3055 2, /* CONF_HW_RXTX_RATE_MCS2 */
3056 1, /* CONF_HW_RXTX_RATE_MCS1 */
3057 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003058
3059 7, /* CONF_HW_RXTX_RATE_54 */
3060 6, /* CONF_HW_RXTX_RATE_48 */
3061 5, /* CONF_HW_RXTX_RATE_36 */
3062 4, /* CONF_HW_RXTX_RATE_24 */
3063
3064 /* TI-specific rate */
3065 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3066
3067 3, /* CONF_HW_RXTX_RATE_18 */
3068 2, /* CONF_HW_RXTX_RATE_12 */
3069 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3070 1, /* CONF_HW_RXTX_RATE_9 */
3071 0, /* CONF_HW_RXTX_RATE_6 */
3072 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3073 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3074 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3075};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003076
3077static struct ieee80211_supported_band wl1271_band_5ghz = {
3078 .channels = wl1271_channels_5ghz,
3079 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3080 .bitrates = wl1271_rates_5ghz,
3081 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003082 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003083};
3084
Tobias Klausera0ea9492010-05-20 10:38:11 +02003085static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003086 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3087 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3088};
3089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090static const struct ieee80211_ops wl1271_ops = {
3091 .start = wl1271_op_start,
3092 .stop = wl1271_op_stop,
3093 .add_interface = wl1271_op_add_interface,
3094 .remove_interface = wl1271_op_remove_interface,
3095 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003096 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003097 .configure_filter = wl1271_op_configure_filter,
3098 .tx = wl1271_op_tx,
3099 .set_key = wl1271_op_set_key,
3100 .hw_scan = wl1271_op_hw_scan,
3101 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003102 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003103 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003104 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003105 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003106 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003107 .sta_add = wl1271_op_sta_add,
3108 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003109 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003110 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111};
3112
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003113
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003114u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003115{
3116 u8 idx;
3117
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003118 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003119
3120 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3121 wl1271_error("Illegal RX rate from HW: %d", rate);
3122 return 0;
3123 }
3124
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003125 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003126 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3127 wl1271_error("Unsupported RX rate from HW: %d", rate);
3128 return 0;
3129 }
3130
3131 return idx;
3132}
3133
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003134static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3135 struct device_attribute *attr,
3136 char *buf)
3137{
3138 struct wl1271 *wl = dev_get_drvdata(dev);
3139 ssize_t len;
3140
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003141 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003142
3143 mutex_lock(&wl->mutex);
3144 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3145 wl->sg_enabled);
3146 mutex_unlock(&wl->mutex);
3147
3148 return len;
3149
3150}
3151
3152static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3153 struct device_attribute *attr,
3154 const char *buf, size_t count)
3155{
3156 struct wl1271 *wl = dev_get_drvdata(dev);
3157 unsigned long res;
3158 int ret;
3159
3160 ret = strict_strtoul(buf, 10, &res);
3161
3162 if (ret < 0) {
3163 wl1271_warning("incorrect value written to bt_coex_mode");
3164 return count;
3165 }
3166
3167 mutex_lock(&wl->mutex);
3168
3169 res = !!res;
3170
3171 if (res == wl->sg_enabled)
3172 goto out;
3173
3174 wl->sg_enabled = res;
3175
3176 if (wl->state == WL1271_STATE_OFF)
3177 goto out;
3178
3179 ret = wl1271_ps_elp_wakeup(wl, false);
3180 if (ret < 0)
3181 goto out;
3182
3183 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3184 wl1271_ps_elp_sleep(wl);
3185
3186 out:
3187 mutex_unlock(&wl->mutex);
3188 return count;
3189}
3190
3191static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3192 wl1271_sysfs_show_bt_coex_state,
3193 wl1271_sysfs_store_bt_coex_state);
3194
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003195static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3196 struct device_attribute *attr,
3197 char *buf)
3198{
3199 struct wl1271 *wl = dev_get_drvdata(dev);
3200 ssize_t len;
3201
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003202 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003203
3204 mutex_lock(&wl->mutex);
3205 if (wl->hw_pg_ver >= 0)
3206 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3207 else
3208 len = snprintf(buf, len, "n/a\n");
3209 mutex_unlock(&wl->mutex);
3210
3211 return len;
3212}
3213
3214static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3215 wl1271_sysfs_show_hw_pg_ver, NULL);
3216
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003217int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218{
3219 int ret;
3220
3221 if (wl->mac80211_registered)
3222 return 0;
3223
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003224 ret = wl1271_fetch_nvs(wl);
3225 if (ret == 0) {
3226 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3227
3228 wl->mac_addr[0] = nvs_ptr[11];
3229 wl->mac_addr[1] = nvs_ptr[10];
3230 wl->mac_addr[2] = nvs_ptr[6];
3231 wl->mac_addr[3] = nvs_ptr[5];
3232 wl->mac_addr[4] = nvs_ptr[4];
3233 wl->mac_addr[5] = nvs_ptr[3];
3234 }
3235
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3237
3238 ret = ieee80211_register_hw(wl->hw);
3239 if (ret < 0) {
3240 wl1271_error("unable to register mac80211 hw: %d", ret);
3241 return ret;
3242 }
3243
3244 wl->mac80211_registered = true;
3245
Eliad Pellerd60080a2010-11-24 12:53:16 +02003246 wl1271_debugfs_init(wl);
3247
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003248 register_netdevice_notifier(&wl1271_dev_notifier);
3249
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003250 wl1271_notice("loaded");
3251
3252 return 0;
3253}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003254EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003256void wl1271_unregister_hw(struct wl1271 *wl)
3257{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003258 if (wl->state == WL1271_STATE_PLT)
3259 __wl1271_plt_stop(wl);
3260
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003261 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003262 ieee80211_unregister_hw(wl->hw);
3263 wl->mac80211_registered = false;
3264
3265}
3266EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3267
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003268int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003269{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003270 static const u32 cipher_suites[] = {
3271 WLAN_CIPHER_SUITE_WEP40,
3272 WLAN_CIPHER_SUITE_WEP104,
3273 WLAN_CIPHER_SUITE_TKIP,
3274 WLAN_CIPHER_SUITE_CCMP,
3275 WL1271_CIPHER_SUITE_GEM,
3276 };
3277
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003278 /* The tx descriptor buffer and the TKIP space. */
3279 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3280 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003281
3282 /* unit us */
3283 /* FIXME: find a proper value */
3284 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003285 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003286
3287 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003288 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003289 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003290 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003291 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003292 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003293 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003294 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3295 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003296
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003297 wl->hw->wiphy->cipher_suites = cipher_suites;
3298 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3299
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003300 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003301 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003303 /*
3304 * Maximum length of elements in scanning probe request templates
3305 * should be the maximum length possible for a template, without
3306 * the IEEE80211 header of the template
3307 */
3308 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3309 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003310
3311 /*
3312 * We keep local copies of the band structs because we need to
3313 * modify them on a per-device basis.
3314 */
3315 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3316 sizeof(wl1271_band_2ghz));
3317 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3318 sizeof(wl1271_band_5ghz));
3319
3320 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3321 &wl->bands[IEEE80211_BAND_2GHZ];
3322 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3323 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003324
Kalle Valo12bd8942010-03-18 12:26:33 +02003325 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003326 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003327
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003328 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3329
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003330 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003332 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3333
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003334 wl->hw->max_rx_aggregation_subframes = 8;
3335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003336 return 0;
3337}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003338EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003339
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003341
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003342struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003343{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003344 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003345 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003347 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003348 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003349
3350 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3351 if (!hw) {
3352 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003353 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003354 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003355 }
3356
Julia Lawall929ebd32010-05-15 23:16:39 +02003357 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003358 if (!plat_dev) {
3359 wl1271_error("could not allocate platform_device");
3360 ret = -ENOMEM;
3361 goto err_plat_alloc;
3362 }
3363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003364 wl = hw->priv;
3365 memset(wl, 0, sizeof(*wl));
3366
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003367 INIT_LIST_HEAD(&wl->list);
3368
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003369 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003370 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003371
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003372 for (i = 0; i < NUM_TX_QUEUES; i++)
3373 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003374
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003375 for (i = 0; i < NUM_TX_QUEUES; i++)
3376 for (j = 0; j < AP_MAX_LINKS; j++)
3377 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3378
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003379 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003380 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003381 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3382 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3383 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3384 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003385 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003386 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003387 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003388 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003389 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3390 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003391 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003392 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003393 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003394 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003395 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003396 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003397 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003398 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003399 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003400 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003401 wl->bss_type = MAX_BSS_TYPE;
3402 wl->set_bss_type = MAX_BSS_TYPE;
3403 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003404 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003405 wl->ap_ps_map = 0;
3406 wl->ap_fw_ps_map = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003407
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003408 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003409 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003410 wl->tx_frames[i] = NULL;
3411
3412 spin_lock_init(&wl->wl_lock);
3413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003414 wl->state = WL1271_STATE_OFF;
3415 mutex_init(&wl->mutex);
3416
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003417 /* Apply default driver configuration. */
3418 wl1271_conf_init(wl);
3419
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003420 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3421 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3422 if (!wl->aggr_buf) {
3423 ret = -ENOMEM;
3424 goto err_hw;
3425 }
3426
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003427 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003428 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003429 if (ret) {
3430 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003431 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003432 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003433 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003434
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003435 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003436 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003437 if (ret < 0) {
3438 wl1271_error("failed to create sysfs file bt_coex_state");
3439 goto err_platform;
3440 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003441
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003442 /* Create sysfs file to get HW PG version */
3443 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3444 if (ret < 0) {
3445 wl1271_error("failed to create sysfs file hw_pg_ver");
3446 goto err_bt_coex_state;
3447 }
3448
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003449 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003450
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003451err_bt_coex_state:
3452 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3453
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003454err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003455 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003456
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003457err_aggr:
3458 free_pages((unsigned long)wl->aggr_buf, order);
3459
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003460err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003461 wl1271_debugfs_exit(wl);
3462 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003463
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003464err_plat_alloc:
3465 ieee80211_free_hw(hw);
3466
3467err_hw_alloc:
3468
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003469 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003470}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003471EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003472
3473int wl1271_free_hw(struct wl1271 *wl)
3474{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003475 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003476 free_pages((unsigned long)wl->aggr_buf,
3477 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003478 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003479
3480 wl1271_debugfs_exit(wl);
3481
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003482 vfree(wl->fw);
3483 wl->fw = NULL;
3484 kfree(wl->nvs);
3485 wl->nvs = NULL;
3486
3487 kfree(wl->fw_status);
3488 kfree(wl->tx_res_if);
3489
3490 ieee80211_free_hw(wl->hw);
3491
3492 return 0;
3493}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003494EXPORT_SYMBOL_GPL(wl1271_free_hw);
3495
Guy Eilam491bbd62011-01-12 10:33:29 +01003496u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003497EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003498module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003499MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3500
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003501MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003502MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003503MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");