blob: f408c5a84cc912ff65784e0e6cbb6534499b05ca [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
Ido Yariva6208652011-03-01 15:14:41 +0200377 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300378 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
Ido Yariva6208652011-03-01 15:14:41 +0200638static void wl1271_flush_deferred_work(struct wl1271 *wl)
639{
640 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200641
Ido Yariva6208652011-03-01 15:14:41 +0200642 /* Pass all received frames to the network stack */
643 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
644 ieee80211_rx_ni(wl->hw, skb);
645
646 /* Return sent skbs to the network stack */
647 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
648 ieee80211_tx_status(wl->hw, skb);
649}
650
651static void wl1271_netstack_work(struct work_struct *work)
652{
653 struct wl1271 *wl =
654 container_of(work, struct wl1271, netstack_work);
655
656 do {
657 wl1271_flush_deferred_work(wl);
658 } while (skb_queue_len(&wl->deferred_rx_queue));
659}
660
661#define WL1271_IRQ_MAX_LOOPS 256
662
663irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300666 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200667 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200668 struct wl1271 *wl = (struct wl1271 *)cookie;
669 bool done = false;
670 unsigned int defer_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671
672 mutex_lock(&wl->mutex);
673
674 wl1271_debug(DEBUG_IRQ, "IRQ work");
675
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200676 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 goto out;
678
Ido Yariva6208652011-03-01 15:14:41 +0200679 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 if (ret < 0)
681 goto out;
682
Ido Yariva6208652011-03-01 15:14:41 +0200683 while (!done && loopcount--) {
684 /*
685 * In order to avoid a race with the hardirq, clear the flag
686 * before acknowledging the chip. Since the mutex is held,
687 * wl1271_ps_elp_wakeup cannot be called concurrently.
688 */
689 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
690 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200691
692 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200693 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200694 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200695 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200696 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200697 continue;
698 }
699
Eliad Pellerccc83b02010-10-27 14:09:57 +0200700 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
701 wl1271_error("watchdog interrupt received! "
702 "starting recovery.");
703 ieee80211_queue_work(wl->hw, &wl->recovery_work);
704
705 /* restarting the chip. ignore any other interrupt. */
706 goto out;
707 }
708
Ido Yariva6208652011-03-01 15:14:41 +0200709 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200710 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
711
Ido Yariv8aad2462011-03-01 15:14:38 +0200712 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200713
Ido Yariva5225502010-10-12 14:49:10 +0200714 /* Check if any tx blocks were freed */
715 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200716 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200717 /*
718 * In order to avoid starvation of the TX path,
719 * call the work function directly.
720 */
721 wl1271_tx_work_locked(wl);
722 }
723
Ido Yariv8aad2462011-03-01 15:14:38 +0200724 /* check for tx results */
725 if (wl->fw_status->common.tx_results_counter !=
726 (wl->tx_results_count & 0xff))
727 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200728
729 /* Make sure the deferred queues don't get too long */
730 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
731 skb_queue_len(&wl->deferred_rx_queue);
732 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
733 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200734 }
735
736 if (intr & WL1271_ACX_INTR_EVENT_A) {
737 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
738 wl1271_event_handle(wl, 0);
739 }
740
741 if (intr & WL1271_ACX_INTR_EVENT_B) {
742 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
743 wl1271_event_handle(wl, 1);
744 }
745
746 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
747 wl1271_debug(DEBUG_IRQ,
748 "WL1271_ACX_INTR_INIT_COMPLETE");
749
750 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
751 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752 }
753
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 wl1271_ps_elp_sleep(wl);
755
756out:
757 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200758
759 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760}
Ido Yariva6208652011-03-01 15:14:41 +0200761EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763static int wl1271_fetch_firmware(struct wl1271 *wl)
764{
765 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200766 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767 int ret;
768
Arik Nemtsov166d5042010-10-16 21:44:57 +0200769 switch (wl->bss_type) {
770 case BSS_TYPE_AP_BSS:
771 fw_name = WL1271_AP_FW_NAME;
772 break;
773 case BSS_TYPE_IBSS:
774 case BSS_TYPE_STA_BSS:
775 fw_name = WL1271_FW_NAME;
776 break;
777 default:
778 wl1271_error("no compatible firmware for bss_type %d",
779 wl->bss_type);
780 return -EINVAL;
781 }
782
783 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
784
785 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786
787 if (ret < 0) {
788 wl1271_error("could not get firmware: %d", ret);
789 return ret;
790 }
791
792 if (fw->size % 4) {
793 wl1271_error("firmware size is not multiple of 32 bits: %zu",
794 fw->size);
795 ret = -EILSEQ;
796 goto out;
797 }
798
Arik Nemtsov166d5042010-10-16 21:44:57 +0200799 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300801 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802
803 if (!wl->fw) {
804 wl1271_error("could not allocate memory for the firmware");
805 ret = -ENOMEM;
806 goto out;
807 }
808
809 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200810 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300811 ret = 0;
812
813out:
814 release_firmware(fw);
815
816 return ret;
817}
818
819static int wl1271_fetch_nvs(struct wl1271 *wl)
820{
821 const struct firmware *fw;
822 int ret;
823
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200824 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300825
826 if (ret < 0) {
827 wl1271_error("could not get nvs file: %d", ret);
828 return ret;
829 }
830
Julia Lawall929ebd32010-05-15 23:16:39 +0200831 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
833 if (!wl->nvs) {
834 wl1271_error("could not allocate memory for the nvs file");
835 ret = -ENOMEM;
836 goto out;
837 }
838
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200839 wl->nvs_len = fw->size;
840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841out:
842 release_firmware(fw);
843
844 return ret;
845}
846
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200847static void wl1271_recovery_work(struct work_struct *work)
848{
849 struct wl1271 *wl =
850 container_of(work, struct wl1271, recovery_work);
851
852 mutex_lock(&wl->mutex);
853
854 if (wl->state != WL1271_STATE_ON)
855 goto out;
856
857 wl1271_info("Hardware recovery in progress.");
858
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200859 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
860 ieee80211_connection_loss(wl->vif);
861
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200862 /* reboot the chipset */
863 __wl1271_op_remove_interface(wl);
864 ieee80211_restart_hw(wl->hw);
865
866out:
867 mutex_unlock(&wl->mutex);
868}
869
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300870static void wl1271_fw_wakeup(struct wl1271 *wl)
871{
872 u32 elp_reg;
873
874 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300875 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876}
877
878static int wl1271_setup(struct wl1271 *wl)
879{
880 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
881 if (!wl->fw_status)
882 return -ENOMEM;
883
884 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
885 if (!wl->tx_res_if) {
886 kfree(wl->fw_status);
887 return -ENOMEM;
888 }
889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890 return 0;
891}
892
893static int wl1271_chip_wakeup(struct wl1271 *wl)
894{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300895 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300896 int ret = 0;
897
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200898 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200899 ret = wl1271_power_on(wl);
900 if (ret < 0)
901 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200903 wl1271_io_reset(wl);
904 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905
906 /* We don't need a real memory partition here, because we only want
907 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300908 memset(&partition, 0, sizeof(partition));
909 partition.reg.start = REGISTERS_BASE;
910 partition.reg.size = REGISTERS_DOWN_SIZE;
911 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912
913 /* ELP module wake up */
914 wl1271_fw_wakeup(wl);
915
916 /* whal_FwCtrl_BootSm() */
917
918 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200919 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300920
921 /* 1. check if chip id is valid */
922
923 switch (wl->chip.id) {
924 case CHIP_ID_1271_PG10:
925 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
926 wl->chip.id);
927
928 ret = wl1271_setup(wl);
929 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200930 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 break;
932 case CHIP_ID_1271_PG20:
933 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
934 wl->chip.id);
935
936 ret = wl1271_setup(wl);
937 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200938 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 break;
940 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200941 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200943 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 }
945
Arik Nemtsov166d5042010-10-16 21:44:57 +0200946 /* Make sure the firmware type matches the BSS type */
947 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 ret = wl1271_fetch_firmware(wl);
949 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200950 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951 }
952
953 /* No NVS from netlink, try to get it from the filesystem */
954 if (wl->nvs == NULL) {
955 ret = wl1271_fetch_nvs(wl);
956 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200957 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 }
959
960out:
961 return ret;
962}
963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964int wl1271_plt_start(struct wl1271 *wl)
965{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200966 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967 int ret;
968
969 mutex_lock(&wl->mutex);
970
971 wl1271_notice("power up");
972
973 if (wl->state != WL1271_STATE_OFF) {
974 wl1271_error("cannot go into PLT state because not "
975 "in off state: %d", wl->state);
976 ret = -EBUSY;
977 goto out;
978 }
979
Arik Nemtsov166d5042010-10-16 21:44:57 +0200980 wl->bss_type = BSS_TYPE_STA_BSS;
981
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200982 while (retries) {
983 retries--;
984 ret = wl1271_chip_wakeup(wl);
985 if (ret < 0)
986 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988 ret = wl1271_boot(wl);
989 if (ret < 0)
990 goto power_off;
991
992 ret = wl1271_plt_init(wl);
993 if (ret < 0)
994 goto irq_disable;
995
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200996 wl->state = WL1271_STATE_PLT;
997 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100998 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 goto out;
1000
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001001irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001002 mutex_unlock(&wl->mutex);
1003 /* Unlocking the mutex in the middle of handling is
1004 inherently unsafe. In this case we deem it safe to do,
1005 because we need to let any possibly pending IRQ out of
1006 the system (and while we are WL1271_STATE_OFF the IRQ
1007 work function will not do anything.) Also, any other
1008 possible concurrent operations will fail due to the
1009 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001010 wl1271_disable_interrupts(wl);
1011 wl1271_flush_deferred_work(wl);
1012 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001013 mutex_lock(&wl->mutex);
1014power_off:
1015 wl1271_power_off(wl);
1016 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001018 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1019 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020out:
1021 mutex_unlock(&wl->mutex);
1022
1023 return ret;
1024}
1025
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001026int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027{
1028 int ret = 0;
1029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 wl1271_notice("power down");
1031
1032 if (wl->state != WL1271_STATE_PLT) {
1033 wl1271_error("cannot power down because not in PLT "
1034 "state: %d", wl->state);
1035 ret = -EBUSY;
1036 goto out;
1037 }
1038
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039 wl1271_power_off(wl);
1040
1041 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001042 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001045 wl1271_disable_interrupts(wl);
1046 wl1271_flush_deferred_work(wl);
1047 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001048 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001049 mutex_lock(&wl->mutex);
1050out:
1051 return ret;
1052}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001053
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001054int wl1271_plt_stop(struct wl1271 *wl)
1055{
1056 int ret;
1057
1058 mutex_lock(&wl->mutex);
1059 ret = __wl1271_plt_stop(wl);
1060 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 return ret;
1062}
1063
Johannes Berg7bb45682011-02-24 14:42:06 +01001064static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065{
1066 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001067 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001068 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001069 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001071 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001072 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001073
1074 /*
1075 * The workqueue is slow to process the tx_queue and we need stop
1076 * the queue here, otherwise the queue will get too long.
1077 */
1078 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1079 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1080 ieee80211_stop_queues(wl->hw);
1081 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1082 }
1083
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001084 spin_unlock_irqrestore(&wl->wl_lock, flags);
1085
1086 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001087 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001088 if (wl->bss_type == BSS_TYPE_AP_BSS) {
1089 hlid = wl1271_tx_get_hlid(skb);
1090 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1091 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1092 } else {
1093 skb_queue_tail(&wl->tx_queue[q], skb);
1094 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095
1096 /*
1097 * The chip specific setup must run before the first TX packet -
1098 * before that, the tx_work will not be initialized!
1099 */
1100
Ido Yariva5225502010-10-12 14:49:10 +02001101 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1102 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103}
1104
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001105static struct notifier_block wl1271_dev_notifier = {
1106 .notifier_call = wl1271_dev_notify,
1107};
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109static int wl1271_op_start(struct ieee80211_hw *hw)
1110{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001111 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1112
1113 /*
1114 * We have to delay the booting of the hardware because
1115 * we need to know the local MAC address before downloading and
1116 * initializing the firmware. The MAC address cannot be changed
1117 * after boot, and without the proper MAC address, the firmware
1118 * will not function properly.
1119 *
1120 * The MAC address is first known when the corresponding interface
1121 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001122 *
1123 * In addition, we currently have different firmwares for AP and managed
1124 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001125 */
1126
1127 return 0;
1128}
1129
1130static void wl1271_op_stop(struct ieee80211_hw *hw)
1131{
1132 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1133}
1134
1135static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1136 struct ieee80211_vif *vif)
1137{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001139 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001140 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001142 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001144 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1145 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146
1147 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001148 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001149 wl1271_debug(DEBUG_MAC80211,
1150 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001151 ret = -EBUSY;
1152 goto out;
1153 }
1154
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001155 switch (vif->type) {
1156 case NL80211_IFTYPE_STATION:
1157 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001158 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001159 break;
1160 case NL80211_IFTYPE_ADHOC:
1161 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001162 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001163 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001164 case NL80211_IFTYPE_AP:
1165 wl->bss_type = BSS_TYPE_AP_BSS;
1166 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001167 default:
1168 ret = -EOPNOTSUPP;
1169 goto out;
1170 }
1171
1172 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173
1174 if (wl->state != WL1271_STATE_OFF) {
1175 wl1271_error("cannot start because not in off state: %d",
1176 wl->state);
1177 ret = -EBUSY;
1178 goto out;
1179 }
1180
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001181 while (retries) {
1182 retries--;
1183 ret = wl1271_chip_wakeup(wl);
1184 if (ret < 0)
1185 goto power_off;
1186
1187 ret = wl1271_boot(wl);
1188 if (ret < 0)
1189 goto power_off;
1190
1191 ret = wl1271_hw_init(wl);
1192 if (ret < 0)
1193 goto irq_disable;
1194
Eliad Peller71125ab2010-10-28 21:46:43 +02001195 booted = true;
1196 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001197
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001198irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001199 mutex_unlock(&wl->mutex);
1200 /* Unlocking the mutex in the middle of handling is
1201 inherently unsafe. In this case we deem it safe to do,
1202 because we need to let any possibly pending IRQ out of
1203 the system (and while we are WL1271_STATE_OFF the IRQ
1204 work function will not do anything.) Also, any other
1205 possible concurrent operations will fail due to the
1206 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001207 wl1271_disable_interrupts(wl);
1208 wl1271_flush_deferred_work(wl);
1209 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001210 mutex_lock(&wl->mutex);
1211power_off:
1212 wl1271_power_off(wl);
1213 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214
Eliad Peller71125ab2010-10-28 21:46:43 +02001215 if (!booted) {
1216 wl1271_error("firmware boot failed despite %d retries",
1217 WL1271_BOOT_RETRIES);
1218 goto out;
1219 }
1220
1221 wl->vif = vif;
1222 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001223 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001224
1225 /* update hw/fw version info in wiphy struct */
1226 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001227 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001228 sizeof(wiphy->fw_version));
1229
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001230 /*
1231 * Now we know if 11a is supported (info from the NVS), so disable
1232 * 11a channels if not supported
1233 */
1234 if (!wl->enable_11a)
1235 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1236
1237 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1238 wl->enable_11a ? "" : "not ");
1239
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001240out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241 mutex_unlock(&wl->mutex);
1242
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001243 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001244 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001245
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246 return ret;
1247}
1248
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001249static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251 int i;
1252
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001253 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001255 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001257 list_del(&wl->list);
1258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259 WARN_ON(wl->state != WL1271_STATE_ON);
1260
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001261 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001262 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001263 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001264
Luciano Coelho08688d62010-07-08 17:50:07 +03001265 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001266 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1267 kfree(wl->scan.scanned_ch);
1268 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001269 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001270 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271 }
1272
1273 wl->state = WL1271_STATE_OFF;
1274
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275 mutex_unlock(&wl->mutex);
1276
Ido Yariva6208652011-03-01 15:14:41 +02001277 wl1271_disable_interrupts(wl);
1278 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001279 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001280 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001282 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001283 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284
1285 mutex_lock(&wl->mutex);
1286
1287 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001288 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 wl1271_power_off(wl);
1290
1291 memset(wl->bssid, 0, ETH_ALEN);
1292 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1293 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001295 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001296 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297
1298 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001299 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1301 wl->tx_blocks_available = 0;
1302 wl->tx_results_count = 0;
1303 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001304 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001305 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 wl->time_offset = 0;
1307 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001308 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001309 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001310 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001311 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001312 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001313 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001314 wl->ap_fw_ps_map = 0;
1315 wl->ap_ps_map = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001316
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317 for (i = 0; i < NUM_TX_QUEUES; i++)
1318 wl->tx_blocks_freed[i] = 0;
1319
1320 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001321
1322 kfree(wl->fw_status);
1323 wl->fw_status = NULL;
1324 kfree(wl->tx_res_if);
1325 wl->tx_res_if = NULL;
1326 kfree(wl->target_mem_map);
1327 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001328}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001329
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001330static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1331 struct ieee80211_vif *vif)
1332{
1333 struct wl1271 *wl = hw->priv;
1334
1335 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001336 /*
1337 * wl->vif can be null here if someone shuts down the interface
1338 * just when hardware recovery has been started.
1339 */
1340 if (wl->vif) {
1341 WARN_ON(wl->vif != vif);
1342 __wl1271_op_remove_interface(wl);
1343 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001344
Juuso Oikarinen67353292010-11-18 15:19:02 +02001345 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001346 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347}
1348
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001349static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1350{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001351 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001352
1353 /* combine requested filters with current filter config */
1354 filters = wl->filters | filters;
1355
1356 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1357
1358 if (filters & FIF_PROMISC_IN_BSS) {
1359 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1360 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1361 wl->rx_config |= CFG_BSSID_FILTER_EN;
1362 }
1363 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1364 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1365 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1366 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1367 }
1368 if (filters & FIF_OTHER_BSS) {
1369 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1370 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1371 }
1372 if (filters & FIF_CONTROL) {
1373 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1374 wl->rx_filter |= CFG_RX_CTL_EN;
1375 }
1376 if (filters & FIF_FCSFAIL) {
1377 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1378 wl->rx_filter |= CFG_RX_FCS_ERROR;
1379 }
1380}
1381
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001382static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001383{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001384 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001385 /* we need to use a dummy BSSID for now */
1386 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1387 0xad, 0xbe, 0xef };
1388
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001389 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1390
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001391 /* pass through frames from all BSS */
1392 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1393
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001394 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001395 if (ret < 0)
1396 goto out;
1397
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001398 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001399
1400out:
1401 return ret;
1402}
1403
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001404static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001405{
1406 int ret;
1407
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001408 /*
1409 * One of the side effects of the JOIN command is that is clears
1410 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1411 * to a WPA/WPA2 access point will therefore kill the data-path.
1412 * Currently there is no supported scenario for JOIN during
1413 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1414 * must be handled somehow.
1415 *
1416 */
1417 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1418 wl1271_info("JOIN while associated.");
1419
1420 if (set_assoc)
1421 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1422
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001423 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1424 if (ret < 0)
1425 goto out;
1426
1427 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1428
1429 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1430 goto out;
1431
1432 /*
1433 * The join command disable the keep-alive mode, shut down its process,
1434 * and also clear the template config, so we need to reset it all after
1435 * the join. The acx_aid starts the keep-alive process, and the order
1436 * of the commands below is relevant.
1437 */
1438 ret = wl1271_acx_keep_alive_mode(wl, true);
1439 if (ret < 0)
1440 goto out;
1441
1442 ret = wl1271_acx_aid(wl, wl->aid);
1443 if (ret < 0)
1444 goto out;
1445
1446 ret = wl1271_cmd_build_klv_null_data(wl);
1447 if (ret < 0)
1448 goto out;
1449
1450 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1451 ACX_KEEP_ALIVE_TPL_VALID);
1452 if (ret < 0)
1453 goto out;
1454
1455out:
1456 return ret;
1457}
1458
1459static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001460{
1461 int ret;
1462
1463 /* to stop listening to a channel, we disconnect */
1464 ret = wl1271_cmd_disconnect(wl);
1465 if (ret < 0)
1466 goto out;
1467
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001468 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001469 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001470
1471 /* stop filterting packets based on bssid */
1472 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001473
1474out:
1475 return ret;
1476}
1477
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001478static void wl1271_set_band_rate(struct wl1271 *wl)
1479{
1480 if (wl->band == IEEE80211_BAND_2GHZ)
1481 wl->basic_rate_set = wl->conf.tx.basic_rate;
1482 else
1483 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1484}
1485
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001486static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001487{
1488 int ret;
1489
1490 if (idle) {
1491 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1492 ret = wl1271_unjoin(wl);
1493 if (ret < 0)
1494 goto out;
1495 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001496 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001497 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001498 if (ret < 0)
1499 goto out;
1500 ret = wl1271_acx_keep_alive_config(
1501 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1502 ACX_KEEP_ALIVE_TPL_INVALID);
1503 if (ret < 0)
1504 goto out;
1505 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1506 } else {
1507 /* increment the session counter */
1508 wl->session_counter++;
1509 if (wl->session_counter >= SESSION_COUNTER_MAX)
1510 wl->session_counter = 0;
1511 ret = wl1271_dummy_join(wl);
1512 if (ret < 0)
1513 goto out;
1514 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1515 }
1516
1517out:
1518 return ret;
1519}
1520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1522{
1523 struct wl1271 *wl = hw->priv;
1524 struct ieee80211_conf *conf = &hw->conf;
1525 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001526 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527
1528 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1529
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001530 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1531 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 channel,
1533 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001534 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001535 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1536 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001538 /*
1539 * mac80211 will go to idle nearly immediately after transmitting some
1540 * frames, such as the deauth. To make sure those frames reach the air,
1541 * wait here until the TX queue is fully flushed.
1542 */
1543 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1544 (conf->flags & IEEE80211_CONF_IDLE))
1545 wl1271_tx_flush(wl);
1546
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 mutex_lock(&wl->mutex);
1548
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001549 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1550 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001551 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001552 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001553
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001554 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1555
Ido Yariva6208652011-03-01 15:14:41 +02001556 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 if (ret < 0)
1558 goto out;
1559
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001560 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001561 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1562 ((wl->band != conf->channel->band) ||
1563 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001564 wl->band = conf->channel->band;
1565 wl->channel = channel;
1566
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001567 if (!is_ap) {
1568 /*
1569 * FIXME: the mac80211 should really provide a fixed
1570 * rate to use here. for now, just use the smallest
1571 * possible rate for the band as a fixed rate for
1572 * association frames and other control messages.
1573 */
1574 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1575 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001576
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001577 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1578 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001579 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001580 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001581 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001582
1583 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1584 ret = wl1271_join(wl, false);
1585 if (ret < 0)
1586 wl1271_warning("cmd join on channel "
1587 "failed %d", ret);
1588 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001589 }
1590 }
1591
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001592 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1593 ret = wl1271_sta_handle_idle(wl,
1594 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001595 if (ret < 0)
1596 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597 }
1598
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001599 /*
1600 * if mac80211 changes the PSM mode, make sure the mode is not
1601 * incorrectly changed after the pspoll failure active window.
1602 */
1603 if (changed & IEEE80211_CONF_CHANGE_PS)
1604 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1605
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001606 if (conf->flags & IEEE80211_CONF_PS &&
1607 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1608 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609
1610 /*
1611 * We enter PSM only if we're already associated.
1612 * If we're not, we'll enter it when joining an SSID,
1613 * through the bss_info_changed() hook.
1614 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001615 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001616 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001617 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001618 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001619 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001621 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001622 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001623
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001624 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001625
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001626 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001627 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001628 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001629 }
1630
1631 if (conf->power_level != wl->power_level) {
1632 ret = wl1271_acx_tx_power(wl, conf->power_level);
1633 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001634 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635
1636 wl->power_level = conf->power_level;
1637 }
1638
1639out_sleep:
1640 wl1271_ps_elp_sleep(wl);
1641
1642out:
1643 mutex_unlock(&wl->mutex);
1644
1645 return ret;
1646}
1647
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001648struct wl1271_filter_params {
1649 bool enabled;
1650 int mc_list_length;
1651 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1652};
1653
Jiri Pirko22bedad32010-04-01 21:22:57 +00001654static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1655 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001656{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001657 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001658 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001659 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001660
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001661 if (unlikely(wl->state == WL1271_STATE_OFF))
1662 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001663
Juuso Oikarinen74441132009-10-13 12:47:53 +03001664 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001665 if (!fp) {
1666 wl1271_error("Out of memory setting filters.");
1667 return 0;
1668 }
1669
1670 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001671 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001672 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1673 fp->enabled = false;
1674 } else {
1675 fp->enabled = true;
1676 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001677 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001678 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001679 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001680 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001681 }
1682
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001683 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001684}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001686#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1687 FIF_ALLMULTI | \
1688 FIF_FCSFAIL | \
1689 FIF_BCN_PRBRESP_PROMISC | \
1690 FIF_CONTROL | \
1691 FIF_OTHER_BSS)
1692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1694 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001695 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001697 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001699 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001700
Arik Nemtsov7d057862010-10-16 19:25:35 +02001701 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1702 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001703
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001704 mutex_lock(&wl->mutex);
1705
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001706 *total &= WL1271_SUPPORTED_FILTERS;
1707 changed &= WL1271_SUPPORTED_FILTERS;
1708
1709 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001710 goto out;
1711
Ido Yariva6208652011-03-01 15:14:41 +02001712 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001713 if (ret < 0)
1714 goto out;
1715
Arik Nemtsov7d057862010-10-16 19:25:35 +02001716 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1717 if (*total & FIF_ALLMULTI)
1718 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1719 else if (fp)
1720 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1721 fp->mc_list,
1722 fp->mc_list_length);
1723 if (ret < 0)
1724 goto out_sleep;
1725 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001727 /* determine, whether supported filter values have changed */
1728 if (changed == 0)
1729 goto out_sleep;
1730
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001731 /* configure filters */
1732 wl->filters = *total;
1733 wl1271_configure_filters(wl, 0);
1734
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001735 /* apply configured filters */
1736 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1737 if (ret < 0)
1738 goto out_sleep;
1739
1740out_sleep:
1741 wl1271_ps_elp_sleep(wl);
1742
1743out:
1744 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001745 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001746}
1747
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001748static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1749 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1750 u16 tx_seq_16)
1751{
1752 struct wl1271_ap_key *ap_key;
1753 int i;
1754
1755 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1756
1757 if (key_size > MAX_KEY_SIZE)
1758 return -EINVAL;
1759
1760 /*
1761 * Find next free entry in ap_keys. Also check we are not replacing
1762 * an existing key.
1763 */
1764 for (i = 0; i < MAX_NUM_KEYS; i++) {
1765 if (wl->recorded_ap_keys[i] == NULL)
1766 break;
1767
1768 if (wl->recorded_ap_keys[i]->id == id) {
1769 wl1271_warning("trying to record key replacement");
1770 return -EINVAL;
1771 }
1772 }
1773
1774 if (i == MAX_NUM_KEYS)
1775 return -EBUSY;
1776
1777 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1778 if (!ap_key)
1779 return -ENOMEM;
1780
1781 ap_key->id = id;
1782 ap_key->key_type = key_type;
1783 ap_key->key_size = key_size;
1784 memcpy(ap_key->key, key, key_size);
1785 ap_key->hlid = hlid;
1786 ap_key->tx_seq_32 = tx_seq_32;
1787 ap_key->tx_seq_16 = tx_seq_16;
1788
1789 wl->recorded_ap_keys[i] = ap_key;
1790 return 0;
1791}
1792
1793static void wl1271_free_ap_keys(struct wl1271 *wl)
1794{
1795 int i;
1796
1797 for (i = 0; i < MAX_NUM_KEYS; i++) {
1798 kfree(wl->recorded_ap_keys[i]);
1799 wl->recorded_ap_keys[i] = NULL;
1800 }
1801}
1802
1803static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1804{
1805 int i, ret = 0;
1806 struct wl1271_ap_key *key;
1807 bool wep_key_added = false;
1808
1809 for (i = 0; i < MAX_NUM_KEYS; i++) {
1810 if (wl->recorded_ap_keys[i] == NULL)
1811 break;
1812
1813 key = wl->recorded_ap_keys[i];
1814 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1815 key->id, key->key_type,
1816 key->key_size, key->key,
1817 key->hlid, key->tx_seq_32,
1818 key->tx_seq_16);
1819 if (ret < 0)
1820 goto out;
1821
1822 if (key->key_type == KEY_WEP)
1823 wep_key_added = true;
1824 }
1825
1826 if (wep_key_added) {
1827 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1828 if (ret < 0)
1829 goto out;
1830 }
1831
1832out:
1833 wl1271_free_ap_keys(wl);
1834 return ret;
1835}
1836
1837static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1838 u8 key_size, const u8 *key, u32 tx_seq_32,
1839 u16 tx_seq_16, struct ieee80211_sta *sta)
1840{
1841 int ret;
1842 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1843
1844 if (is_ap) {
1845 struct wl1271_station *wl_sta;
1846 u8 hlid;
1847
1848 if (sta) {
1849 wl_sta = (struct wl1271_station *)sta->drv_priv;
1850 hlid = wl_sta->hlid;
1851 } else {
1852 hlid = WL1271_AP_BROADCAST_HLID;
1853 }
1854
1855 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1856 /*
1857 * We do not support removing keys after AP shutdown.
1858 * Pretend we do to make mac80211 happy.
1859 */
1860 if (action != KEY_ADD_OR_REPLACE)
1861 return 0;
1862
1863 ret = wl1271_record_ap_key(wl, id,
1864 key_type, key_size,
1865 key, hlid, tx_seq_32,
1866 tx_seq_16);
1867 } else {
1868 ret = wl1271_cmd_set_ap_key(wl, action,
1869 id, key_type, key_size,
1870 key, hlid, tx_seq_32,
1871 tx_seq_16);
1872 }
1873
1874 if (ret < 0)
1875 return ret;
1876 } else {
1877 const u8 *addr;
1878 static const u8 bcast_addr[ETH_ALEN] = {
1879 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1880 };
1881
1882 addr = sta ? sta->addr : bcast_addr;
1883
1884 if (is_zero_ether_addr(addr)) {
1885 /* We dont support TX only encryption */
1886 return -EOPNOTSUPP;
1887 }
1888
1889 /* The wl1271 does not allow to remove unicast keys - they
1890 will be cleared automatically on next CMD_JOIN. Ignore the
1891 request silently, as we dont want the mac80211 to emit
1892 an error message. */
1893 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1894 return 0;
1895
1896 ret = wl1271_cmd_set_sta_key(wl, action,
1897 id, key_type, key_size,
1898 key, addr, tx_seq_32,
1899 tx_seq_16);
1900 if (ret < 0)
1901 return ret;
1902
1903 /* the default WEP key needs to be configured at least once */
1904 if (key_type == KEY_WEP) {
1905 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1906 wl->default_key);
1907 if (ret < 0)
1908 return ret;
1909 }
1910 }
1911
1912 return 0;
1913}
1914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1916 struct ieee80211_vif *vif,
1917 struct ieee80211_sta *sta,
1918 struct ieee80211_key_conf *key_conf)
1919{
1920 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001922 u32 tx_seq_32 = 0;
1923 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924 u8 key_type;
1925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1927
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001928 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001930 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 key_conf->keylen, key_conf->flags);
1932 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1933
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 mutex_lock(&wl->mutex);
1935
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001936 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1937 ret = -EAGAIN;
1938 goto out_unlock;
1939 }
1940
Ido Yariva6208652011-03-01 15:14:41 +02001941 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 if (ret < 0)
1943 goto out_unlock;
1944
Johannes Berg97359d12010-08-10 09:46:38 +02001945 switch (key_conf->cipher) {
1946 case WLAN_CIPHER_SUITE_WEP40:
1947 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 key_type = KEY_WEP;
1949
1950 key_conf->hw_key_idx = key_conf->keyidx;
1951 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001952 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 key_type = KEY_TKIP;
1954
1955 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001956 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1957 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001959 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960 key_type = KEY_AES;
1961
1962 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001963 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1964 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001966 case WL1271_CIPHER_SUITE_GEM:
1967 key_type = KEY_GEM;
1968 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1969 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1970 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001972 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973
1974 ret = -EOPNOTSUPP;
1975 goto out_sleep;
1976 }
1977
1978 switch (cmd) {
1979 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001980 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1981 key_conf->keyidx, key_type,
1982 key_conf->keylen, key_conf->key,
1983 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984 if (ret < 0) {
1985 wl1271_error("Could not add or replace key");
1986 goto out_sleep;
1987 }
1988 break;
1989
1990 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001991 ret = wl1271_set_key(wl, KEY_REMOVE,
1992 key_conf->keyidx, key_type,
1993 key_conf->keylen, key_conf->key,
1994 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995 if (ret < 0) {
1996 wl1271_error("Could not remove key");
1997 goto out_sleep;
1998 }
1999 break;
2000
2001 default:
2002 wl1271_error("Unsupported key cmd 0x%x", cmd);
2003 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 break;
2005 }
2006
2007out_sleep:
2008 wl1271_ps_elp_sleep(wl);
2009
2010out_unlock:
2011 mutex_unlock(&wl->mutex);
2012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013 return ret;
2014}
2015
2016static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002017 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 struct cfg80211_scan_request *req)
2019{
2020 struct wl1271 *wl = hw->priv;
2021 int ret;
2022 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002023 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002024
2025 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2026
2027 if (req->n_ssids) {
2028 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002029 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030 }
2031
2032 mutex_lock(&wl->mutex);
2033
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002034 if (wl->state == WL1271_STATE_OFF) {
2035 /*
2036 * We cannot return -EBUSY here because cfg80211 will expect
2037 * a call to ieee80211_scan_completed if we do - in this case
2038 * there won't be any call.
2039 */
2040 ret = -EAGAIN;
2041 goto out;
2042 }
2043
Ido Yariva6208652011-03-01 15:14:41 +02002044 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045 if (ret < 0)
2046 goto out;
2047
Luciano Coelho5924f892010-08-04 03:46:22 +03002048 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049
2050 wl1271_ps_elp_sleep(wl);
2051
2052out:
2053 mutex_unlock(&wl->mutex);
2054
2055 return ret;
2056}
2057
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002058static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2059{
2060 struct wl1271 *wl = hw->priv;
2061 int ret = 0;
2062
2063 mutex_lock(&wl->mutex);
2064
2065 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2066 ret = -EAGAIN;
2067 goto out;
2068 }
2069
Ido Yariva6208652011-03-01 15:14:41 +02002070 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002071 if (ret < 0)
2072 goto out;
2073
2074 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2075 if (ret < 0)
2076 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2077
2078 wl1271_ps_elp_sleep(wl);
2079
2080out:
2081 mutex_unlock(&wl->mutex);
2082
2083 return ret;
2084}
2085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2087{
2088 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002089 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002090
2091 mutex_lock(&wl->mutex);
2092
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002093 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2094 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002095 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002096 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002097
Ido Yariva6208652011-03-01 15:14:41 +02002098 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099 if (ret < 0)
2100 goto out;
2101
2102 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2103 if (ret < 0)
2104 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2105
2106 wl1271_ps_elp_sleep(wl);
2107
2108out:
2109 mutex_unlock(&wl->mutex);
2110
2111 return ret;
2112}
2113
Arik Nemtsove78a2872010-10-16 19:07:21 +02002114static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002115 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002116{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002117 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002118
2119 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002120 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002121 if (ptr[0] == WLAN_EID_SSID) {
2122 wl->ssid_len = ptr[1];
2123 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002124 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002125 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002126 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002127 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002128
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002129 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002130 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002131}
2132
Arik Nemtsove78a2872010-10-16 19:07:21 +02002133static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2134 struct ieee80211_bss_conf *bss_conf,
2135 u32 changed)
2136{
2137 int ret = 0;
2138
2139 if (changed & BSS_CHANGED_ERP_SLOT) {
2140 if (bss_conf->use_short_slot)
2141 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2142 else
2143 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2144 if (ret < 0) {
2145 wl1271_warning("Set slot time failed %d", ret);
2146 goto out;
2147 }
2148 }
2149
2150 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2151 if (bss_conf->use_short_preamble)
2152 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2153 else
2154 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2155 }
2156
2157 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2158 if (bss_conf->use_cts_prot)
2159 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2160 else
2161 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2162 if (ret < 0) {
2163 wl1271_warning("Set ctsprotect failed %d", ret);
2164 goto out;
2165 }
2166 }
2167
2168out:
2169 return ret;
2170}
2171
2172static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2173 struct ieee80211_vif *vif,
2174 struct ieee80211_bss_conf *bss_conf,
2175 u32 changed)
2176{
2177 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2178 int ret = 0;
2179
2180 if ((changed & BSS_CHANGED_BEACON_INT)) {
2181 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2182 bss_conf->beacon_int);
2183
2184 wl->beacon_int = bss_conf->beacon_int;
2185 }
2186
2187 if ((changed & BSS_CHANGED_BEACON)) {
2188 struct ieee80211_hdr *hdr;
2189 int ieoffset = offsetof(struct ieee80211_mgmt,
2190 u.beacon.variable);
2191 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2192 u16 tmpl_id;
2193
2194 if (!beacon)
2195 goto out;
2196
2197 wl1271_debug(DEBUG_MASTER, "beacon updated");
2198
2199 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2200 if (ret < 0) {
2201 dev_kfree_skb(beacon);
2202 goto out;
2203 }
2204 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2205 CMD_TEMPL_BEACON;
2206 ret = wl1271_cmd_template_set(wl, tmpl_id,
2207 beacon->data,
2208 beacon->len, 0,
2209 wl1271_tx_min_rate_get(wl));
2210 if (ret < 0) {
2211 dev_kfree_skb(beacon);
2212 goto out;
2213 }
2214
2215 hdr = (struct ieee80211_hdr *) beacon->data;
2216 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2217 IEEE80211_STYPE_PROBE_RESP);
2218
2219 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2220 CMD_TEMPL_PROBE_RESPONSE;
2221 ret = wl1271_cmd_template_set(wl,
2222 tmpl_id,
2223 beacon->data,
2224 beacon->len, 0,
2225 wl1271_tx_min_rate_get(wl));
2226 dev_kfree_skb(beacon);
2227 if (ret < 0)
2228 goto out;
2229 }
2230
2231out:
2232 return ret;
2233}
2234
2235/* AP mode changes */
2236static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002237 struct ieee80211_vif *vif,
2238 struct ieee80211_bss_conf *bss_conf,
2239 u32 changed)
2240{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002241 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002242
Arik Nemtsove78a2872010-10-16 19:07:21 +02002243 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2244 u32 rates = bss_conf->basic_rates;
2245 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002246
Arik Nemtsove78a2872010-10-16 19:07:21 +02002247 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2248 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2249 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2250 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251
Arik Nemtsove78a2872010-10-16 19:07:21 +02002252 /* update the AP management rate policy with the new rates */
2253 mgmt_rc.enabled_rates = wl->basic_rate_set;
2254 mgmt_rc.long_retry_limit = 10;
2255 mgmt_rc.short_retry_limit = 10;
2256 mgmt_rc.aflags = 0;
2257 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2258 ACX_TX_AP_MODE_MGMT_RATE);
2259 if (ret < 0) {
2260 wl1271_error("AP mgmt policy change failed %d", ret);
2261 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002262 }
2263 }
2264
Arik Nemtsove78a2872010-10-16 19:07:21 +02002265 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2266 if (ret < 0)
2267 goto out;
2268
2269 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2270 if (bss_conf->enable_beacon) {
2271 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2272 ret = wl1271_cmd_start_bss(wl);
2273 if (ret < 0)
2274 goto out;
2275
2276 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2277 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002278
2279 ret = wl1271_ap_init_hwenc(wl);
2280 if (ret < 0)
2281 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002282 }
2283 } else {
2284 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2285 ret = wl1271_cmd_stop_bss(wl);
2286 if (ret < 0)
2287 goto out;
2288
2289 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2290 wl1271_debug(DEBUG_AP, "stopped AP");
2291 }
2292 }
2293 }
2294
2295 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2296 if (ret < 0)
2297 goto out;
2298out:
2299 return;
2300}
2301
2302/* STA/IBSS mode changes */
2303static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2304 struct ieee80211_vif *vif,
2305 struct ieee80211_bss_conf *bss_conf,
2306 u32 changed)
2307{
2308 bool do_join = false, set_assoc = false;
2309 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002310 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002311 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002312 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002313 bool sta_exists = false;
2314 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002315
2316 if (is_ibss) {
2317 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2318 changed);
2319 if (ret < 0)
2320 goto out;
2321 }
2322
2323 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2324 do_join = true;
2325
2326 /* Need to update the SSID (for filtering etc) */
2327 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2328 do_join = true;
2329
2330 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002331 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2332 bss_conf->enable_beacon ? "enabled" : "disabled");
2333
2334 if (bss_conf->enable_beacon)
2335 wl->set_bss_type = BSS_TYPE_IBSS;
2336 else
2337 wl->set_bss_type = BSS_TYPE_STA_BSS;
2338 do_join = true;
2339 }
2340
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002342 bool enable = false;
2343 if (bss_conf->cqm_rssi_thold)
2344 enable = true;
2345 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2346 bss_conf->cqm_rssi_thold,
2347 bss_conf->cqm_rssi_hyst);
2348 if (ret < 0)
2349 goto out;
2350 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2351 }
2352
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002353 if ((changed & BSS_CHANGED_BSSID) &&
2354 /*
2355 * Now we know the correct bssid, so we send a new join command
2356 * and enable the BSSID filter
2357 */
2358 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002359 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002360
Eliad Pellerfa287b82010-12-26 09:27:50 +01002361 if (!is_zero_ether_addr(wl->bssid)) {
2362 ret = wl1271_cmd_build_null_data(wl);
2363 if (ret < 0)
2364 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002365
Eliad Pellerfa287b82010-12-26 09:27:50 +01002366 ret = wl1271_build_qos_null_data(wl);
2367 if (ret < 0)
2368 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002369
Eliad Pellerfa287b82010-12-26 09:27:50 +01002370 /* filter out all packets not from this BSSID */
2371 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002372
Eliad Pellerfa287b82010-12-26 09:27:50 +01002373 /* Need to update the BSSID (for filtering etc) */
2374 do_join = true;
2375 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002376 }
2377
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002378 rcu_read_lock();
2379 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2380 if (sta) {
2381 /* save the supp_rates of the ap */
2382 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2383 if (sta->ht_cap.ht_supported)
2384 sta_rate_set |=
2385 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002386 sta_ht_cap = sta->ht_cap;
2387 sta_exists = true;
2388 }
2389 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002390
Arik Nemtsova1008852011-02-12 23:24:20 +02002391 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002392 /* handle new association with HT and HT information change */
2393 if ((changed & BSS_CHANGED_HT) &&
2394 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002395 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002396 true);
2397 if (ret < 0) {
2398 wl1271_warning("Set ht cap true failed %d",
2399 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002400 goto out;
2401 }
2402 ret = wl1271_acx_set_ht_information(wl,
2403 bss_conf->ht_operation_mode);
2404 if (ret < 0) {
2405 wl1271_warning("Set ht information failed %d",
2406 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002407 goto out;
2408 }
2409 }
2410 /* handle new association without HT and disassociation */
2411 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002412 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002413 false);
2414 if (ret < 0) {
2415 wl1271_warning("Set ht cap false failed %d",
2416 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002417 goto out;
2418 }
2419 }
2420 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002421
Arik Nemtsove78a2872010-10-16 19:07:21 +02002422 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002424 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002425 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002426 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002427 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002428
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002429 wl->ps_poll_failures = 0;
2430
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002431 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002432 * use basic rates from AP, and determine lowest rate
2433 * to use with control frames.
2434 */
2435 rates = bss_conf->basic_rates;
2436 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2437 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002438 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002439 if (sta_rate_set)
2440 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2441 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002442 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002443 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002445
2446 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002447 * with wl1271, we don't need to update the
2448 * beacon_int and dtim_period, because the firmware
2449 * updates it by itself when the first beacon is
2450 * received after a join.
2451 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002452 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2453 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002454 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002455
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002456 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002457 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002458 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002459 dev_kfree_skb(wl->probereq);
2460 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2461 ieoffset = offsetof(struct ieee80211_mgmt,
2462 u.probe_req.variable);
2463 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002464
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002465 /* enable the connection monitoring feature */
2466 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002467 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002468 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469
2470 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002471 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2472 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002473 enum wl1271_cmd_ps_mode mode;
2474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002476 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002477 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002478 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002479 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002480 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002482 } else {
2483 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002484 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002485 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002486 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002487
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002488 /* free probe-request template */
2489 dev_kfree_skb(wl->probereq);
2490 wl->probereq = NULL;
2491
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002492 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002493 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002494
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002495 /* revert back to minimum rates for the current band */
2496 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002497 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002498 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002499 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002500 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002501
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002502 /* disable connection monitor features */
2503 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002504
2505 /* Disable the keep-alive feature */
2506 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002507 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002508 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002509
2510 /* restore the bssid filter and go to dummy bssid */
2511 wl1271_unjoin(wl);
2512 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 }
2514 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002515
Arik Nemtsove78a2872010-10-16 19:07:21 +02002516 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2517 if (ret < 0)
2518 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002520 if (changed & BSS_CHANGED_ARP_FILTER) {
2521 __be32 addr = bss_conf->arp_addr_list[0];
2522 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2523
Eliad Pellerc5312772010-12-09 11:31:27 +02002524 if (bss_conf->arp_addr_cnt == 1 &&
2525 bss_conf->arp_filter_enabled) {
2526 /*
2527 * The template should have been configured only upon
2528 * association. however, it seems that the correct ip
2529 * isn't being set (when sending), so we have to
2530 * reconfigure the template upon every ip change.
2531 */
2532 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2533 if (ret < 0) {
2534 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002535 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002536 }
2537
2538 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002539 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002540 addr);
2541 } else
2542 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002543
2544 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002545 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002546 }
2547
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002548 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002549 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002550 if (ret < 0) {
2551 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002552 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002553 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002554 }
2555
Arik Nemtsove78a2872010-10-16 19:07:21 +02002556out:
2557 return;
2558}
2559
2560static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2561 struct ieee80211_vif *vif,
2562 struct ieee80211_bss_conf *bss_conf,
2563 u32 changed)
2564{
2565 struct wl1271 *wl = hw->priv;
2566 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2567 int ret;
2568
2569 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2570 (int)changed);
2571
2572 mutex_lock(&wl->mutex);
2573
2574 if (unlikely(wl->state == WL1271_STATE_OFF))
2575 goto out;
2576
Ido Yariva6208652011-03-01 15:14:41 +02002577 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002578 if (ret < 0)
2579 goto out;
2580
2581 if (is_ap)
2582 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2583 else
2584 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2585
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 wl1271_ps_elp_sleep(wl);
2587
2588out:
2589 mutex_unlock(&wl->mutex);
2590}
2591
Kalle Valoc6999d82010-02-18 13:25:41 +02002592static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2593 const struct ieee80211_tx_queue_params *params)
2594{
2595 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002596 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002597 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002598
2599 mutex_lock(&wl->mutex);
2600
2601 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2602
Kalle Valo4695dc92010-03-18 12:26:38 +02002603 if (params->uapsd)
2604 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2605 else
2606 ps_scheme = CONF_PS_SCHEME_LEGACY;
2607
Arik Nemtsov488fc542010-10-16 20:33:45 +02002608 if (wl->state == WL1271_STATE_OFF) {
2609 /*
2610 * If the state is off, the parameters will be recorded and
2611 * configured on init. This happens in AP-mode.
2612 */
2613 struct conf_tx_ac_category *conf_ac =
2614 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2615 struct conf_tx_tid *conf_tid =
2616 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2617
2618 conf_ac->ac = wl1271_tx_get_queue(queue);
2619 conf_ac->cw_min = (u8)params->cw_min;
2620 conf_ac->cw_max = params->cw_max;
2621 conf_ac->aifsn = params->aifs;
2622 conf_ac->tx_op_limit = params->txop << 5;
2623
2624 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2625 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2626 conf_tid->tsid = wl1271_tx_get_queue(queue);
2627 conf_tid->ps_scheme = ps_scheme;
2628 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2629 conf_tid->apsd_conf[0] = 0;
2630 conf_tid->apsd_conf[1] = 0;
2631 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002632 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002633 if (ret < 0)
2634 goto out;
2635
2636 /*
2637 * the txop is confed in units of 32us by the mac80211,
2638 * we need us
2639 */
2640 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2641 params->cw_min, params->cw_max,
2642 params->aifs, params->txop << 5);
2643 if (ret < 0)
2644 goto out_sleep;
2645
2646 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2647 CONF_CHANNEL_TYPE_EDCF,
2648 wl1271_tx_get_queue(queue),
2649 ps_scheme, CONF_ACK_POLICY_LEGACY,
2650 0, 0);
2651 if (ret < 0)
2652 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002653
2654out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002655 wl1271_ps_elp_sleep(wl);
2656 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002657
2658out:
2659 mutex_unlock(&wl->mutex);
2660
2661 return ret;
2662}
2663
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002664static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2665{
2666
2667 struct wl1271 *wl = hw->priv;
2668 u64 mactime = ULLONG_MAX;
2669 int ret;
2670
2671 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2672
2673 mutex_lock(&wl->mutex);
2674
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002675 if (unlikely(wl->state == WL1271_STATE_OFF))
2676 goto out;
2677
Ido Yariva6208652011-03-01 15:14:41 +02002678 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002679 if (ret < 0)
2680 goto out;
2681
2682 ret = wl1271_acx_tsf_info(wl, &mactime);
2683 if (ret < 0)
2684 goto out_sleep;
2685
2686out_sleep:
2687 wl1271_ps_elp_sleep(wl);
2688
2689out:
2690 mutex_unlock(&wl->mutex);
2691 return mactime;
2692}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693
John W. Linvilleece550d2010-07-28 16:41:06 -04002694static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2695 struct survey_info *survey)
2696{
2697 struct wl1271 *wl = hw->priv;
2698 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002699
John W. Linvilleece550d2010-07-28 16:41:06 -04002700 if (idx != 0)
2701 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002702
John W. Linvilleece550d2010-07-28 16:41:06 -04002703 survey->channel = conf->channel;
2704 survey->filled = SURVEY_INFO_NOISE_DBM;
2705 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002706
John W. Linvilleece550d2010-07-28 16:41:06 -04002707 return 0;
2708}
2709
Arik Nemtsov409622e2011-02-23 00:22:29 +02002710static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002711 struct ieee80211_sta *sta,
2712 u8 *hlid)
2713{
2714 struct wl1271_station *wl_sta;
2715 int id;
2716
2717 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2718 if (id >= AP_MAX_STATIONS) {
2719 wl1271_warning("could not allocate HLID - too much stations");
2720 return -EBUSY;
2721 }
2722
2723 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002724 __set_bit(id, wl->ap_hlid_map);
2725 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2726 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002727 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002728 return 0;
2729}
2730
Arik Nemtsov409622e2011-02-23 00:22:29 +02002731static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002732{
2733 int id = hlid - WL1271_AP_STA_HLID_START;
2734
Arik Nemtsov409622e2011-02-23 00:22:29 +02002735 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2736 return;
2737
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002738 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002739 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002740 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002741 __clear_bit(hlid, &wl->ap_ps_map);
2742 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002743}
2744
2745static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2746 struct ieee80211_vif *vif,
2747 struct ieee80211_sta *sta)
2748{
2749 struct wl1271 *wl = hw->priv;
2750 int ret = 0;
2751 u8 hlid;
2752
2753 mutex_lock(&wl->mutex);
2754
2755 if (unlikely(wl->state == WL1271_STATE_OFF))
2756 goto out;
2757
2758 if (wl->bss_type != BSS_TYPE_AP_BSS)
2759 goto out;
2760
2761 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2762
Arik Nemtsov409622e2011-02-23 00:22:29 +02002763 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002764 if (ret < 0)
2765 goto out;
2766
Ido Yariva6208652011-03-01 15:14:41 +02002767 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002768 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002769 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002770
2771 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2772 if (ret < 0)
2773 goto out_sleep;
2774
2775out_sleep:
2776 wl1271_ps_elp_sleep(wl);
2777
Arik Nemtsov409622e2011-02-23 00:22:29 +02002778out_free_sta:
2779 if (ret < 0)
2780 wl1271_free_sta(wl, hlid);
2781
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002782out:
2783 mutex_unlock(&wl->mutex);
2784 return ret;
2785}
2786
2787static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2788 struct ieee80211_vif *vif,
2789 struct ieee80211_sta *sta)
2790{
2791 struct wl1271 *wl = hw->priv;
2792 struct wl1271_station *wl_sta;
2793 int ret = 0, id;
2794
2795 mutex_lock(&wl->mutex);
2796
2797 if (unlikely(wl->state == WL1271_STATE_OFF))
2798 goto out;
2799
2800 if (wl->bss_type != BSS_TYPE_AP_BSS)
2801 goto out;
2802
2803 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2804
2805 wl_sta = (struct wl1271_station *)sta->drv_priv;
2806 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2807 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2808 goto out;
2809
Ido Yariva6208652011-03-01 15:14:41 +02002810 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002811 if (ret < 0)
2812 goto out;
2813
2814 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2815 if (ret < 0)
2816 goto out_sleep;
2817
Arik Nemtsov409622e2011-02-23 00:22:29 +02002818 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002819
2820out_sleep:
2821 wl1271_ps_elp_sleep(wl);
2822
2823out:
2824 mutex_unlock(&wl->mutex);
2825 return ret;
2826}
2827
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002828int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002829 enum ieee80211_ampdu_mlme_action action,
2830 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2831 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002832{
2833 struct wl1271 *wl = hw->priv;
2834 int ret;
2835
2836 mutex_lock(&wl->mutex);
2837
2838 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2839 ret = -EAGAIN;
2840 goto out;
2841 }
2842
Ido Yariva6208652011-03-01 15:14:41 +02002843 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002844 if (ret < 0)
2845 goto out;
2846
2847 switch (action) {
2848 case IEEE80211_AMPDU_RX_START:
2849 if (wl->ba_support) {
2850 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2851 true);
2852 if (!ret)
2853 wl->ba_rx_bitmap |= BIT(tid);
2854 } else {
2855 ret = -ENOTSUPP;
2856 }
2857 break;
2858
2859 case IEEE80211_AMPDU_RX_STOP:
2860 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2861 if (!ret)
2862 wl->ba_rx_bitmap &= ~BIT(tid);
2863 break;
2864
2865 /*
2866 * The BA initiator session management in FW independently.
2867 * Falling break here on purpose for all TX APDU commands.
2868 */
2869 case IEEE80211_AMPDU_TX_START:
2870 case IEEE80211_AMPDU_TX_STOP:
2871 case IEEE80211_AMPDU_TX_OPERATIONAL:
2872 ret = -EINVAL;
2873 break;
2874
2875 default:
2876 wl1271_error("Incorrect ampdu action id=%x\n", action);
2877 ret = -EINVAL;
2878 }
2879
2880 wl1271_ps_elp_sleep(wl);
2881
2882out:
2883 mutex_unlock(&wl->mutex);
2884
2885 return ret;
2886}
2887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002888/* can't be const, mac80211 writes to this */
2889static struct ieee80211_rate wl1271_rates[] = {
2890 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002891 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2892 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002893 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002894 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2895 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002896 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2897 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002898 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2899 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002900 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2901 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002902 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2903 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2905 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002906 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2907 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002908 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002909 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2910 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002911 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002912 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2913 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002915 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2916 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002918 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2919 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002921 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2922 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002924 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2925 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002927 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2928 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929};
2930
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002931/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002932static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002933 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002934 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002935 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2936 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2937 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002938 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002939 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2940 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2941 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002942 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002943 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2944 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2945 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002946 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947};
2948
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002949/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002950static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002951 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002952 7, /* CONF_HW_RXTX_RATE_MCS7 */
2953 6, /* CONF_HW_RXTX_RATE_MCS6 */
2954 5, /* CONF_HW_RXTX_RATE_MCS5 */
2955 4, /* CONF_HW_RXTX_RATE_MCS4 */
2956 3, /* CONF_HW_RXTX_RATE_MCS3 */
2957 2, /* CONF_HW_RXTX_RATE_MCS2 */
2958 1, /* CONF_HW_RXTX_RATE_MCS1 */
2959 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002960
2961 11, /* CONF_HW_RXTX_RATE_54 */
2962 10, /* CONF_HW_RXTX_RATE_48 */
2963 9, /* CONF_HW_RXTX_RATE_36 */
2964 8, /* CONF_HW_RXTX_RATE_24 */
2965
2966 /* TI-specific rate */
2967 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2968
2969 7, /* CONF_HW_RXTX_RATE_18 */
2970 6, /* CONF_HW_RXTX_RATE_12 */
2971 3, /* CONF_HW_RXTX_RATE_11 */
2972 5, /* CONF_HW_RXTX_RATE_9 */
2973 4, /* CONF_HW_RXTX_RATE_6 */
2974 2, /* CONF_HW_RXTX_RATE_5_5 */
2975 1, /* CONF_HW_RXTX_RATE_2 */
2976 0 /* CONF_HW_RXTX_RATE_1 */
2977};
2978
Shahar Levie8b03a22010-10-13 16:09:39 +02002979/* 11n STA capabilities */
2980#define HW_RX_HIGHEST_RATE 72
2981
Shahar Levi00d20102010-11-08 11:20:10 +00002982#ifdef CONFIG_WL12XX_HT
2983#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002984 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2985 .ht_supported = true, \
2986 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2987 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2988 .mcs = { \
2989 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2990 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2991 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2992 }, \
2993}
Shahar Levi18357852010-10-13 16:09:41 +02002994#else
Shahar Levi00d20102010-11-08 11:20:10 +00002995#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002996 .ht_supported = false, \
2997}
2998#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000/* can't be const, mac80211 writes to this */
3001static struct ieee80211_supported_band wl1271_band_2ghz = {
3002 .channels = wl1271_channels,
3003 .n_channels = ARRAY_SIZE(wl1271_channels),
3004 .bitrates = wl1271_rates,
3005 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003006 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007};
3008
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003009/* 5 GHz data rates for WL1273 */
3010static struct ieee80211_rate wl1271_rates_5ghz[] = {
3011 { .bitrate = 60,
3012 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3013 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3014 { .bitrate = 90,
3015 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3016 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3017 { .bitrate = 120,
3018 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3019 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3020 { .bitrate = 180,
3021 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3022 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3023 { .bitrate = 240,
3024 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3025 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3026 { .bitrate = 360,
3027 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3028 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3029 { .bitrate = 480,
3030 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3031 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3032 { .bitrate = 540,
3033 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3034 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3035};
3036
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003037/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003038static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003039 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003040 { .hw_value = 8, .center_freq = 5040},
3041 { .hw_value = 9, .center_freq = 5045},
3042 { .hw_value = 11, .center_freq = 5055},
3043 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003044 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003045 { .hw_value = 34, .center_freq = 5170},
3046 { .hw_value = 36, .center_freq = 5180},
3047 { .hw_value = 38, .center_freq = 5190},
3048 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003049 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003050 { .hw_value = 44, .center_freq = 5220},
3051 { .hw_value = 46, .center_freq = 5230},
3052 { .hw_value = 48, .center_freq = 5240},
3053 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003054 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003055 { .hw_value = 60, .center_freq = 5300},
3056 { .hw_value = 64, .center_freq = 5320},
3057 { .hw_value = 100, .center_freq = 5500},
3058 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003059 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003060 { .hw_value = 112, .center_freq = 5560},
3061 { .hw_value = 116, .center_freq = 5580},
3062 { .hw_value = 120, .center_freq = 5600},
3063 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003064 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003065 { .hw_value = 132, .center_freq = 5660},
3066 { .hw_value = 136, .center_freq = 5680},
3067 { .hw_value = 140, .center_freq = 5700},
3068 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003069 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003070 { .hw_value = 157, .center_freq = 5785},
3071 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003072 { .hw_value = 165, .center_freq = 5825},
3073};
3074
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003075/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003076static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003077 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003078 7, /* CONF_HW_RXTX_RATE_MCS7 */
3079 6, /* CONF_HW_RXTX_RATE_MCS6 */
3080 5, /* CONF_HW_RXTX_RATE_MCS5 */
3081 4, /* CONF_HW_RXTX_RATE_MCS4 */
3082 3, /* CONF_HW_RXTX_RATE_MCS3 */
3083 2, /* CONF_HW_RXTX_RATE_MCS2 */
3084 1, /* CONF_HW_RXTX_RATE_MCS1 */
3085 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003086
3087 7, /* CONF_HW_RXTX_RATE_54 */
3088 6, /* CONF_HW_RXTX_RATE_48 */
3089 5, /* CONF_HW_RXTX_RATE_36 */
3090 4, /* CONF_HW_RXTX_RATE_24 */
3091
3092 /* TI-specific rate */
3093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3094
3095 3, /* CONF_HW_RXTX_RATE_18 */
3096 2, /* CONF_HW_RXTX_RATE_12 */
3097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3098 1, /* CONF_HW_RXTX_RATE_9 */
3099 0, /* CONF_HW_RXTX_RATE_6 */
3100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3102 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3103};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003104
3105static struct ieee80211_supported_band wl1271_band_5ghz = {
3106 .channels = wl1271_channels_5ghz,
3107 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3108 .bitrates = wl1271_rates_5ghz,
3109 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003110 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003111};
3112
Tobias Klausera0ea9492010-05-20 10:38:11 +02003113static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003114 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3115 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3116};
3117
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003118static const struct ieee80211_ops wl1271_ops = {
3119 .start = wl1271_op_start,
3120 .stop = wl1271_op_stop,
3121 .add_interface = wl1271_op_add_interface,
3122 .remove_interface = wl1271_op_remove_interface,
3123 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003124 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003125 .configure_filter = wl1271_op_configure_filter,
3126 .tx = wl1271_op_tx,
3127 .set_key = wl1271_op_set_key,
3128 .hw_scan = wl1271_op_hw_scan,
3129 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003130 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003132 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003133 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003134 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003135 .sta_add = wl1271_op_sta_add,
3136 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003137 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003138 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003139};
3140
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003141
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003142u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003143{
3144 u8 idx;
3145
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003146 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003147
3148 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3149 wl1271_error("Illegal RX rate from HW: %d", rate);
3150 return 0;
3151 }
3152
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003153 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003154 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3155 wl1271_error("Unsupported RX rate from HW: %d", rate);
3156 return 0;
3157 }
3158
3159 return idx;
3160}
3161
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003162static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3163 struct device_attribute *attr,
3164 char *buf)
3165{
3166 struct wl1271 *wl = dev_get_drvdata(dev);
3167 ssize_t len;
3168
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003169 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003170
3171 mutex_lock(&wl->mutex);
3172 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3173 wl->sg_enabled);
3174 mutex_unlock(&wl->mutex);
3175
3176 return len;
3177
3178}
3179
3180static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3181 struct device_attribute *attr,
3182 const char *buf, size_t count)
3183{
3184 struct wl1271 *wl = dev_get_drvdata(dev);
3185 unsigned long res;
3186 int ret;
3187
3188 ret = strict_strtoul(buf, 10, &res);
3189
3190 if (ret < 0) {
3191 wl1271_warning("incorrect value written to bt_coex_mode");
3192 return count;
3193 }
3194
3195 mutex_lock(&wl->mutex);
3196
3197 res = !!res;
3198
3199 if (res == wl->sg_enabled)
3200 goto out;
3201
3202 wl->sg_enabled = res;
3203
3204 if (wl->state == WL1271_STATE_OFF)
3205 goto out;
3206
Ido Yariva6208652011-03-01 15:14:41 +02003207 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003208 if (ret < 0)
3209 goto out;
3210
3211 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3212 wl1271_ps_elp_sleep(wl);
3213
3214 out:
3215 mutex_unlock(&wl->mutex);
3216 return count;
3217}
3218
3219static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3220 wl1271_sysfs_show_bt_coex_state,
3221 wl1271_sysfs_store_bt_coex_state);
3222
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003223static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3224 struct device_attribute *attr,
3225 char *buf)
3226{
3227 struct wl1271 *wl = dev_get_drvdata(dev);
3228 ssize_t len;
3229
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003230 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003231
3232 mutex_lock(&wl->mutex);
3233 if (wl->hw_pg_ver >= 0)
3234 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3235 else
3236 len = snprintf(buf, len, "n/a\n");
3237 mutex_unlock(&wl->mutex);
3238
3239 return len;
3240}
3241
3242static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3243 wl1271_sysfs_show_hw_pg_ver, NULL);
3244
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003245int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003246{
3247 int ret;
3248
3249 if (wl->mac80211_registered)
3250 return 0;
3251
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003252 ret = wl1271_fetch_nvs(wl);
3253 if (ret == 0) {
3254 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3255
3256 wl->mac_addr[0] = nvs_ptr[11];
3257 wl->mac_addr[1] = nvs_ptr[10];
3258 wl->mac_addr[2] = nvs_ptr[6];
3259 wl->mac_addr[3] = nvs_ptr[5];
3260 wl->mac_addr[4] = nvs_ptr[4];
3261 wl->mac_addr[5] = nvs_ptr[3];
3262 }
3263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3265
3266 ret = ieee80211_register_hw(wl->hw);
3267 if (ret < 0) {
3268 wl1271_error("unable to register mac80211 hw: %d", ret);
3269 return ret;
3270 }
3271
3272 wl->mac80211_registered = true;
3273
Eliad Pellerd60080a2010-11-24 12:53:16 +02003274 wl1271_debugfs_init(wl);
3275
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003276 register_netdevice_notifier(&wl1271_dev_notifier);
3277
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003278 wl1271_notice("loaded");
3279
3280 return 0;
3281}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003282EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003283
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003284void wl1271_unregister_hw(struct wl1271 *wl)
3285{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003286 if (wl->state == WL1271_STATE_PLT)
3287 __wl1271_plt_stop(wl);
3288
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003289 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003290 ieee80211_unregister_hw(wl->hw);
3291 wl->mac80211_registered = false;
3292
3293}
3294EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3295
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003296int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003297{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003298 static const u32 cipher_suites[] = {
3299 WLAN_CIPHER_SUITE_WEP40,
3300 WLAN_CIPHER_SUITE_WEP104,
3301 WLAN_CIPHER_SUITE_TKIP,
3302 WLAN_CIPHER_SUITE_CCMP,
3303 WL1271_CIPHER_SUITE_GEM,
3304 };
3305
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003306 /* The tx descriptor buffer and the TKIP space. */
3307 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3308 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309
3310 /* unit us */
3311 /* FIXME: find a proper value */
3312 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003313 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003314
3315 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003316 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003317 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003318 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003319 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003320 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003321 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003322 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3323 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003325 wl->hw->wiphy->cipher_suites = cipher_suites;
3326 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3327
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003328 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003329 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003330 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003331 /*
3332 * Maximum length of elements in scanning probe request templates
3333 * should be the maximum length possible for a template, without
3334 * the IEEE80211 header of the template
3335 */
3336 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3337 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003338
3339 /*
3340 * We keep local copies of the band structs because we need to
3341 * modify them on a per-device basis.
3342 */
3343 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3344 sizeof(wl1271_band_2ghz));
3345 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3346 sizeof(wl1271_band_5ghz));
3347
3348 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3349 &wl->bands[IEEE80211_BAND_2GHZ];
3350 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3351 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003352
Kalle Valo12bd8942010-03-18 12:26:33 +02003353 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003354 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003355
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003356 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3357
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003358 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003360 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3361
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003362 wl->hw->max_rx_aggregation_subframes = 8;
3363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003364 return 0;
3365}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003366EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003368#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003369
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003370struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003371{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003372 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003373 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003374 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003375 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003376 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003377
3378 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3379 if (!hw) {
3380 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003381 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003382 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003383 }
3384
Julia Lawall929ebd32010-05-15 23:16:39 +02003385 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003386 if (!plat_dev) {
3387 wl1271_error("could not allocate platform_device");
3388 ret = -ENOMEM;
3389 goto err_plat_alloc;
3390 }
3391
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003392 wl = hw->priv;
3393 memset(wl, 0, sizeof(*wl));
3394
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003395 INIT_LIST_HEAD(&wl->list);
3396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003397 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003398 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003399
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003400 for (i = 0; i < NUM_TX_QUEUES; i++)
3401 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003402
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003403 for (i = 0; i < NUM_TX_QUEUES; i++)
3404 for (j = 0; j < AP_MAX_LINKS; j++)
3405 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3406
Ido Yariva6208652011-03-01 15:14:41 +02003407 skb_queue_head_init(&wl->deferred_rx_queue);
3408 skb_queue_head_init(&wl->deferred_tx_queue);
3409
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003410 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003411 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003412 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003413 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3414 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3415 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003416 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003417 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003418 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003420 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3421 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003422 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003423 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003424 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003425 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003426 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003427 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003428 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003429 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003430 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003431 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003432 wl->bss_type = MAX_BSS_TYPE;
3433 wl->set_bss_type = MAX_BSS_TYPE;
3434 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003435 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003436 wl->ap_ps_map = 0;
3437 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003438 wl->quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003439
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003440 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003441 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003442 wl->tx_frames[i] = NULL;
3443
3444 spin_lock_init(&wl->wl_lock);
3445
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446 wl->state = WL1271_STATE_OFF;
3447 mutex_init(&wl->mutex);
3448
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003449 /* Apply default driver configuration. */
3450 wl1271_conf_init(wl);
3451
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003452 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3453 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3454 if (!wl->aggr_buf) {
3455 ret = -ENOMEM;
3456 goto err_hw;
3457 }
3458
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003459 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003460 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003461 if (ret) {
3462 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003463 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003464 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003465 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003466
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003467 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003468 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003469 if (ret < 0) {
3470 wl1271_error("failed to create sysfs file bt_coex_state");
3471 goto err_platform;
3472 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003473
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003474 /* Create sysfs file to get HW PG version */
3475 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3476 if (ret < 0) {
3477 wl1271_error("failed to create sysfs file hw_pg_ver");
3478 goto err_bt_coex_state;
3479 }
3480
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003481 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003482
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003483err_bt_coex_state:
3484 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3485
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003486err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003487 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003488
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003489err_aggr:
3490 free_pages((unsigned long)wl->aggr_buf, order);
3491
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003492err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003493 wl1271_debugfs_exit(wl);
3494 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003495
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003496err_plat_alloc:
3497 ieee80211_free_hw(hw);
3498
3499err_hw_alloc:
3500
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003501 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003502}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003503EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003504
3505int wl1271_free_hw(struct wl1271 *wl)
3506{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003507 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003508 free_pages((unsigned long)wl->aggr_buf,
3509 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003510 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003511
3512 wl1271_debugfs_exit(wl);
3513
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003514 vfree(wl->fw);
3515 wl->fw = NULL;
3516 kfree(wl->nvs);
3517 wl->nvs = NULL;
3518
3519 kfree(wl->fw_status);
3520 kfree(wl->tx_res_if);
3521
3522 ieee80211_free_hw(wl->hw);
3523
3524 return 0;
3525}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003526EXPORT_SYMBOL_GPL(wl1271_free_hw);
3527
Guy Eilam491bbd62011-01-12 10:33:29 +01003528u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003529EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003530module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003531MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3532
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003533MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003534MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003535MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");