blob: 8b3c8d196b03310bc7760340411414b0bbf7e82c [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,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200307 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200308 .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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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 Coelho12419cce2010-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;
Ido Yarivb07d4032011-03-01 15:14:43 +0200671 unsigned long flags;
672
673 /* TX might be handled here, avoid redundant work */
674 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
675 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676
677 mutex_lock(&wl->mutex);
678
679 wl1271_debug(DEBUG_IRQ, "IRQ work");
680
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200681 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 goto out;
683
Ido Yariva6208652011-03-01 15:14:41 +0200684 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685 if (ret < 0)
686 goto out;
687
Ido Yariva6208652011-03-01 15:14:41 +0200688 while (!done && loopcount--) {
689 /*
690 * In order to avoid a race with the hardirq, clear the flag
691 * before acknowledging the chip. Since the mutex is held,
692 * wl1271_ps_elp_wakeup cannot be called concurrently.
693 */
694 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
695 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200696
697 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200698 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200699 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200700 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200701 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200702 continue;
703 }
704
Eliad Pellerccc83b02010-10-27 14:09:57 +0200705 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
706 wl1271_error("watchdog interrupt received! "
707 "starting recovery.");
708 ieee80211_queue_work(wl->hw, &wl->recovery_work);
709
710 /* restarting the chip. ignore any other interrupt. */
711 goto out;
712 }
713
Ido Yariva6208652011-03-01 15:14:41 +0200714 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200715 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
716
Ido Yariv8aad2462011-03-01 15:14:38 +0200717 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200718
Ido Yariva5225502010-10-12 14:49:10 +0200719 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200720 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200721 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200722 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200723 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200724 /*
725 * In order to avoid starvation of the TX path,
726 * call the work function directly.
727 */
728 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200729 } else {
730 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200731 }
732
Ido Yariv8aad2462011-03-01 15:14:38 +0200733 /* check for tx results */
734 if (wl->fw_status->common.tx_results_counter !=
735 (wl->tx_results_count & 0xff))
736 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200737
738 /* Make sure the deferred queues don't get too long */
739 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
740 skb_queue_len(&wl->deferred_rx_queue);
741 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
742 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200743 }
744
745 if (intr & WL1271_ACX_INTR_EVENT_A) {
746 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
747 wl1271_event_handle(wl, 0);
748 }
749
750 if (intr & WL1271_ACX_INTR_EVENT_B) {
751 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
752 wl1271_event_handle(wl, 1);
753 }
754
755 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
756 wl1271_debug(DEBUG_IRQ,
757 "WL1271_ACX_INTR_INIT_COMPLETE");
758
759 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
760 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761 }
762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763 wl1271_ps_elp_sleep(wl);
764
765out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200766 spin_lock_irqsave(&wl->wl_lock, flags);
767 /* In case TX was not handled here, queue TX work */
768 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
769 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
770 wl->tx_queue_count)
771 ieee80211_queue_work(wl->hw, &wl->tx_work);
772 spin_unlock_irqrestore(&wl->wl_lock, flags);
773
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200775
776 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777}
Ido Yariva6208652011-03-01 15:14:41 +0200778EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780static int wl1271_fetch_firmware(struct wl1271 *wl)
781{
782 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200783 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784 int ret;
785
Arik Nemtsov166d5042010-10-16 21:44:57 +0200786 switch (wl->bss_type) {
787 case BSS_TYPE_AP_BSS:
788 fw_name = WL1271_AP_FW_NAME;
789 break;
790 case BSS_TYPE_IBSS:
791 case BSS_TYPE_STA_BSS:
792 fw_name = WL1271_FW_NAME;
793 break;
794 default:
795 wl1271_error("no compatible firmware for bss_type %d",
796 wl->bss_type);
797 return -EINVAL;
798 }
799
800 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
801
802 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300803
804 if (ret < 0) {
805 wl1271_error("could not get firmware: %d", ret);
806 return ret;
807 }
808
809 if (fw->size % 4) {
810 wl1271_error("firmware size is not multiple of 32 bits: %zu",
811 fw->size);
812 ret = -EILSEQ;
813 goto out;
814 }
815
Arik Nemtsov166d5042010-10-16 21:44:57 +0200816 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300817 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300818 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819
820 if (!wl->fw) {
821 wl1271_error("could not allocate memory for the firmware");
822 ret = -ENOMEM;
823 goto out;
824 }
825
826 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200827 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828 ret = 0;
829
830out:
831 release_firmware(fw);
832
833 return ret;
834}
835
836static int wl1271_fetch_nvs(struct wl1271 *wl)
837{
838 const struct firmware *fw;
839 int ret;
840
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200841 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842
843 if (ret < 0) {
844 wl1271_error("could not get nvs file: %d", ret);
845 return ret;
846 }
847
Julia Lawall929ebd32010-05-15 23:16:39 +0200848 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849
850 if (!wl->nvs) {
851 wl1271_error("could not allocate memory for the nvs file");
852 ret = -ENOMEM;
853 goto out;
854 }
855
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200856 wl->nvs_len = fw->size;
857
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300858out:
859 release_firmware(fw);
860
861 return ret;
862}
863
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200864static void wl1271_recovery_work(struct work_struct *work)
865{
866 struct wl1271 *wl =
867 container_of(work, struct wl1271, recovery_work);
868
869 mutex_lock(&wl->mutex);
870
871 if (wl->state != WL1271_STATE_ON)
872 goto out;
873
874 wl1271_info("Hardware recovery in progress.");
875
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200876 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
877 ieee80211_connection_loss(wl->vif);
878
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200879 /* reboot the chipset */
880 __wl1271_op_remove_interface(wl);
881 ieee80211_restart_hw(wl->hw);
882
883out:
884 mutex_unlock(&wl->mutex);
885}
886
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887static void wl1271_fw_wakeup(struct wl1271 *wl)
888{
889 u32 elp_reg;
890
891 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300892 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893}
894
895static int wl1271_setup(struct wl1271 *wl)
896{
897 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
898 if (!wl->fw_status)
899 return -ENOMEM;
900
901 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
902 if (!wl->tx_res_if) {
903 kfree(wl->fw_status);
904 return -ENOMEM;
905 }
906
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907 return 0;
908}
909
910static int wl1271_chip_wakeup(struct wl1271 *wl)
911{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300912 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913 int ret = 0;
914
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200915 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200916 ret = wl1271_power_on(wl);
917 if (ret < 0)
918 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200920 wl1271_io_reset(wl);
921 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300922
923 /* We don't need a real memory partition here, because we only want
924 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300925 memset(&partition, 0, sizeof(partition));
926 partition.reg.start = REGISTERS_BASE;
927 partition.reg.size = REGISTERS_DOWN_SIZE;
928 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929
930 /* ELP module wake up */
931 wl1271_fw_wakeup(wl);
932
933 /* whal_FwCtrl_BootSm() */
934
935 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200936 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
938 /* 1. check if chip id is valid */
939
940 switch (wl->chip.id) {
941 case CHIP_ID_1271_PG10:
942 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
943 wl->chip.id);
944
945 ret = wl1271_setup(wl);
946 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200947 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 break;
949 case CHIP_ID_1271_PG20:
950 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
951 wl->chip.id);
952
953 ret = wl1271_setup(wl);
954 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200955 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 break;
957 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200958 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200960 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 }
962
Arik Nemtsov166d5042010-10-16 21:44:57 +0200963 /* Make sure the firmware type matches the BSS type */
964 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 ret = wl1271_fetch_firmware(wl);
966 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200967 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 }
969
970 /* No NVS from netlink, try to get it from the filesystem */
971 if (wl->nvs == NULL) {
972 ret = wl1271_fetch_nvs(wl);
973 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200974 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975 }
976
977out:
978 return ret;
979}
980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981int wl1271_plt_start(struct wl1271 *wl)
982{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200983 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300984 int ret;
985
986 mutex_lock(&wl->mutex);
987
988 wl1271_notice("power up");
989
990 if (wl->state != WL1271_STATE_OFF) {
991 wl1271_error("cannot go into PLT state because not "
992 "in off state: %d", wl->state);
993 ret = -EBUSY;
994 goto out;
995 }
996
Arik Nemtsov166d5042010-10-16 21:44:57 +0200997 wl->bss_type = BSS_TYPE_STA_BSS;
998
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200999 while (retries) {
1000 retries--;
1001 ret = wl1271_chip_wakeup(wl);
1002 if (ret < 0)
1003 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001005 ret = wl1271_boot(wl);
1006 if (ret < 0)
1007 goto power_off;
1008
1009 ret = wl1271_plt_init(wl);
1010 if (ret < 0)
1011 goto irq_disable;
1012
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001013 wl->state = WL1271_STATE_PLT;
1014 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001015 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 goto out;
1017
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001018irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001019 mutex_unlock(&wl->mutex);
1020 /* Unlocking the mutex in the middle of handling is
1021 inherently unsafe. In this case we deem it safe to do,
1022 because we need to let any possibly pending IRQ out of
1023 the system (and while we are WL1271_STATE_OFF the IRQ
1024 work function will not do anything.) Also, any other
1025 possible concurrent operations will fail due to the
1026 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001027 wl1271_disable_interrupts(wl);
1028 wl1271_flush_deferred_work(wl);
1029 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001030 mutex_lock(&wl->mutex);
1031power_off:
1032 wl1271_power_off(wl);
1033 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001035 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1036 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037out:
1038 mutex_unlock(&wl->mutex);
1039
1040 return ret;
1041}
1042
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001043int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044{
1045 int ret = 0;
1046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 wl1271_notice("power down");
1048
1049 if (wl->state != WL1271_STATE_PLT) {
1050 wl1271_error("cannot power down because not in PLT "
1051 "state: %d", wl->state);
1052 ret = -EBUSY;
1053 goto out;
1054 }
1055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056 wl1271_power_off(wl);
1057
1058 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001059 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001062 wl1271_disable_interrupts(wl);
1063 wl1271_flush_deferred_work(wl);
1064 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001065 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001066 mutex_lock(&wl->mutex);
1067out:
1068 return ret;
1069}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001070
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001071int wl1271_plt_stop(struct wl1271 *wl)
1072{
1073 int ret;
1074
1075 mutex_lock(&wl->mutex);
1076 ret = __wl1271_plt_stop(wl);
1077 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 return ret;
1079}
1080
Johannes Berg7bb45682011-02-24 14:42:06 +01001081static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082{
1083 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001084 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001085 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001086 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
Ido Yarivb07d4032011-03-01 15:14:43 +02001088 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1089
1090 if (wl->bss_type == BSS_TYPE_AP_BSS)
1091 hlid = wl1271_tx_get_hlid(skb);
1092
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001093 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001094
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001095 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001096
1097 /*
1098 * The workqueue is slow to process the tx_queue and we need stop
1099 * the queue here, otherwise the queue will get too long.
1100 */
1101 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1102 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1103 ieee80211_stop_queues(wl->hw);
1104 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1105 }
1106
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001107 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001108 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001109 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1110 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1111 } else {
1112 skb_queue_tail(&wl->tx_queue[q], skb);
1113 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001114
1115 /*
1116 * The chip specific setup must run before the first TX packet -
1117 * before that, the tx_work will not be initialized!
1118 */
1119
Ido Yarivb07d4032011-03-01 15:14:43 +02001120 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1121 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001122 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001123
1124 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001125}
1126
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001127static struct notifier_block wl1271_dev_notifier = {
1128 .notifier_call = wl1271_dev_notify,
1129};
1130
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001131static int wl1271_op_start(struct ieee80211_hw *hw)
1132{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001133 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1134
1135 /*
1136 * We have to delay the booting of the hardware because
1137 * we need to know the local MAC address before downloading and
1138 * initializing the firmware. The MAC address cannot be changed
1139 * after boot, and without the proper MAC address, the firmware
1140 * will not function properly.
1141 *
1142 * The MAC address is first known when the corresponding interface
1143 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001144 *
1145 * In addition, we currently have different firmwares for AP and managed
1146 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001147 */
1148
1149 return 0;
1150}
1151
1152static void wl1271_op_stop(struct ieee80211_hw *hw)
1153{
1154 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1155}
1156
1157static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1158 struct ieee80211_vif *vif)
1159{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001161 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001162 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001164 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001165
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001166 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1167 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168
1169 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001170 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001171 wl1271_debug(DEBUG_MAC80211,
1172 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001173 ret = -EBUSY;
1174 goto out;
1175 }
1176
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001177 switch (vif->type) {
1178 case NL80211_IFTYPE_STATION:
1179 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001180 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001181 break;
1182 case NL80211_IFTYPE_ADHOC:
1183 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001184 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001185 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001186 case NL80211_IFTYPE_AP:
1187 wl->bss_type = BSS_TYPE_AP_BSS;
1188 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001189 default:
1190 ret = -EOPNOTSUPP;
1191 goto out;
1192 }
1193
1194 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195
1196 if (wl->state != WL1271_STATE_OFF) {
1197 wl1271_error("cannot start because not in off state: %d",
1198 wl->state);
1199 ret = -EBUSY;
1200 goto out;
1201 }
1202
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001203 while (retries) {
1204 retries--;
1205 ret = wl1271_chip_wakeup(wl);
1206 if (ret < 0)
1207 goto power_off;
1208
1209 ret = wl1271_boot(wl);
1210 if (ret < 0)
1211 goto power_off;
1212
1213 ret = wl1271_hw_init(wl);
1214 if (ret < 0)
1215 goto irq_disable;
1216
Eliad Peller71125ab2010-10-28 21:46:43 +02001217 booted = true;
1218 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001220irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001221 mutex_unlock(&wl->mutex);
1222 /* Unlocking the mutex in the middle of handling is
1223 inherently unsafe. In this case we deem it safe to do,
1224 because we need to let any possibly pending IRQ out of
1225 the system (and while we are WL1271_STATE_OFF the IRQ
1226 work function will not do anything.) Also, any other
1227 possible concurrent operations will fail due to the
1228 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001229 wl1271_disable_interrupts(wl);
1230 wl1271_flush_deferred_work(wl);
1231 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001232 mutex_lock(&wl->mutex);
1233power_off:
1234 wl1271_power_off(wl);
1235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236
Eliad Peller71125ab2010-10-28 21:46:43 +02001237 if (!booted) {
1238 wl1271_error("firmware boot failed despite %d retries",
1239 WL1271_BOOT_RETRIES);
1240 goto out;
1241 }
1242
1243 wl->vif = vif;
1244 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001245 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001246
1247 /* update hw/fw version info in wiphy struct */
1248 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001249 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001250 sizeof(wiphy->fw_version));
1251
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001252 /*
1253 * Now we know if 11a is supported (info from the NVS), so disable
1254 * 11a channels if not supported
1255 */
1256 if (!wl->enable_11a)
1257 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1258
1259 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1260 wl->enable_11a ? "" : "not ");
1261
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001262out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 mutex_unlock(&wl->mutex);
1264
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001265 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001266 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268 return ret;
1269}
1270
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001271static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 int i;
1274
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001275 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001277 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001279 list_del(&wl->list);
1280
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 WARN_ON(wl->state != WL1271_STATE_ON);
1282
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001283 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001284 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001285 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001286
Luciano Coelho08688d62010-07-08 17:50:07 +03001287 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001288 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1289 kfree(wl->scan.scanned_ch);
1290 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001291 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001292 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 }
1294
1295 wl->state = WL1271_STATE_OFF;
1296
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 mutex_unlock(&wl->mutex);
1298
Ido Yariva6208652011-03-01 15:14:41 +02001299 wl1271_disable_interrupts(wl);
1300 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001301 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001302 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001303 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001304 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001305 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306
1307 mutex_lock(&wl->mutex);
1308
1309 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001310 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 wl1271_power_off(wl);
1312
1313 memset(wl->bssid, 0, ETH_ALEN);
1314 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1315 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001317 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001318 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319
1320 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001321 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1323 wl->tx_blocks_available = 0;
1324 wl->tx_results_count = 0;
1325 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001326 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001327 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 wl->time_offset = 0;
1329 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001330 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001331 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001332 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001333 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001334 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001335 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001336 wl->ap_fw_ps_map = 0;
1337 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 for (i = 0; i < NUM_TX_QUEUES; i++)
1340 wl->tx_blocks_freed[i] = 0;
1341
1342 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001343
1344 kfree(wl->fw_status);
1345 wl->fw_status = NULL;
1346 kfree(wl->tx_res_if);
1347 wl->tx_res_if = NULL;
1348 kfree(wl->target_mem_map);
1349 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001350}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001351
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001352static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1353 struct ieee80211_vif *vif)
1354{
1355 struct wl1271 *wl = hw->priv;
1356
1357 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001358 /*
1359 * wl->vif can be null here if someone shuts down the interface
1360 * just when hardware recovery has been started.
1361 */
1362 if (wl->vif) {
1363 WARN_ON(wl->vif != vif);
1364 __wl1271_op_remove_interface(wl);
1365 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001366
Juuso Oikarinen67353292010-11-18 15:19:02 +02001367 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001368 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369}
1370
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001371static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1372{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001373 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001374
1375 /* combine requested filters with current filter config */
1376 filters = wl->filters | filters;
1377
1378 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1379
1380 if (filters & FIF_PROMISC_IN_BSS) {
1381 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1382 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1383 wl->rx_config |= CFG_BSSID_FILTER_EN;
1384 }
1385 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1386 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1387 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1388 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1389 }
1390 if (filters & FIF_OTHER_BSS) {
1391 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1392 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1393 }
1394 if (filters & FIF_CONTROL) {
1395 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1396 wl->rx_filter |= CFG_RX_CTL_EN;
1397 }
1398 if (filters & FIF_FCSFAIL) {
1399 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1400 wl->rx_filter |= CFG_RX_FCS_ERROR;
1401 }
1402}
1403
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001404static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001405{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001406 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001407 /* we need to use a dummy BSSID for now */
1408 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1409 0xad, 0xbe, 0xef };
1410
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001411 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1412
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001413 /* pass through frames from all BSS */
1414 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1415
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001416 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001417 if (ret < 0)
1418 goto out;
1419
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001420 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001421
1422out:
1423 return ret;
1424}
1425
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001426static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001427{
1428 int ret;
1429
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001430 /*
1431 * One of the side effects of the JOIN command is that is clears
1432 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1433 * to a WPA/WPA2 access point will therefore kill the data-path.
1434 * Currently there is no supported scenario for JOIN during
1435 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1436 * must be handled somehow.
1437 *
1438 */
1439 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1440 wl1271_info("JOIN while associated.");
1441
1442 if (set_assoc)
1443 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1444
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001445 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1446 if (ret < 0)
1447 goto out;
1448
1449 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1450
1451 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1452 goto out;
1453
1454 /*
1455 * The join command disable the keep-alive mode, shut down its process,
1456 * and also clear the template config, so we need to reset it all after
1457 * the join. The acx_aid starts the keep-alive process, and the order
1458 * of the commands below is relevant.
1459 */
1460 ret = wl1271_acx_keep_alive_mode(wl, true);
1461 if (ret < 0)
1462 goto out;
1463
1464 ret = wl1271_acx_aid(wl, wl->aid);
1465 if (ret < 0)
1466 goto out;
1467
1468 ret = wl1271_cmd_build_klv_null_data(wl);
1469 if (ret < 0)
1470 goto out;
1471
1472 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1473 ACX_KEEP_ALIVE_TPL_VALID);
1474 if (ret < 0)
1475 goto out;
1476
1477out:
1478 return ret;
1479}
1480
1481static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001482{
1483 int ret;
1484
1485 /* to stop listening to a channel, we disconnect */
1486 ret = wl1271_cmd_disconnect(wl);
1487 if (ret < 0)
1488 goto out;
1489
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001490 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001491 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001492
1493 /* stop filterting packets based on bssid */
1494 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001495
1496out:
1497 return ret;
1498}
1499
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001500static void wl1271_set_band_rate(struct wl1271 *wl)
1501{
1502 if (wl->band == IEEE80211_BAND_2GHZ)
1503 wl->basic_rate_set = wl->conf.tx.basic_rate;
1504 else
1505 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1506}
1507
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001508static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001509{
1510 int ret;
1511
1512 if (idle) {
1513 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1514 ret = wl1271_unjoin(wl);
1515 if (ret < 0)
1516 goto out;
1517 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001518 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001519 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001520 if (ret < 0)
1521 goto out;
1522 ret = wl1271_acx_keep_alive_config(
1523 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1524 ACX_KEEP_ALIVE_TPL_INVALID);
1525 if (ret < 0)
1526 goto out;
1527 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1528 } else {
1529 /* increment the session counter */
1530 wl->session_counter++;
1531 if (wl->session_counter >= SESSION_COUNTER_MAX)
1532 wl->session_counter = 0;
1533 ret = wl1271_dummy_join(wl);
1534 if (ret < 0)
1535 goto out;
1536 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1537 }
1538
1539out:
1540 return ret;
1541}
1542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1544{
1545 struct wl1271 *wl = hw->priv;
1546 struct ieee80211_conf *conf = &hw->conf;
1547 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001548 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001549
1550 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1551
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001552 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1553 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554 channel,
1555 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001556 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001557 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1558 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001560 /*
1561 * mac80211 will go to idle nearly immediately after transmitting some
1562 * frames, such as the deauth. To make sure those frames reach the air,
1563 * wait here until the TX queue is fully flushed.
1564 */
1565 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1566 (conf->flags & IEEE80211_CONF_IDLE))
1567 wl1271_tx_flush(wl);
1568
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569 mutex_lock(&wl->mutex);
1570
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001571 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1572 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001573 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001574 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001575
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001576 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1577
Ido Yariva6208652011-03-01 15:14:41 +02001578 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 if (ret < 0)
1580 goto out;
1581
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001582 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001583 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1584 ((wl->band != conf->channel->band) ||
1585 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001586 wl->band = conf->channel->band;
1587 wl->channel = channel;
1588
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001589 if (!is_ap) {
1590 /*
1591 * FIXME: the mac80211 should really provide a fixed
1592 * rate to use here. for now, just use the smallest
1593 * possible rate for the band as a fixed rate for
1594 * association frames and other control messages.
1595 */
1596 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1597 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001598
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001599 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1600 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001601 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001602 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001603 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001604
1605 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1606 ret = wl1271_join(wl, false);
1607 if (ret < 0)
1608 wl1271_warning("cmd join on channel "
1609 "failed %d", ret);
1610 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001611 }
1612 }
1613
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001614 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1615 ret = wl1271_sta_handle_idle(wl,
1616 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001617 if (ret < 0)
1618 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 }
1620
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001621 /*
1622 * if mac80211 changes the PSM mode, make sure the mode is not
1623 * incorrectly changed after the pspoll failure active window.
1624 */
1625 if (changed & IEEE80211_CONF_CHANGE_PS)
1626 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1627
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001628 if (conf->flags & IEEE80211_CONF_PS &&
1629 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1630 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631
1632 /*
1633 * We enter PSM only if we're already associated.
1634 * If we're not, we'll enter it when joining an SSID,
1635 * through the bss_info_changed() hook.
1636 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001637 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001638 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001639 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001640 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001641 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001643 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001644 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001646 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001648 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001649 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001650 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001651 }
1652
1653 if (conf->power_level != wl->power_level) {
1654 ret = wl1271_acx_tx_power(wl, conf->power_level);
1655 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001656 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657
1658 wl->power_level = conf->power_level;
1659 }
1660
1661out_sleep:
1662 wl1271_ps_elp_sleep(wl);
1663
1664out:
1665 mutex_unlock(&wl->mutex);
1666
1667 return ret;
1668}
1669
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001670struct wl1271_filter_params {
1671 bool enabled;
1672 int mc_list_length;
1673 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1674};
1675
Jiri Pirko22bedad32010-04-01 21:22:57 +00001676static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1677 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001678{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001679 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001680 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001681 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001682
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001683 if (unlikely(wl->state == WL1271_STATE_OFF))
1684 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001685
Juuso Oikarinen74441132009-10-13 12:47:53 +03001686 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001687 if (!fp) {
1688 wl1271_error("Out of memory setting filters.");
1689 return 0;
1690 }
1691
1692 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001693 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001694 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1695 fp->enabled = false;
1696 } else {
1697 fp->enabled = true;
1698 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001699 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001700 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001701 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001702 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001703 }
1704
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001705 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001706}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001708#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1709 FIF_ALLMULTI | \
1710 FIF_FCSFAIL | \
1711 FIF_BCN_PRBRESP_PROMISC | \
1712 FIF_CONTROL | \
1713 FIF_OTHER_BSS)
1714
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1716 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001717 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001719 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001721 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722
Arik Nemtsov7d057862010-10-16 19:25:35 +02001723 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1724 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001726 mutex_lock(&wl->mutex);
1727
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001728 *total &= WL1271_SUPPORTED_FILTERS;
1729 changed &= WL1271_SUPPORTED_FILTERS;
1730
1731 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001732 goto out;
1733
Ido Yariva6208652011-03-01 15:14:41 +02001734 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001735 if (ret < 0)
1736 goto out;
1737
Arik Nemtsov7d057862010-10-16 19:25:35 +02001738 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1739 if (*total & FIF_ALLMULTI)
1740 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1741 else if (fp)
1742 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1743 fp->mc_list,
1744 fp->mc_list_length);
1745 if (ret < 0)
1746 goto out_sleep;
1747 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001748
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001749 /* determine, whether supported filter values have changed */
1750 if (changed == 0)
1751 goto out_sleep;
1752
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001753 /* configure filters */
1754 wl->filters = *total;
1755 wl1271_configure_filters(wl, 0);
1756
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001757 /* apply configured filters */
1758 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1759 if (ret < 0)
1760 goto out_sleep;
1761
1762out_sleep:
1763 wl1271_ps_elp_sleep(wl);
1764
1765out:
1766 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001767 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768}
1769
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001770static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1771 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1772 u16 tx_seq_16)
1773{
1774 struct wl1271_ap_key *ap_key;
1775 int i;
1776
1777 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1778
1779 if (key_size > MAX_KEY_SIZE)
1780 return -EINVAL;
1781
1782 /*
1783 * Find next free entry in ap_keys. Also check we are not replacing
1784 * an existing key.
1785 */
1786 for (i = 0; i < MAX_NUM_KEYS; i++) {
1787 if (wl->recorded_ap_keys[i] == NULL)
1788 break;
1789
1790 if (wl->recorded_ap_keys[i]->id == id) {
1791 wl1271_warning("trying to record key replacement");
1792 return -EINVAL;
1793 }
1794 }
1795
1796 if (i == MAX_NUM_KEYS)
1797 return -EBUSY;
1798
1799 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1800 if (!ap_key)
1801 return -ENOMEM;
1802
1803 ap_key->id = id;
1804 ap_key->key_type = key_type;
1805 ap_key->key_size = key_size;
1806 memcpy(ap_key->key, key, key_size);
1807 ap_key->hlid = hlid;
1808 ap_key->tx_seq_32 = tx_seq_32;
1809 ap_key->tx_seq_16 = tx_seq_16;
1810
1811 wl->recorded_ap_keys[i] = ap_key;
1812 return 0;
1813}
1814
1815static void wl1271_free_ap_keys(struct wl1271 *wl)
1816{
1817 int i;
1818
1819 for (i = 0; i < MAX_NUM_KEYS; i++) {
1820 kfree(wl->recorded_ap_keys[i]);
1821 wl->recorded_ap_keys[i] = NULL;
1822 }
1823}
1824
1825static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1826{
1827 int i, ret = 0;
1828 struct wl1271_ap_key *key;
1829 bool wep_key_added = false;
1830
1831 for (i = 0; i < MAX_NUM_KEYS; i++) {
1832 if (wl->recorded_ap_keys[i] == NULL)
1833 break;
1834
1835 key = wl->recorded_ap_keys[i];
1836 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1837 key->id, key->key_type,
1838 key->key_size, key->key,
1839 key->hlid, key->tx_seq_32,
1840 key->tx_seq_16);
1841 if (ret < 0)
1842 goto out;
1843
1844 if (key->key_type == KEY_WEP)
1845 wep_key_added = true;
1846 }
1847
1848 if (wep_key_added) {
1849 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1850 if (ret < 0)
1851 goto out;
1852 }
1853
1854out:
1855 wl1271_free_ap_keys(wl);
1856 return ret;
1857}
1858
1859static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1860 u8 key_size, const u8 *key, u32 tx_seq_32,
1861 u16 tx_seq_16, struct ieee80211_sta *sta)
1862{
1863 int ret;
1864 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1865
1866 if (is_ap) {
1867 struct wl1271_station *wl_sta;
1868 u8 hlid;
1869
1870 if (sta) {
1871 wl_sta = (struct wl1271_station *)sta->drv_priv;
1872 hlid = wl_sta->hlid;
1873 } else {
1874 hlid = WL1271_AP_BROADCAST_HLID;
1875 }
1876
1877 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1878 /*
1879 * We do not support removing keys after AP shutdown.
1880 * Pretend we do to make mac80211 happy.
1881 */
1882 if (action != KEY_ADD_OR_REPLACE)
1883 return 0;
1884
1885 ret = wl1271_record_ap_key(wl, id,
1886 key_type, key_size,
1887 key, hlid, tx_seq_32,
1888 tx_seq_16);
1889 } else {
1890 ret = wl1271_cmd_set_ap_key(wl, action,
1891 id, key_type, key_size,
1892 key, hlid, tx_seq_32,
1893 tx_seq_16);
1894 }
1895
1896 if (ret < 0)
1897 return ret;
1898 } else {
1899 const u8 *addr;
1900 static const u8 bcast_addr[ETH_ALEN] = {
1901 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1902 };
1903
1904 addr = sta ? sta->addr : bcast_addr;
1905
1906 if (is_zero_ether_addr(addr)) {
1907 /* We dont support TX only encryption */
1908 return -EOPNOTSUPP;
1909 }
1910
1911 /* The wl1271 does not allow to remove unicast keys - they
1912 will be cleared automatically on next CMD_JOIN. Ignore the
1913 request silently, as we dont want the mac80211 to emit
1914 an error message. */
1915 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1916 return 0;
1917
1918 ret = wl1271_cmd_set_sta_key(wl, action,
1919 id, key_type, key_size,
1920 key, addr, tx_seq_32,
1921 tx_seq_16);
1922 if (ret < 0)
1923 return ret;
1924
1925 /* the default WEP key needs to be configured at least once */
1926 if (key_type == KEY_WEP) {
1927 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1928 wl->default_key);
1929 if (ret < 0)
1930 return ret;
1931 }
1932 }
1933
1934 return 0;
1935}
1936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1938 struct ieee80211_vif *vif,
1939 struct ieee80211_sta *sta,
1940 struct ieee80211_key_conf *key_conf)
1941{
1942 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001944 u32 tx_seq_32 = 0;
1945 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946 u8 key_type;
1947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1949
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001950 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001952 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 key_conf->keylen, key_conf->flags);
1954 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 mutex_lock(&wl->mutex);
1957
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001958 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1959 ret = -EAGAIN;
1960 goto out_unlock;
1961 }
1962
Ido Yariva6208652011-03-01 15:14:41 +02001963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 if (ret < 0)
1965 goto out_unlock;
1966
Johannes Berg97359d12010-08-10 09:46:38 +02001967 switch (key_conf->cipher) {
1968 case WLAN_CIPHER_SUITE_WEP40:
1969 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 key_type = KEY_WEP;
1971
1972 key_conf->hw_key_idx = key_conf->keyidx;
1973 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001974 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975 key_type = KEY_TKIP;
1976
1977 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001978 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1979 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001981 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982 key_type = KEY_AES;
1983
1984 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001985 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1986 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001988 case WL1271_CIPHER_SUITE_GEM:
1989 key_type = KEY_GEM;
1990 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1991 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1992 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001994 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995
1996 ret = -EOPNOTSUPP;
1997 goto out_sleep;
1998 }
1999
2000 switch (cmd) {
2001 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002002 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2003 key_conf->keyidx, key_type,
2004 key_conf->keylen, key_conf->key,
2005 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 if (ret < 0) {
2007 wl1271_error("Could not add or replace key");
2008 goto out_sleep;
2009 }
2010 break;
2011
2012 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002013 ret = wl1271_set_key(wl, KEY_REMOVE,
2014 key_conf->keyidx, key_type,
2015 key_conf->keylen, key_conf->key,
2016 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002017 if (ret < 0) {
2018 wl1271_error("Could not remove key");
2019 goto out_sleep;
2020 }
2021 break;
2022
2023 default:
2024 wl1271_error("Unsupported key cmd 0x%x", cmd);
2025 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026 break;
2027 }
2028
2029out_sleep:
2030 wl1271_ps_elp_sleep(wl);
2031
2032out_unlock:
2033 mutex_unlock(&wl->mutex);
2034
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035 return ret;
2036}
2037
2038static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002039 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002040 struct cfg80211_scan_request *req)
2041{
2042 struct wl1271 *wl = hw->priv;
2043 int ret;
2044 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002045 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046
2047 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2048
2049 if (req->n_ssids) {
2050 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002051 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 }
2053
2054 mutex_lock(&wl->mutex);
2055
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002056 if (wl->state == WL1271_STATE_OFF) {
2057 /*
2058 * We cannot return -EBUSY here because cfg80211 will expect
2059 * a call to ieee80211_scan_completed if we do - in this case
2060 * there won't be any call.
2061 */
2062 ret = -EAGAIN;
2063 goto out;
2064 }
2065
Ido Yariva6208652011-03-01 15:14:41 +02002066 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 if (ret < 0)
2068 goto out;
2069
Luciano Coelho5924f892010-08-04 03:46:22 +03002070 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071
2072 wl1271_ps_elp_sleep(wl);
2073
2074out:
2075 mutex_unlock(&wl->mutex);
2076
2077 return ret;
2078}
2079
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002080static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2081{
2082 struct wl1271 *wl = hw->priv;
2083 int ret = 0;
2084
2085 mutex_lock(&wl->mutex);
2086
2087 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2088 ret = -EAGAIN;
2089 goto out;
2090 }
2091
Ido Yariva6208652011-03-01 15:14:41 +02002092 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002093 if (ret < 0)
2094 goto out;
2095
2096 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2097 if (ret < 0)
2098 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2099
2100 wl1271_ps_elp_sleep(wl);
2101
2102out:
2103 mutex_unlock(&wl->mutex);
2104
2105 return ret;
2106}
2107
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2109{
2110 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002111 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002112
2113 mutex_lock(&wl->mutex);
2114
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002115 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2116 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002117 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002118 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002119
Ido Yariva6208652011-03-01 15:14:41 +02002120 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121 if (ret < 0)
2122 goto out;
2123
2124 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2125 if (ret < 0)
2126 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2127
2128 wl1271_ps_elp_sleep(wl);
2129
2130out:
2131 mutex_unlock(&wl->mutex);
2132
2133 return ret;
2134}
2135
Arik Nemtsove78a2872010-10-16 19:07:21 +02002136static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002137 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002138{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002139 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002140
2141 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002142 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002143 if (ptr[0] == WLAN_EID_SSID) {
2144 wl->ssid_len = ptr[1];
2145 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002146 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002147 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002148 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002149 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002150
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002151 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002152 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002153}
2154
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2156 struct ieee80211_bss_conf *bss_conf,
2157 u32 changed)
2158{
2159 int ret = 0;
2160
2161 if (changed & BSS_CHANGED_ERP_SLOT) {
2162 if (bss_conf->use_short_slot)
2163 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2164 else
2165 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2166 if (ret < 0) {
2167 wl1271_warning("Set slot time failed %d", ret);
2168 goto out;
2169 }
2170 }
2171
2172 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2173 if (bss_conf->use_short_preamble)
2174 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2175 else
2176 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2177 }
2178
2179 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2180 if (bss_conf->use_cts_prot)
2181 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2182 else
2183 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2184 if (ret < 0) {
2185 wl1271_warning("Set ctsprotect failed %d", ret);
2186 goto out;
2187 }
2188 }
2189
2190out:
2191 return ret;
2192}
2193
2194static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2195 struct ieee80211_vif *vif,
2196 struct ieee80211_bss_conf *bss_conf,
2197 u32 changed)
2198{
2199 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2200 int ret = 0;
2201
2202 if ((changed & BSS_CHANGED_BEACON_INT)) {
2203 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2204 bss_conf->beacon_int);
2205
2206 wl->beacon_int = bss_conf->beacon_int;
2207 }
2208
2209 if ((changed & BSS_CHANGED_BEACON)) {
2210 struct ieee80211_hdr *hdr;
2211 int ieoffset = offsetof(struct ieee80211_mgmt,
2212 u.beacon.variable);
2213 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2214 u16 tmpl_id;
2215
2216 if (!beacon)
2217 goto out;
2218
2219 wl1271_debug(DEBUG_MASTER, "beacon updated");
2220
2221 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2222 if (ret < 0) {
2223 dev_kfree_skb(beacon);
2224 goto out;
2225 }
2226 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2227 CMD_TEMPL_BEACON;
2228 ret = wl1271_cmd_template_set(wl, tmpl_id,
2229 beacon->data,
2230 beacon->len, 0,
2231 wl1271_tx_min_rate_get(wl));
2232 if (ret < 0) {
2233 dev_kfree_skb(beacon);
2234 goto out;
2235 }
2236
2237 hdr = (struct ieee80211_hdr *) beacon->data;
2238 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2239 IEEE80211_STYPE_PROBE_RESP);
2240
2241 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2242 CMD_TEMPL_PROBE_RESPONSE;
2243 ret = wl1271_cmd_template_set(wl,
2244 tmpl_id,
2245 beacon->data,
2246 beacon->len, 0,
2247 wl1271_tx_min_rate_get(wl));
2248 dev_kfree_skb(beacon);
2249 if (ret < 0)
2250 goto out;
2251 }
2252
2253out:
2254 return ret;
2255}
2256
2257/* AP mode changes */
2258static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002259 struct ieee80211_vif *vif,
2260 struct ieee80211_bss_conf *bss_conf,
2261 u32 changed)
2262{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002263 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002264
Arik Nemtsove78a2872010-10-16 19:07:21 +02002265 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2266 u32 rates = bss_conf->basic_rates;
2267 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002268
Arik Nemtsove78a2872010-10-16 19:07:21 +02002269 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2270 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2271 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2272 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002273
Arik Nemtsove78a2872010-10-16 19:07:21 +02002274 /* update the AP management rate policy with the new rates */
2275 mgmt_rc.enabled_rates = wl->basic_rate_set;
2276 mgmt_rc.long_retry_limit = 10;
2277 mgmt_rc.short_retry_limit = 10;
2278 mgmt_rc.aflags = 0;
2279 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2280 ACX_TX_AP_MODE_MGMT_RATE);
2281 if (ret < 0) {
2282 wl1271_error("AP mgmt policy change failed %d", ret);
2283 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002284 }
2285 }
2286
Arik Nemtsove78a2872010-10-16 19:07:21 +02002287 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2288 if (ret < 0)
2289 goto out;
2290
2291 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2292 if (bss_conf->enable_beacon) {
2293 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2294 ret = wl1271_cmd_start_bss(wl);
2295 if (ret < 0)
2296 goto out;
2297
2298 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2299 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002300
2301 ret = wl1271_ap_init_hwenc(wl);
2302 if (ret < 0)
2303 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002304 }
2305 } else {
2306 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2307 ret = wl1271_cmd_stop_bss(wl);
2308 if (ret < 0)
2309 goto out;
2310
2311 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2312 wl1271_debug(DEBUG_AP, "stopped AP");
2313 }
2314 }
2315 }
2316
2317 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2318 if (ret < 0)
2319 goto out;
2320out:
2321 return;
2322}
2323
2324/* STA/IBSS mode changes */
2325static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2326 struct ieee80211_vif *vif,
2327 struct ieee80211_bss_conf *bss_conf,
2328 u32 changed)
2329{
2330 bool do_join = false, set_assoc = false;
2331 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002332 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002333 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002334 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002335 bool sta_exists = false;
2336 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002337
2338 if (is_ibss) {
2339 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2340 changed);
2341 if (ret < 0)
2342 goto out;
2343 }
2344
2345 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2346 do_join = true;
2347
2348 /* Need to update the SSID (for filtering etc) */
2349 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2350 do_join = true;
2351
2352 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002353 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2354 bss_conf->enable_beacon ? "enabled" : "disabled");
2355
2356 if (bss_conf->enable_beacon)
2357 wl->set_bss_type = BSS_TYPE_IBSS;
2358 else
2359 wl->set_bss_type = BSS_TYPE_STA_BSS;
2360 do_join = true;
2361 }
2362
Arik Nemtsove78a2872010-10-16 19:07:21 +02002363 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002364 bool enable = false;
2365 if (bss_conf->cqm_rssi_thold)
2366 enable = true;
2367 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2368 bss_conf->cqm_rssi_thold,
2369 bss_conf->cqm_rssi_hyst);
2370 if (ret < 0)
2371 goto out;
2372 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2373 }
2374
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002375 if ((changed & BSS_CHANGED_BSSID) &&
2376 /*
2377 * Now we know the correct bssid, so we send a new join command
2378 * and enable the BSSID filter
2379 */
2380 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002381 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002382
Eliad Pellerfa287b82010-12-26 09:27:50 +01002383 if (!is_zero_ether_addr(wl->bssid)) {
2384 ret = wl1271_cmd_build_null_data(wl);
2385 if (ret < 0)
2386 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002387
Eliad Pellerfa287b82010-12-26 09:27:50 +01002388 ret = wl1271_build_qos_null_data(wl);
2389 if (ret < 0)
2390 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002391
Eliad Pellerfa287b82010-12-26 09:27:50 +01002392 /* filter out all packets not from this BSSID */
2393 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002394
Eliad Pellerfa287b82010-12-26 09:27:50 +01002395 /* Need to update the BSSID (for filtering etc) */
2396 do_join = true;
2397 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002398 }
2399
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002400 rcu_read_lock();
2401 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2402 if (sta) {
2403 /* save the supp_rates of the ap */
2404 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2405 if (sta->ht_cap.ht_supported)
2406 sta_rate_set |=
2407 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002408 sta_ht_cap = sta->ht_cap;
2409 sta_exists = true;
2410 }
2411 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002412
Arik Nemtsova1008852011-02-12 23:24:20 +02002413 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002414 /* handle new association with HT and HT information change */
2415 if ((changed & BSS_CHANGED_HT) &&
2416 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002417 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002418 true);
2419 if (ret < 0) {
2420 wl1271_warning("Set ht cap true failed %d",
2421 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002422 goto out;
2423 }
2424 ret = wl1271_acx_set_ht_information(wl,
2425 bss_conf->ht_operation_mode);
2426 if (ret < 0) {
2427 wl1271_warning("Set ht information failed %d",
2428 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002429 goto out;
2430 }
2431 }
2432 /* handle new association without HT and disassociation */
2433 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002434 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002435 false);
2436 if (ret < 0) {
2437 wl1271_warning("Set ht cap false failed %d",
2438 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002439 goto out;
2440 }
2441 }
2442 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002443
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002446 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002447 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002449 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002451 wl->ps_poll_failures = 0;
2452
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002453 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002454 * use basic rates from AP, and determine lowest rate
2455 * to use with control frames.
2456 */
2457 rates = bss_conf->basic_rates;
2458 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2459 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002460 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002461 if (sta_rate_set)
2462 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2463 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002464 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002465 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002466 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002467
2468 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002469 * with wl1271, we don't need to update the
2470 * beacon_int and dtim_period, because the firmware
2471 * updates it by itself when the first beacon is
2472 * received after a join.
2473 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002474 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2475 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002476 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002478 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002479 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002480 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002481 dev_kfree_skb(wl->probereq);
2482 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2483 ieoffset = offsetof(struct ieee80211_mgmt,
2484 u.probe_req.variable);
2485 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002486
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002487 /* enable the connection monitoring feature */
2488 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002489 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002490 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491
2492 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002493 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2494 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002495 enum wl1271_cmd_ps_mode mode;
2496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002497 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002498 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002499 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002500 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002501 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002502 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002503 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002504 } else {
2505 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002506 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002507 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002508 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002509
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002510 /* free probe-request template */
2511 dev_kfree_skb(wl->probereq);
2512 wl->probereq = NULL;
2513
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002514 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002515 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002516
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002517 /* revert back to minimum rates for the current band */
2518 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002519 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002520 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002521 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002522 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002523
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002524 /* disable connection monitor features */
2525 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002526
2527 /* Disable the keep-alive feature */
2528 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002529 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002530 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002531
2532 /* restore the bssid filter and go to dummy bssid */
2533 wl1271_unjoin(wl);
2534 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535 }
2536 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002537
Arik Nemtsove78a2872010-10-16 19:07:21 +02002538 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2539 if (ret < 0)
2540 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002542 if (changed & BSS_CHANGED_ARP_FILTER) {
2543 __be32 addr = bss_conf->arp_addr_list[0];
2544 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2545
Eliad Pellerc5312772010-12-09 11:31:27 +02002546 if (bss_conf->arp_addr_cnt == 1 &&
2547 bss_conf->arp_filter_enabled) {
2548 /*
2549 * The template should have been configured only upon
2550 * association. however, it seems that the correct ip
2551 * isn't being set (when sending), so we have to
2552 * reconfigure the template upon every ip change.
2553 */
2554 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2555 if (ret < 0) {
2556 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002557 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002558 }
2559
2560 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002561 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002562 addr);
2563 } else
2564 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002565
2566 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002567 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002568 }
2569
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002570 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002571 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002572 if (ret < 0) {
2573 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002574 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002575 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002576 }
2577
Arik Nemtsove78a2872010-10-16 19:07:21 +02002578out:
2579 return;
2580}
2581
2582static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2583 struct ieee80211_vif *vif,
2584 struct ieee80211_bss_conf *bss_conf,
2585 u32 changed)
2586{
2587 struct wl1271 *wl = hw->priv;
2588 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2589 int ret;
2590
2591 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2592 (int)changed);
2593
2594 mutex_lock(&wl->mutex);
2595
2596 if (unlikely(wl->state == WL1271_STATE_OFF))
2597 goto out;
2598
Ido Yariva6208652011-03-01 15:14:41 +02002599 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002600 if (ret < 0)
2601 goto out;
2602
2603 if (is_ap)
2604 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2605 else
2606 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2607
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002608 wl1271_ps_elp_sleep(wl);
2609
2610out:
2611 mutex_unlock(&wl->mutex);
2612}
2613
Kalle Valoc6999d82010-02-18 13:25:41 +02002614static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2615 const struct ieee80211_tx_queue_params *params)
2616{
2617 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002618 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002619 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002620
2621 mutex_lock(&wl->mutex);
2622
2623 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2624
Kalle Valo4695dc92010-03-18 12:26:38 +02002625 if (params->uapsd)
2626 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2627 else
2628 ps_scheme = CONF_PS_SCHEME_LEGACY;
2629
Arik Nemtsov488fc542010-10-16 20:33:45 +02002630 if (wl->state == WL1271_STATE_OFF) {
2631 /*
2632 * If the state is off, the parameters will be recorded and
2633 * configured on init. This happens in AP-mode.
2634 */
2635 struct conf_tx_ac_category *conf_ac =
2636 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2637 struct conf_tx_tid *conf_tid =
2638 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2639
2640 conf_ac->ac = wl1271_tx_get_queue(queue);
2641 conf_ac->cw_min = (u8)params->cw_min;
2642 conf_ac->cw_max = params->cw_max;
2643 conf_ac->aifsn = params->aifs;
2644 conf_ac->tx_op_limit = params->txop << 5;
2645
2646 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2647 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2648 conf_tid->tsid = wl1271_tx_get_queue(queue);
2649 conf_tid->ps_scheme = ps_scheme;
2650 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2651 conf_tid->apsd_conf[0] = 0;
2652 conf_tid->apsd_conf[1] = 0;
2653 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002654 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002655 if (ret < 0)
2656 goto out;
2657
2658 /*
2659 * the txop is confed in units of 32us by the mac80211,
2660 * we need us
2661 */
2662 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2663 params->cw_min, params->cw_max,
2664 params->aifs, params->txop << 5);
2665 if (ret < 0)
2666 goto out_sleep;
2667
2668 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2669 CONF_CHANNEL_TYPE_EDCF,
2670 wl1271_tx_get_queue(queue),
2671 ps_scheme, CONF_ACK_POLICY_LEGACY,
2672 0, 0);
2673 if (ret < 0)
2674 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002675
2676out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002677 wl1271_ps_elp_sleep(wl);
2678 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002679
2680out:
2681 mutex_unlock(&wl->mutex);
2682
2683 return ret;
2684}
2685
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002686static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2687{
2688
2689 struct wl1271 *wl = hw->priv;
2690 u64 mactime = ULLONG_MAX;
2691 int ret;
2692
2693 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2694
2695 mutex_lock(&wl->mutex);
2696
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002697 if (unlikely(wl->state == WL1271_STATE_OFF))
2698 goto out;
2699
Ido Yariva6208652011-03-01 15:14:41 +02002700 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002701 if (ret < 0)
2702 goto out;
2703
2704 ret = wl1271_acx_tsf_info(wl, &mactime);
2705 if (ret < 0)
2706 goto out_sleep;
2707
2708out_sleep:
2709 wl1271_ps_elp_sleep(wl);
2710
2711out:
2712 mutex_unlock(&wl->mutex);
2713 return mactime;
2714}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002715
John W. Linvilleece550d2010-07-28 16:41:06 -04002716static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2717 struct survey_info *survey)
2718{
2719 struct wl1271 *wl = hw->priv;
2720 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002721
John W. Linvilleece550d2010-07-28 16:41:06 -04002722 if (idx != 0)
2723 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002724
John W. Linvilleece550d2010-07-28 16:41:06 -04002725 survey->channel = conf->channel;
2726 survey->filled = SURVEY_INFO_NOISE_DBM;
2727 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002728
John W. Linvilleece550d2010-07-28 16:41:06 -04002729 return 0;
2730}
2731
Arik Nemtsov409622e2011-02-23 00:22:29 +02002732static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002733 struct ieee80211_sta *sta,
2734 u8 *hlid)
2735{
2736 struct wl1271_station *wl_sta;
2737 int id;
2738
2739 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2740 if (id >= AP_MAX_STATIONS) {
2741 wl1271_warning("could not allocate HLID - too much stations");
2742 return -EBUSY;
2743 }
2744
2745 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002746 __set_bit(id, wl->ap_hlid_map);
2747 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2748 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002749 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002750 return 0;
2751}
2752
Arik Nemtsov409622e2011-02-23 00:22:29 +02002753static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002754{
2755 int id = hlid - WL1271_AP_STA_HLID_START;
2756
Arik Nemtsov409622e2011-02-23 00:22:29 +02002757 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2758 return;
2759
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002760 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002761 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002762 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002763 __clear_bit(hlid, &wl->ap_ps_map);
2764 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002765}
2766
2767static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2768 struct ieee80211_vif *vif,
2769 struct ieee80211_sta *sta)
2770{
2771 struct wl1271 *wl = hw->priv;
2772 int ret = 0;
2773 u8 hlid;
2774
2775 mutex_lock(&wl->mutex);
2776
2777 if (unlikely(wl->state == WL1271_STATE_OFF))
2778 goto out;
2779
2780 if (wl->bss_type != BSS_TYPE_AP_BSS)
2781 goto out;
2782
2783 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2784
Arik Nemtsov409622e2011-02-23 00:22:29 +02002785 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002786 if (ret < 0)
2787 goto out;
2788
Ido Yariva6208652011-03-01 15:14:41 +02002789 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002790 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002791 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002792
2793 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2794 if (ret < 0)
2795 goto out_sleep;
2796
2797out_sleep:
2798 wl1271_ps_elp_sleep(wl);
2799
Arik Nemtsov409622e2011-02-23 00:22:29 +02002800out_free_sta:
2801 if (ret < 0)
2802 wl1271_free_sta(wl, hlid);
2803
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002804out:
2805 mutex_unlock(&wl->mutex);
2806 return ret;
2807}
2808
2809static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2810 struct ieee80211_vif *vif,
2811 struct ieee80211_sta *sta)
2812{
2813 struct wl1271 *wl = hw->priv;
2814 struct wl1271_station *wl_sta;
2815 int ret = 0, id;
2816
2817 mutex_lock(&wl->mutex);
2818
2819 if (unlikely(wl->state == WL1271_STATE_OFF))
2820 goto out;
2821
2822 if (wl->bss_type != BSS_TYPE_AP_BSS)
2823 goto out;
2824
2825 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2826
2827 wl_sta = (struct wl1271_station *)sta->drv_priv;
2828 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2829 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2830 goto out;
2831
Ido Yariva6208652011-03-01 15:14:41 +02002832 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002833 if (ret < 0)
2834 goto out;
2835
2836 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2837 if (ret < 0)
2838 goto out_sleep;
2839
Arik Nemtsov409622e2011-02-23 00:22:29 +02002840 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002841
2842out_sleep:
2843 wl1271_ps_elp_sleep(wl);
2844
2845out:
2846 mutex_unlock(&wl->mutex);
2847 return ret;
2848}
2849
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002850int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002851 enum ieee80211_ampdu_mlme_action action,
2852 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2853 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002854{
2855 struct wl1271 *wl = hw->priv;
2856 int ret;
2857
2858 mutex_lock(&wl->mutex);
2859
2860 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2861 ret = -EAGAIN;
2862 goto out;
2863 }
2864
Ido Yariva6208652011-03-01 15:14:41 +02002865 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002866 if (ret < 0)
2867 goto out;
2868
2869 switch (action) {
2870 case IEEE80211_AMPDU_RX_START:
2871 if (wl->ba_support) {
2872 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2873 true);
2874 if (!ret)
2875 wl->ba_rx_bitmap |= BIT(tid);
2876 } else {
2877 ret = -ENOTSUPP;
2878 }
2879 break;
2880
2881 case IEEE80211_AMPDU_RX_STOP:
2882 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2883 if (!ret)
2884 wl->ba_rx_bitmap &= ~BIT(tid);
2885 break;
2886
2887 /*
2888 * The BA initiator session management in FW independently.
2889 * Falling break here on purpose for all TX APDU commands.
2890 */
2891 case IEEE80211_AMPDU_TX_START:
2892 case IEEE80211_AMPDU_TX_STOP:
2893 case IEEE80211_AMPDU_TX_OPERATIONAL:
2894 ret = -EINVAL;
2895 break;
2896
2897 default:
2898 wl1271_error("Incorrect ampdu action id=%x\n", action);
2899 ret = -EINVAL;
2900 }
2901
2902 wl1271_ps_elp_sleep(wl);
2903
2904out:
2905 mutex_unlock(&wl->mutex);
2906
2907 return ret;
2908}
2909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910/* can't be const, mac80211 writes to this */
2911static struct ieee80211_rate wl1271_rates[] = {
2912 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002913 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2914 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002915 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002916 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2917 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2919 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002920 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2921 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002922 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2923 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002924 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2925 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2927 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002928 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2929 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002931 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2932 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002934 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2935 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002937 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2938 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002940 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2941 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002943 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2944 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002946 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2947 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002949 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2950 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951};
2952
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002953/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002955 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002956 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002957 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2958 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2959 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002960 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002961 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2962 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2963 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002964 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002965 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2966 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2967 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002968 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969};
2970
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002971/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002972static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002973 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002974 7, /* CONF_HW_RXTX_RATE_MCS7 */
2975 6, /* CONF_HW_RXTX_RATE_MCS6 */
2976 5, /* CONF_HW_RXTX_RATE_MCS5 */
2977 4, /* CONF_HW_RXTX_RATE_MCS4 */
2978 3, /* CONF_HW_RXTX_RATE_MCS3 */
2979 2, /* CONF_HW_RXTX_RATE_MCS2 */
2980 1, /* CONF_HW_RXTX_RATE_MCS1 */
2981 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002982
2983 11, /* CONF_HW_RXTX_RATE_54 */
2984 10, /* CONF_HW_RXTX_RATE_48 */
2985 9, /* CONF_HW_RXTX_RATE_36 */
2986 8, /* CONF_HW_RXTX_RATE_24 */
2987
2988 /* TI-specific rate */
2989 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2990
2991 7, /* CONF_HW_RXTX_RATE_18 */
2992 6, /* CONF_HW_RXTX_RATE_12 */
2993 3, /* CONF_HW_RXTX_RATE_11 */
2994 5, /* CONF_HW_RXTX_RATE_9 */
2995 4, /* CONF_HW_RXTX_RATE_6 */
2996 2, /* CONF_HW_RXTX_RATE_5_5 */
2997 1, /* CONF_HW_RXTX_RATE_2 */
2998 0 /* CONF_HW_RXTX_RATE_1 */
2999};
3000
Shahar Levie8b03a22010-10-13 16:09:39 +02003001/* 11n STA capabilities */
3002#define HW_RX_HIGHEST_RATE 72
3003
Shahar Levi00d20102010-11-08 11:20:10 +00003004#ifdef CONFIG_WL12XX_HT
3005#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003006 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3007 .ht_supported = true, \
3008 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3009 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3010 .mcs = { \
3011 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3012 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3013 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3014 }, \
3015}
Shahar Levi18357852010-10-13 16:09:41 +02003016#else
Shahar Levi00d20102010-11-08 11:20:10 +00003017#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003018 .ht_supported = false, \
3019}
3020#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022/* can't be const, mac80211 writes to this */
3023static struct ieee80211_supported_band wl1271_band_2ghz = {
3024 .channels = wl1271_channels,
3025 .n_channels = ARRAY_SIZE(wl1271_channels),
3026 .bitrates = wl1271_rates,
3027 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003028 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029};
3030
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003031/* 5 GHz data rates for WL1273 */
3032static struct ieee80211_rate wl1271_rates_5ghz[] = {
3033 { .bitrate = 60,
3034 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3035 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3036 { .bitrate = 90,
3037 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3038 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3039 { .bitrate = 120,
3040 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3041 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3042 { .bitrate = 180,
3043 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3044 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3045 { .bitrate = 240,
3046 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3047 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3048 { .bitrate = 360,
3049 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3050 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3051 { .bitrate = 480,
3052 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3053 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3054 { .bitrate = 540,
3055 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3056 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3057};
3058
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003059/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003060static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003061 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003062 { .hw_value = 8, .center_freq = 5040},
3063 { .hw_value = 9, .center_freq = 5045},
3064 { .hw_value = 11, .center_freq = 5055},
3065 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003066 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003067 { .hw_value = 34, .center_freq = 5170},
3068 { .hw_value = 36, .center_freq = 5180},
3069 { .hw_value = 38, .center_freq = 5190},
3070 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003071 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003072 { .hw_value = 44, .center_freq = 5220},
3073 { .hw_value = 46, .center_freq = 5230},
3074 { .hw_value = 48, .center_freq = 5240},
3075 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003076 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003077 { .hw_value = 60, .center_freq = 5300},
3078 { .hw_value = 64, .center_freq = 5320},
3079 { .hw_value = 100, .center_freq = 5500},
3080 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003081 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003082 { .hw_value = 112, .center_freq = 5560},
3083 { .hw_value = 116, .center_freq = 5580},
3084 { .hw_value = 120, .center_freq = 5600},
3085 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003086 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003087 { .hw_value = 132, .center_freq = 5660},
3088 { .hw_value = 136, .center_freq = 5680},
3089 { .hw_value = 140, .center_freq = 5700},
3090 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003091 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003092 { .hw_value = 157, .center_freq = 5785},
3093 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003094 { .hw_value = 165, .center_freq = 5825},
3095};
3096
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003097/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003098static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003099 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003100 7, /* CONF_HW_RXTX_RATE_MCS7 */
3101 6, /* CONF_HW_RXTX_RATE_MCS6 */
3102 5, /* CONF_HW_RXTX_RATE_MCS5 */
3103 4, /* CONF_HW_RXTX_RATE_MCS4 */
3104 3, /* CONF_HW_RXTX_RATE_MCS3 */
3105 2, /* CONF_HW_RXTX_RATE_MCS2 */
3106 1, /* CONF_HW_RXTX_RATE_MCS1 */
3107 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003108
3109 7, /* CONF_HW_RXTX_RATE_54 */
3110 6, /* CONF_HW_RXTX_RATE_48 */
3111 5, /* CONF_HW_RXTX_RATE_36 */
3112 4, /* CONF_HW_RXTX_RATE_24 */
3113
3114 /* TI-specific rate */
3115 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3116
3117 3, /* CONF_HW_RXTX_RATE_18 */
3118 2, /* CONF_HW_RXTX_RATE_12 */
3119 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3120 1, /* CONF_HW_RXTX_RATE_9 */
3121 0, /* CONF_HW_RXTX_RATE_6 */
3122 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3123 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3124 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3125};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003126
3127static struct ieee80211_supported_band wl1271_band_5ghz = {
3128 .channels = wl1271_channels_5ghz,
3129 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3130 .bitrates = wl1271_rates_5ghz,
3131 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003132 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003133};
3134
Tobias Klausera0ea9492010-05-20 10:38:11 +02003135static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003136 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3137 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3138};
3139
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003140static const struct ieee80211_ops wl1271_ops = {
3141 .start = wl1271_op_start,
3142 .stop = wl1271_op_stop,
3143 .add_interface = wl1271_op_add_interface,
3144 .remove_interface = wl1271_op_remove_interface,
3145 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003146 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003147 .configure_filter = wl1271_op_configure_filter,
3148 .tx = wl1271_op_tx,
3149 .set_key = wl1271_op_set_key,
3150 .hw_scan = wl1271_op_hw_scan,
3151 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003152 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003153 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003154 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003155 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003156 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003157 .sta_add = wl1271_op_sta_add,
3158 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003159 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003160 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003161};
3162
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003163
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003164u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003165{
3166 u8 idx;
3167
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003168 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003169
3170 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3171 wl1271_error("Illegal RX rate from HW: %d", rate);
3172 return 0;
3173 }
3174
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003175 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003176 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3177 wl1271_error("Unsupported RX rate from HW: %d", rate);
3178 return 0;
3179 }
3180
3181 return idx;
3182}
3183
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003184static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3185 struct device_attribute *attr,
3186 char *buf)
3187{
3188 struct wl1271 *wl = dev_get_drvdata(dev);
3189 ssize_t len;
3190
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003191 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003192
3193 mutex_lock(&wl->mutex);
3194 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3195 wl->sg_enabled);
3196 mutex_unlock(&wl->mutex);
3197
3198 return len;
3199
3200}
3201
3202static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3203 struct device_attribute *attr,
3204 const char *buf, size_t count)
3205{
3206 struct wl1271 *wl = dev_get_drvdata(dev);
3207 unsigned long res;
3208 int ret;
3209
3210 ret = strict_strtoul(buf, 10, &res);
3211
3212 if (ret < 0) {
3213 wl1271_warning("incorrect value written to bt_coex_mode");
3214 return count;
3215 }
3216
3217 mutex_lock(&wl->mutex);
3218
3219 res = !!res;
3220
3221 if (res == wl->sg_enabled)
3222 goto out;
3223
3224 wl->sg_enabled = res;
3225
3226 if (wl->state == WL1271_STATE_OFF)
3227 goto out;
3228
Ido Yariva6208652011-03-01 15:14:41 +02003229 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003230 if (ret < 0)
3231 goto out;
3232
3233 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3234 wl1271_ps_elp_sleep(wl);
3235
3236 out:
3237 mutex_unlock(&wl->mutex);
3238 return count;
3239}
3240
3241static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3242 wl1271_sysfs_show_bt_coex_state,
3243 wl1271_sysfs_store_bt_coex_state);
3244
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003245static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3246 struct device_attribute *attr,
3247 char *buf)
3248{
3249 struct wl1271 *wl = dev_get_drvdata(dev);
3250 ssize_t len;
3251
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003252 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003253
3254 mutex_lock(&wl->mutex);
3255 if (wl->hw_pg_ver >= 0)
3256 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3257 else
3258 len = snprintf(buf, len, "n/a\n");
3259 mutex_unlock(&wl->mutex);
3260
3261 return len;
3262}
3263
3264static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3265 wl1271_sysfs_show_hw_pg_ver, NULL);
3266
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003267int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268{
3269 int ret;
3270
3271 if (wl->mac80211_registered)
3272 return 0;
3273
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003274 ret = wl1271_fetch_nvs(wl);
3275 if (ret == 0) {
3276 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3277
3278 wl->mac_addr[0] = nvs_ptr[11];
3279 wl->mac_addr[1] = nvs_ptr[10];
3280 wl->mac_addr[2] = nvs_ptr[6];
3281 wl->mac_addr[3] = nvs_ptr[5];
3282 wl->mac_addr[4] = nvs_ptr[4];
3283 wl->mac_addr[5] = nvs_ptr[3];
3284 }
3285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003286 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3287
3288 ret = ieee80211_register_hw(wl->hw);
3289 if (ret < 0) {
3290 wl1271_error("unable to register mac80211 hw: %d", ret);
3291 return ret;
3292 }
3293
3294 wl->mac80211_registered = true;
3295
Eliad Pellerd60080a2010-11-24 12:53:16 +02003296 wl1271_debugfs_init(wl);
3297
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003298 register_netdevice_notifier(&wl1271_dev_notifier);
3299
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003300 wl1271_notice("loaded");
3301
3302 return 0;
3303}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003304EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003306void wl1271_unregister_hw(struct wl1271 *wl)
3307{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003308 if (wl->state == WL1271_STATE_PLT)
3309 __wl1271_plt_stop(wl);
3310
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003311 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003312 ieee80211_unregister_hw(wl->hw);
3313 wl->mac80211_registered = false;
3314
3315}
3316EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3317
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003318int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003320 static const u32 cipher_suites[] = {
3321 WLAN_CIPHER_SUITE_WEP40,
3322 WLAN_CIPHER_SUITE_WEP104,
3323 WLAN_CIPHER_SUITE_TKIP,
3324 WLAN_CIPHER_SUITE_CCMP,
3325 WL1271_CIPHER_SUITE_GEM,
3326 };
3327
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003328 /* The tx descriptor buffer and the TKIP space. */
3329 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3330 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331
3332 /* unit us */
3333 /* FIXME: find a proper value */
3334 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003335 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003336
3337 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003338 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003339 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003340 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003341 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003342 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003343 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003344 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3345 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003347 wl->hw->wiphy->cipher_suites = cipher_suites;
3348 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3349
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003350 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003351 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003352 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003353 /*
3354 * Maximum length of elements in scanning probe request templates
3355 * should be the maximum length possible for a template, without
3356 * the IEEE80211 header of the template
3357 */
3358 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3359 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003360
3361 /*
3362 * We keep local copies of the band structs because we need to
3363 * modify them on a per-device basis.
3364 */
3365 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3366 sizeof(wl1271_band_2ghz));
3367 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3368 sizeof(wl1271_band_5ghz));
3369
3370 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3371 &wl->bands[IEEE80211_BAND_2GHZ];
3372 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3373 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003374
Kalle Valo12bd8942010-03-18 12:26:33 +02003375 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003376 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003377
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003378 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3379
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003380 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003381
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003382 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3383
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003384 wl->hw->max_rx_aggregation_subframes = 8;
3385
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003386 return 0;
3387}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003388EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003389
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003390#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003391
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003392struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003393{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003394 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003395 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003396 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003397 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003398 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003399
3400 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3401 if (!hw) {
3402 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003403 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003404 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003405 }
3406
Julia Lawall929ebd32010-05-15 23:16:39 +02003407 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003408 if (!plat_dev) {
3409 wl1271_error("could not allocate platform_device");
3410 ret = -ENOMEM;
3411 goto err_plat_alloc;
3412 }
3413
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003414 wl = hw->priv;
3415 memset(wl, 0, sizeof(*wl));
3416
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003417 INIT_LIST_HEAD(&wl->list);
3418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003420 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003421
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003422 for (i = 0; i < NUM_TX_QUEUES; i++)
3423 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003424
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003425 for (i = 0; i < NUM_TX_QUEUES; i++)
3426 for (j = 0; j < AP_MAX_LINKS; j++)
3427 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3428
Ido Yariva6208652011-03-01 15:14:41 +02003429 skb_queue_head_init(&wl->deferred_rx_queue);
3430 skb_queue_head_init(&wl->deferred_tx_queue);
3431
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003432 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003433 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003434 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003435 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3436 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3437 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003438 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003439 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003441 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003442 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3443 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003444 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003445 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003446 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003447 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003448 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003449 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003450 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003451 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003452 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003453 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003454 wl->bss_type = MAX_BSS_TYPE;
3455 wl->set_bss_type = MAX_BSS_TYPE;
3456 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003457 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003458 wl->ap_ps_map = 0;
3459 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003460 wl->quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003462 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003463 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003464 wl->tx_frames[i] = NULL;
3465
3466 spin_lock_init(&wl->wl_lock);
3467
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003468 wl->state = WL1271_STATE_OFF;
3469 mutex_init(&wl->mutex);
3470
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003471 /* Apply default driver configuration. */
3472 wl1271_conf_init(wl);
3473
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003474 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3475 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3476 if (!wl->aggr_buf) {
3477 ret = -ENOMEM;
3478 goto err_hw;
3479 }
3480
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003481 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003482 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003483 if (ret) {
3484 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003485 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003486 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003487 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003488
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003489 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003490 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003491 if (ret < 0) {
3492 wl1271_error("failed to create sysfs file bt_coex_state");
3493 goto err_platform;
3494 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003495
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003496 /* Create sysfs file to get HW PG version */
3497 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3498 if (ret < 0) {
3499 wl1271_error("failed to create sysfs file hw_pg_ver");
3500 goto err_bt_coex_state;
3501 }
3502
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003503 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003504
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003505err_bt_coex_state:
3506 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3507
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003508err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003509 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003510
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003511err_aggr:
3512 free_pages((unsigned long)wl->aggr_buf, order);
3513
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003514err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003515 wl1271_debugfs_exit(wl);
3516 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003517
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003518err_plat_alloc:
3519 ieee80211_free_hw(hw);
3520
3521err_hw_alloc:
3522
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003523 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003524}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003525EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003526
3527int wl1271_free_hw(struct wl1271 *wl)
3528{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003529 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003530 free_pages((unsigned long)wl->aggr_buf,
3531 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003532 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003533
3534 wl1271_debugfs_exit(wl);
3535
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003536 vfree(wl->fw);
3537 wl->fw = NULL;
3538 kfree(wl->nvs);
3539 wl->nvs = NULL;
3540
3541 kfree(wl->fw_status);
3542 kfree(wl->tx_res_if);
3543
3544 ieee80211_free_hw(wl->hw);
3545
3546 return 0;
3547}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003548EXPORT_SYMBOL_GPL(wl1271_free_hw);
3549
Guy Eilam491bbd62011-01-12 10:33:29 +01003550u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003551EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003552module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003553MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3554
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003555MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003556MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003557MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");