blob: f24906f54a711032815ce24d0746b86368c0edc5 [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 Coelho12419cc2010-02-18 13:25:44 +0200437 struct conf_tx_ac_category *conf_ac;
438 struct conf_tx_tid *conf_tid;
439 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200441 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200442 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200443 return ret;
444
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200445 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200446 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200447 return ret;
448
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200449 ret = wl1271_cmd_ext_radio_parms(wl);
450 if (ret < 0)
451 return ret;
452
Shahar Levi48a61472011-03-06 16:32:08 +0200453 /* Chip-specific initializations */
454 ret = wl1271_chip_specific_init(wl);
455 if (ret < 0)
456 return ret;
457
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200458 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200459 if (ret < 0)
460 return ret;
461
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300462 ret = wl1271_acx_init_mem_config(wl);
463 if (ret < 0)
464 return ret;
465
Luciano Coelho12419cc2010-02-18 13:25:44 +0200466 /* PHY layer config */
467 ret = wl1271_init_phy_config(wl);
468 if (ret < 0)
469 goto out_free_memmap;
470
471 ret = wl1271_acx_dco_itrim_params(wl);
472 if (ret < 0)
473 goto out_free_memmap;
474
475 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200476 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200477 if (ret < 0)
478 goto out_free_memmap;
479
480 /* Bluetooth WLAN coexistence */
481 ret = wl1271_init_pta(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
485 /* Energy detection */
486 ret = wl1271_init_energy_detection(wl);
487 if (ret < 0)
488 goto out_free_memmap;
489
Gery Kahn1ec610e2011-02-01 03:03:08 -0600490 ret = wl1271_acx_sta_mem_cfg(wl);
491 if (ret < 0)
492 goto out_free_memmap;
493
Luciano Coelho12419cc2010-02-18 13:25:44 +0200494 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100495 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 if (ret < 0)
497 goto out_free_memmap;
498
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200499 /* Default TID/AC configuration */
500 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200501 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200502 conf_ac = &wl->conf.tx.ac_conf[i];
503 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
504 conf_ac->cw_max, conf_ac->aifsn,
505 conf_ac->tx_op_limit);
506 if (ret < 0)
507 goto out_free_memmap;
508
Luciano Coelho12419cc2010-02-18 13:25:44 +0200509 conf_tid = &wl->conf.tx.tid_conf[i];
510 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
511 conf_tid->channel_type,
512 conf_tid->tsid,
513 conf_tid->ps_scheme,
514 conf_tid->ack_policy,
515 conf_tid->apsd_conf[0],
516 conf_tid->apsd_conf[1]);
517 if (ret < 0)
518 goto out_free_memmap;
519 }
520
Luciano Coelho12419cc2010-02-18 13:25:44 +0200521 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200522 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200524 goto out_free_memmap;
525
526 /* Configure for CAM power saving (ie. always active) */
527 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
528 if (ret < 0)
529 goto out_free_memmap;
530
531 /* configure PM */
532 ret = wl1271_acx_pm_config(wl);
533 if (ret < 0)
534 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535
536 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200537
538 out_free_memmap:
539 kfree(wl->target_mem_map);
540 wl->target_mem_map = NULL;
541
542 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543}
544
Arik Nemtsovb622d992011-02-23 00:22:31 +0200545static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
546{
547 bool fw_ps;
548
549 /* only regulate station links */
550 if (hlid < WL1271_AP_STA_HLID_START)
551 return;
552
553 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
554
555 /*
556 * Wake up from high level PS if the STA is asleep with too little
557 * blocks in FW or if the STA is awake.
558 */
559 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
560 wl1271_ps_link_end(wl, hlid);
561
562 /* Start high-level PS if the STA is asleep with enough blocks in FW */
563 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
564 wl1271_ps_link_start(wl, hlid, true);
565}
566
567static void wl1271_irq_update_links_status(struct wl1271 *wl,
568 struct wl1271_fw_ap_status *status)
569{
570 u32 cur_fw_ps_map;
571 u8 hlid;
572
573 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
574 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
575 wl1271_debug(DEBUG_PSM,
576 "link ps prev 0x%x cur 0x%x changed 0x%x",
577 wl->ap_fw_ps_map, cur_fw_ps_map,
578 wl->ap_fw_ps_map ^ cur_fw_ps_map);
579
580 wl->ap_fw_ps_map = cur_fw_ps_map;
581 }
582
583 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
584 u8 cnt = status->tx_lnk_free_blks[hlid] -
585 wl->links[hlid].prev_freed_blks;
586
587 wl->links[hlid].prev_freed_blks =
588 status->tx_lnk_free_blks[hlid];
589 wl->links[hlid].allocated_blks -= cnt;
590
591 wl1271_irq_ps_regulate_link(wl, hlid,
592 wl->links[hlid].allocated_blks);
593 }
594}
595
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300596static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200597 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300598{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200599 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200600 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601 u32 total = 0;
602 int i;
603
Eliad Pellerc8bde242011-02-02 09:59:35 +0200604 if (wl->bss_type == BSS_TYPE_AP_BSS)
605 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
606 sizeof(struct wl1271_fw_ap_status), false);
607 else
608 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
609 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300610
611 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
612 "drv_rx_counter = %d, tx_results_counter = %d)",
613 status->intr,
614 status->fw_rx_counter,
615 status->drv_rx_counter,
616 status->tx_results_counter);
617
618 /* update number of available TX blocks */
619 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300620 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
621 wl->tx_blocks_freed[i];
622
623 wl->tx_blocks_freed[i] =
624 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625 wl->tx_blocks_available += cnt;
626 total += cnt;
627 }
628
Ido Yariva5225502010-10-12 14:49:10 +0200629 /* if more blocks are available now, tx work can be scheduled */
630 if (total)
631 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632
Arik Nemtsovb622d992011-02-23 00:22:31 +0200633 /* for AP update num of allocated TX blocks per link and ps status */
634 if (wl->bss_type == BSS_TYPE_AP_BSS)
635 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200636
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200638 getnstimeofday(&ts);
639 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
640 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641}
642
Ido Yariva6208652011-03-01 15:14:41 +0200643static void wl1271_flush_deferred_work(struct wl1271 *wl)
644{
645 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200646
Ido Yariva6208652011-03-01 15:14:41 +0200647 /* Pass all received frames to the network stack */
648 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
649 ieee80211_rx_ni(wl->hw, skb);
650
651 /* Return sent skbs to the network stack */
652 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
653 ieee80211_tx_status(wl->hw, skb);
654}
655
656static void wl1271_netstack_work(struct work_struct *work)
657{
658 struct wl1271 *wl =
659 container_of(work, struct wl1271, netstack_work);
660
661 do {
662 wl1271_flush_deferred_work(wl);
663 } while (skb_queue_len(&wl->deferred_rx_queue));
664}
665
666#define WL1271_IRQ_MAX_LOOPS 256
667
668irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300671 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200672 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200673 struct wl1271 *wl = (struct wl1271 *)cookie;
674 bool done = false;
675 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200676 unsigned long flags;
677
678 /* TX might be handled here, avoid redundant work */
679 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
680 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681
682 mutex_lock(&wl->mutex);
683
684 wl1271_debug(DEBUG_IRQ, "IRQ work");
685
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200686 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 goto out;
688
Ido Yariva6208652011-03-01 15:14:41 +0200689 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 if (ret < 0)
691 goto out;
692
Ido Yariva6208652011-03-01 15:14:41 +0200693 while (!done && loopcount--) {
694 /*
695 * In order to avoid a race with the hardirq, clear the flag
696 * before acknowledging the chip. Since the mutex is held,
697 * wl1271_ps_elp_wakeup cannot be called concurrently.
698 */
699 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
700 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200701
702 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200703 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200704 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200705 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200706 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200707 continue;
708 }
709
Eliad Pellerccc83b02010-10-27 14:09:57 +0200710 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
711 wl1271_error("watchdog interrupt received! "
712 "starting recovery.");
713 ieee80211_queue_work(wl->hw, &wl->recovery_work);
714
715 /* restarting the chip. ignore any other interrupt. */
716 goto out;
717 }
718
Ido Yariva6208652011-03-01 15:14:41 +0200719 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200720 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
721
Ido Yariv8aad2462011-03-01 15:14:38 +0200722 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200723
Ido Yariva5225502010-10-12 14:49:10 +0200724 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200725 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200726 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200727 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200728 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200729 /*
730 * In order to avoid starvation of the TX path,
731 * call the work function directly.
732 */
733 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200734 } else {
735 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200736 }
737
Ido Yariv8aad2462011-03-01 15:14:38 +0200738 /* check for tx results */
739 if (wl->fw_status->common.tx_results_counter !=
740 (wl->tx_results_count & 0xff))
741 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200742
743 /* Make sure the deferred queues don't get too long */
744 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
745 skb_queue_len(&wl->deferred_rx_queue);
746 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
747 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200748 }
749
750 if (intr & WL1271_ACX_INTR_EVENT_A) {
751 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
752 wl1271_event_handle(wl, 0);
753 }
754
755 if (intr & WL1271_ACX_INTR_EVENT_B) {
756 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
757 wl1271_event_handle(wl, 1);
758 }
759
760 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
761 wl1271_debug(DEBUG_IRQ,
762 "WL1271_ACX_INTR_INIT_COMPLETE");
763
764 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
765 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766 }
767
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300768 wl1271_ps_elp_sleep(wl);
769
770out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200771 spin_lock_irqsave(&wl->wl_lock, flags);
772 /* In case TX was not handled here, queue TX work */
773 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
774 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
775 wl->tx_queue_count)
776 ieee80211_queue_work(wl->hw, &wl->tx_work);
777 spin_unlock_irqrestore(&wl->wl_lock, flags);
778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200780
781 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782}
Ido Yariva6208652011-03-01 15:14:41 +0200783EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785static int wl1271_fetch_firmware(struct wl1271 *wl)
786{
787 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200788 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789 int ret;
790
Arik Nemtsov166d5042010-10-16 21:44:57 +0200791 switch (wl->bss_type) {
792 case BSS_TYPE_AP_BSS:
793 fw_name = WL1271_AP_FW_NAME;
794 break;
795 case BSS_TYPE_IBSS:
796 case BSS_TYPE_STA_BSS:
797 fw_name = WL1271_FW_NAME;
798 break;
799 default:
800 wl1271_error("no compatible firmware for bss_type %d",
801 wl->bss_type);
802 return -EINVAL;
803 }
804
805 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
806
807 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808
809 if (ret < 0) {
810 wl1271_error("could not get firmware: %d", ret);
811 return ret;
812 }
813
814 if (fw->size % 4) {
815 wl1271_error("firmware size is not multiple of 32 bits: %zu",
816 fw->size);
817 ret = -EILSEQ;
818 goto out;
819 }
820
Arik Nemtsov166d5042010-10-16 21:44:57 +0200821 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300822 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300823 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
825 if (!wl->fw) {
826 wl1271_error("could not allocate memory for the firmware");
827 ret = -ENOMEM;
828 goto out;
829 }
830
831 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200832 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300833 ret = 0;
834
835out:
836 release_firmware(fw);
837
838 return ret;
839}
840
841static int wl1271_fetch_nvs(struct wl1271 *wl)
842{
843 const struct firmware *fw;
844 int ret;
845
Shahar Levi5aa42342011-03-06 16:32:07 +0200846 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847
848 if (ret < 0) {
849 wl1271_error("could not get nvs file: %d", ret);
850 return ret;
851 }
852
Julia Lawall929ebd32010-05-15 23:16:39 +0200853 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854
855 if (!wl->nvs) {
856 wl1271_error("could not allocate memory for the nvs file");
857 ret = -ENOMEM;
858 goto out;
859 }
860
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200861 wl->nvs_len = fw->size;
862
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863out:
864 release_firmware(fw);
865
866 return ret;
867}
868
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200869static void wl1271_recovery_work(struct work_struct *work)
870{
871 struct wl1271 *wl =
872 container_of(work, struct wl1271, recovery_work);
873
874 mutex_lock(&wl->mutex);
875
876 if (wl->state != WL1271_STATE_ON)
877 goto out;
878
879 wl1271_info("Hardware recovery in progress.");
880
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200881 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
882 ieee80211_connection_loss(wl->vif);
883
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200884 /* reboot the chipset */
885 __wl1271_op_remove_interface(wl);
886 ieee80211_restart_hw(wl->hw);
887
888out:
889 mutex_unlock(&wl->mutex);
890}
891
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892static void wl1271_fw_wakeup(struct wl1271 *wl)
893{
894 u32 elp_reg;
895
896 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300897 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898}
899
900static int wl1271_setup(struct wl1271 *wl)
901{
902 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
903 if (!wl->fw_status)
904 return -ENOMEM;
905
906 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
907 if (!wl->tx_res_if) {
908 kfree(wl->fw_status);
909 return -ENOMEM;
910 }
911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912 return 0;
913}
914
915static int wl1271_chip_wakeup(struct wl1271 *wl)
916{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300917 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918 int ret = 0;
919
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +0200920 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200921 ret = wl1271_power_on(wl);
922 if (ret < 0)
923 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200925 wl1271_io_reset(wl);
926 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927
928 /* We don't need a real memory partition here, because we only want
929 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300930 memset(&partition, 0, sizeof(partition));
931 partition.reg.start = REGISTERS_BASE;
932 partition.reg.size = REGISTERS_DOWN_SIZE;
933 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
935 /* ELP module wake up */
936 wl1271_fw_wakeup(wl);
937
938 /* whal_FwCtrl_BootSm() */
939
940 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200941 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942
943 /* 1. check if chip id is valid */
944
945 switch (wl->chip.id) {
946 case CHIP_ID_1271_PG10:
947 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
948 wl->chip.id);
949
950 ret = wl1271_setup(wl);
951 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200952 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 break;
954 case CHIP_ID_1271_PG20:
955 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
956 wl->chip.id);
957
958 ret = wl1271_setup(wl);
959 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200960 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 break;
962 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200965 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 }
967
Arik Nemtsov166d5042010-10-16 21:44:57 +0200968 /* Make sure the firmware type matches the BSS type */
969 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 ret = wl1271_fetch_firmware(wl);
971 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200972 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 }
974
975 /* No NVS from netlink, try to get it from the filesystem */
976 if (wl->nvs == NULL) {
977 ret = wl1271_fetch_nvs(wl);
978 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200979 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 }
981
982out:
983 return ret;
984}
985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986int wl1271_plt_start(struct wl1271 *wl)
987{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 int ret;
990
991 mutex_lock(&wl->mutex);
992
993 wl1271_notice("power up");
994
995 if (wl->state != WL1271_STATE_OFF) {
996 wl1271_error("cannot go into PLT state because not "
997 "in off state: %d", wl->state);
998 ret = -EBUSY;
999 goto out;
1000 }
1001
Arik Nemtsov166d5042010-10-16 21:44:57 +02001002 wl->bss_type = BSS_TYPE_STA_BSS;
1003
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001004 while (retries) {
1005 retries--;
1006 ret = wl1271_chip_wakeup(wl);
1007 if (ret < 0)
1008 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001010 ret = wl1271_boot(wl);
1011 if (ret < 0)
1012 goto power_off;
1013
1014 ret = wl1271_plt_init(wl);
1015 if (ret < 0)
1016 goto irq_disable;
1017
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001018 wl->state = WL1271_STATE_PLT;
1019 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001020 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 goto out;
1022
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001023irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001024 mutex_unlock(&wl->mutex);
1025 /* Unlocking the mutex in the middle of handling is
1026 inherently unsafe. In this case we deem it safe to do,
1027 because we need to let any possibly pending IRQ out of
1028 the system (and while we are WL1271_STATE_OFF the IRQ
1029 work function will not do anything.) Also, any other
1030 possible concurrent operations will fail due to the
1031 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001032 wl1271_disable_interrupts(wl);
1033 wl1271_flush_deferred_work(wl);
1034 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001035 mutex_lock(&wl->mutex);
1036power_off:
1037 wl1271_power_off(wl);
1038 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001040 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1041 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042out:
1043 mutex_unlock(&wl->mutex);
1044
1045 return ret;
1046}
1047
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001048int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049{
1050 int ret = 0;
1051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 wl1271_notice("power down");
1053
1054 if (wl->state != WL1271_STATE_PLT) {
1055 wl1271_error("cannot power down because not in PLT "
1056 "state: %d", wl->state);
1057 ret = -EBUSY;
1058 goto out;
1059 }
1060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 wl1271_power_off(wl);
1062
1063 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001064 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001067 wl1271_disable_interrupts(wl);
1068 wl1271_flush_deferred_work(wl);
1069 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001070 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001071 mutex_lock(&wl->mutex);
1072out:
1073 return ret;
1074}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001075
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001076int wl1271_plt_stop(struct wl1271 *wl)
1077{
1078 int ret;
1079
1080 mutex_lock(&wl->mutex);
1081 ret = __wl1271_plt_stop(wl);
1082 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 return ret;
1084}
1085
Johannes Berg7bb45682011-02-24 14:42:06 +01001086static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087{
1088 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001089 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001090 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001091 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092
Ido Yarivb07d4032011-03-01 15:14:43 +02001093 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1094
1095 if (wl->bss_type == BSS_TYPE_AP_BSS)
1096 hlid = wl1271_tx_get_hlid(skb);
1097
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001098 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001099
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001100 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001101
1102 /*
1103 * The workqueue is slow to process the tx_queue and we need stop
1104 * the queue here, otherwise the queue will get too long.
1105 */
1106 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1107 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1108 ieee80211_stop_queues(wl->hw);
1109 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1110 }
1111
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001112 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001113 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001114 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1115 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1116 } else {
1117 skb_queue_tail(&wl->tx_queue[q], skb);
1118 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119
1120 /*
1121 * The chip specific setup must run before the first TX packet -
1122 * before that, the tx_work will not be initialized!
1123 */
1124
Ido Yarivb07d4032011-03-01 15:14:43 +02001125 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1126 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001127 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001128
1129 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001130}
1131
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001132static struct notifier_block wl1271_dev_notifier = {
1133 .notifier_call = wl1271_dev_notify,
1134};
1135
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136static int wl1271_op_start(struct ieee80211_hw *hw)
1137{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001138 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1139
1140 /*
1141 * We have to delay the booting of the hardware because
1142 * we need to know the local MAC address before downloading and
1143 * initializing the firmware. The MAC address cannot be changed
1144 * after boot, and without the proper MAC address, the firmware
1145 * will not function properly.
1146 *
1147 * The MAC address is first known when the corresponding interface
1148 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001149 *
1150 * In addition, we currently have different firmwares for AP and managed
1151 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001152 */
1153
1154 return 0;
1155}
1156
1157static void wl1271_op_stop(struct ieee80211_hw *hw)
1158{
1159 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1160}
1161
1162static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1163 struct ieee80211_vif *vif)
1164{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001165 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001166 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001167 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001169 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001171 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1172 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173
1174 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001175 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001176 wl1271_debug(DEBUG_MAC80211,
1177 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001178 ret = -EBUSY;
1179 goto out;
1180 }
1181
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001182 switch (vif->type) {
1183 case NL80211_IFTYPE_STATION:
1184 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001185 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001186 break;
1187 case NL80211_IFTYPE_ADHOC:
1188 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001189 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001190 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001191 case NL80211_IFTYPE_AP:
1192 wl->bss_type = BSS_TYPE_AP_BSS;
1193 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001194 default:
1195 ret = -EOPNOTSUPP;
1196 goto out;
1197 }
1198
1199 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200
1201 if (wl->state != WL1271_STATE_OFF) {
1202 wl1271_error("cannot start because not in off state: %d",
1203 wl->state);
1204 ret = -EBUSY;
1205 goto out;
1206 }
1207
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001208 while (retries) {
1209 retries--;
1210 ret = wl1271_chip_wakeup(wl);
1211 if (ret < 0)
1212 goto power_off;
1213
1214 ret = wl1271_boot(wl);
1215 if (ret < 0)
1216 goto power_off;
1217
1218 ret = wl1271_hw_init(wl);
1219 if (ret < 0)
1220 goto irq_disable;
1221
Eliad Peller71125ab2010-10-28 21:46:43 +02001222 booted = true;
1223 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001225irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001226 mutex_unlock(&wl->mutex);
1227 /* Unlocking the mutex in the middle of handling is
1228 inherently unsafe. In this case we deem it safe to do,
1229 because we need to let any possibly pending IRQ out of
1230 the system (and while we are WL1271_STATE_OFF the IRQ
1231 work function will not do anything.) Also, any other
1232 possible concurrent operations will fail due to the
1233 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001234 wl1271_disable_interrupts(wl);
1235 wl1271_flush_deferred_work(wl);
1236 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001237 mutex_lock(&wl->mutex);
1238power_off:
1239 wl1271_power_off(wl);
1240 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241
Eliad Peller71125ab2010-10-28 21:46:43 +02001242 if (!booted) {
1243 wl1271_error("firmware boot failed despite %d retries",
1244 WL1271_BOOT_RETRIES);
1245 goto out;
1246 }
1247
1248 wl->vif = vif;
1249 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001250 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001251
1252 /* update hw/fw version info in wiphy struct */
1253 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001254 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001255 sizeof(wiphy->fw_version));
1256
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001257 /*
1258 * Now we know if 11a is supported (info from the NVS), so disable
1259 * 11a channels if not supported
1260 */
1261 if (!wl->enable_11a)
1262 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1263
1264 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1265 wl->enable_11a ? "" : "not ");
1266
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001267out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268 mutex_unlock(&wl->mutex);
1269
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001270 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001271 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001272
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 return ret;
1274}
1275
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001276static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 int i;
1279
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001280 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001282 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001284 list_del(&wl->list);
1285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 WARN_ON(wl->state != WL1271_STATE_ON);
1287
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001288 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001289 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001290 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001291
Luciano Coelho08688d62010-07-08 17:50:07 +03001292 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001293 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1294 kfree(wl->scan.scanned_ch);
1295 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001296 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001297 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 }
1299
1300 wl->state = WL1271_STATE_OFF;
1301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 mutex_unlock(&wl->mutex);
1303
Ido Yariva6208652011-03-01 15:14:41 +02001304 wl1271_disable_interrupts(wl);
1305 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001306 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001307 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001309 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001310 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311
1312 mutex_lock(&wl->mutex);
1313
1314 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001315 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 wl1271_power_off(wl);
1317
1318 memset(wl->bssid, 0, ETH_ALEN);
1319 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1320 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001322 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001323 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324
1325 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001326 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1328 wl->tx_blocks_available = 0;
1329 wl->tx_results_count = 0;
1330 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001331 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001332 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 wl->time_offset = 0;
1334 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001335 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001336 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001337 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001338 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001339 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001340 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001341 wl->ap_fw_ps_map = 0;
1342 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001343 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001344
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345 for (i = 0; i < NUM_TX_QUEUES; i++)
1346 wl->tx_blocks_freed[i] = 0;
1347
1348 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001349
1350 kfree(wl->fw_status);
1351 wl->fw_status = NULL;
1352 kfree(wl->tx_res_if);
1353 wl->tx_res_if = NULL;
1354 kfree(wl->target_mem_map);
1355 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001356}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001357
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001358static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1359 struct ieee80211_vif *vif)
1360{
1361 struct wl1271 *wl = hw->priv;
1362
1363 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001364 /*
1365 * wl->vif can be null here if someone shuts down the interface
1366 * just when hardware recovery has been started.
1367 */
1368 if (wl->vif) {
1369 WARN_ON(wl->vif != vif);
1370 __wl1271_op_remove_interface(wl);
1371 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001372
Juuso Oikarinen67353292010-11-18 15:19:02 +02001373 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001374 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375}
1376
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001377static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1378{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001379 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001380
1381 /* combine requested filters with current filter config */
1382 filters = wl->filters | filters;
1383
1384 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1385
1386 if (filters & FIF_PROMISC_IN_BSS) {
1387 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1388 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1389 wl->rx_config |= CFG_BSSID_FILTER_EN;
1390 }
1391 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1392 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1393 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1394 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1395 }
1396 if (filters & FIF_OTHER_BSS) {
1397 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1398 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1399 }
1400 if (filters & FIF_CONTROL) {
1401 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1402 wl->rx_filter |= CFG_RX_CTL_EN;
1403 }
1404 if (filters & FIF_FCSFAIL) {
1405 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1406 wl->rx_filter |= CFG_RX_FCS_ERROR;
1407 }
1408}
1409
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001410static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001411{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001412 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001413 /* we need to use a dummy BSSID for now */
1414 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1415 0xad, 0xbe, 0xef };
1416
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001417 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1418
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001419 /* pass through frames from all BSS */
1420 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1421
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001422 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001423 if (ret < 0)
1424 goto out;
1425
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001426 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001427
1428out:
1429 return ret;
1430}
1431
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001432static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001433{
1434 int ret;
1435
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001436 /*
1437 * One of the side effects of the JOIN command is that is clears
1438 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1439 * to a WPA/WPA2 access point will therefore kill the data-path.
1440 * Currently there is no supported scenario for JOIN during
1441 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1442 * must be handled somehow.
1443 *
1444 */
1445 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1446 wl1271_info("JOIN while associated.");
1447
1448 if (set_assoc)
1449 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1450
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001451 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1452 if (ret < 0)
1453 goto out;
1454
1455 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1456
1457 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1458 goto out;
1459
1460 /*
1461 * The join command disable the keep-alive mode, shut down its process,
1462 * and also clear the template config, so we need to reset it all after
1463 * the join. The acx_aid starts the keep-alive process, and the order
1464 * of the commands below is relevant.
1465 */
1466 ret = wl1271_acx_keep_alive_mode(wl, true);
1467 if (ret < 0)
1468 goto out;
1469
1470 ret = wl1271_acx_aid(wl, wl->aid);
1471 if (ret < 0)
1472 goto out;
1473
1474 ret = wl1271_cmd_build_klv_null_data(wl);
1475 if (ret < 0)
1476 goto out;
1477
1478 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1479 ACX_KEEP_ALIVE_TPL_VALID);
1480 if (ret < 0)
1481 goto out;
1482
1483out:
1484 return ret;
1485}
1486
1487static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001488{
1489 int ret;
1490
1491 /* to stop listening to a channel, we disconnect */
1492 ret = wl1271_cmd_disconnect(wl);
1493 if (ret < 0)
1494 goto out;
1495
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001496 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001497 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001498
1499 /* stop filterting packets based on bssid */
1500 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001501
1502out:
1503 return ret;
1504}
1505
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001506static void wl1271_set_band_rate(struct wl1271 *wl)
1507{
1508 if (wl->band == IEEE80211_BAND_2GHZ)
1509 wl->basic_rate_set = wl->conf.tx.basic_rate;
1510 else
1511 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1512}
1513
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001514static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001515{
1516 int ret;
1517
1518 if (idle) {
1519 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1520 ret = wl1271_unjoin(wl);
1521 if (ret < 0)
1522 goto out;
1523 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001524 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001525 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001526 if (ret < 0)
1527 goto out;
1528 ret = wl1271_acx_keep_alive_config(
1529 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1530 ACX_KEEP_ALIVE_TPL_INVALID);
1531 if (ret < 0)
1532 goto out;
1533 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1534 } else {
1535 /* increment the session counter */
1536 wl->session_counter++;
1537 if (wl->session_counter >= SESSION_COUNTER_MAX)
1538 wl->session_counter = 0;
1539 ret = wl1271_dummy_join(wl);
1540 if (ret < 0)
1541 goto out;
1542 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1543 }
1544
1545out:
1546 return ret;
1547}
1548
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001549static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1550{
1551 struct wl1271 *wl = hw->priv;
1552 struct ieee80211_conf *conf = &hw->conf;
1553 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001554 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001555
1556 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1557
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001558 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1559 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560 channel,
1561 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001562 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001563 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1564 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001566 /*
1567 * mac80211 will go to idle nearly immediately after transmitting some
1568 * frames, such as the deauth. To make sure those frames reach the air,
1569 * wait here until the TX queue is fully flushed.
1570 */
1571 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1572 (conf->flags & IEEE80211_CONF_IDLE))
1573 wl1271_tx_flush(wl);
1574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 mutex_lock(&wl->mutex);
1576
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001577 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1578 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001579 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001580 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001581
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001582 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1583
Ido Yariva6208652011-03-01 15:14:41 +02001584 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 if (ret < 0)
1586 goto out;
1587
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001588 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001589 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1590 ((wl->band != conf->channel->band) ||
1591 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001592 wl->band = conf->channel->band;
1593 wl->channel = channel;
1594
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001595 if (!is_ap) {
1596 /*
1597 * FIXME: the mac80211 should really provide a fixed
1598 * rate to use here. for now, just use the smallest
1599 * possible rate for the band as a fixed rate for
1600 * association frames and other control messages.
1601 */
1602 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1603 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001604
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001605 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1606 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001607 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001608 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001609 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001610
1611 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1612 ret = wl1271_join(wl, false);
1613 if (ret < 0)
1614 wl1271_warning("cmd join on channel "
1615 "failed %d", ret);
1616 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001617 }
1618 }
1619
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001620 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1621 ret = wl1271_sta_handle_idle(wl,
1622 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001623 if (ret < 0)
1624 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001625 }
1626
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001627 /*
1628 * if mac80211 changes the PSM mode, make sure the mode is not
1629 * incorrectly changed after the pspoll failure active window.
1630 */
1631 if (changed & IEEE80211_CONF_CHANGE_PS)
1632 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1633
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001634 if (conf->flags & IEEE80211_CONF_PS &&
1635 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1636 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001637
1638 /*
1639 * We enter PSM only if we're already associated.
1640 * If we're not, we'll enter it when joining an SSID,
1641 * through the bss_info_changed() hook.
1642 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001643 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001644 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001645 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001646 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001647 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001649 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001650 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001651
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001652 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001654 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001655 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001656 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657 }
1658
1659 if (conf->power_level != wl->power_level) {
1660 ret = wl1271_acx_tx_power(wl, conf->power_level);
1661 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001662 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663
1664 wl->power_level = conf->power_level;
1665 }
1666
1667out_sleep:
1668 wl1271_ps_elp_sleep(wl);
1669
1670out:
1671 mutex_unlock(&wl->mutex);
1672
1673 return ret;
1674}
1675
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001676struct wl1271_filter_params {
1677 bool enabled;
1678 int mc_list_length;
1679 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1680};
1681
Jiri Pirko22bedad2010-04-01 21:22:57 +00001682static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1683 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001684{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001685 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001686 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001687 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001688
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001689 if (unlikely(wl->state == WL1271_STATE_OFF))
1690 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001691
Juuso Oikarinen74441132009-10-13 12:47:53 +03001692 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001693 if (!fp) {
1694 wl1271_error("Out of memory setting filters.");
1695 return 0;
1696 }
1697
1698 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001699 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001700 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1701 fp->enabled = false;
1702 } else {
1703 fp->enabled = true;
1704 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001705 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001706 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001707 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001708 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001709 }
1710
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001711 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001712}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001713
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001714#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1715 FIF_ALLMULTI | \
1716 FIF_FCSFAIL | \
1717 FIF_BCN_PRBRESP_PROMISC | \
1718 FIF_CONTROL | \
1719 FIF_OTHER_BSS)
1720
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001721static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1722 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001723 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001725 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001727 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728
Arik Nemtsov7d057862010-10-16 19:25:35 +02001729 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1730 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001732 mutex_lock(&wl->mutex);
1733
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001734 *total &= WL1271_SUPPORTED_FILTERS;
1735 changed &= WL1271_SUPPORTED_FILTERS;
1736
1737 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001738 goto out;
1739
Ido Yariva6208652011-03-01 15:14:41 +02001740 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001741 if (ret < 0)
1742 goto out;
1743
Arik Nemtsov7d057862010-10-16 19:25:35 +02001744 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1745 if (*total & FIF_ALLMULTI)
1746 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1747 else if (fp)
1748 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1749 fp->mc_list,
1750 fp->mc_list_length);
1751 if (ret < 0)
1752 goto out_sleep;
1753 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001754
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001755 /* determine, whether supported filter values have changed */
1756 if (changed == 0)
1757 goto out_sleep;
1758
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001759 /* configure filters */
1760 wl->filters = *total;
1761 wl1271_configure_filters(wl, 0);
1762
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001763 /* apply configured filters */
1764 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1765 if (ret < 0)
1766 goto out_sleep;
1767
1768out_sleep:
1769 wl1271_ps_elp_sleep(wl);
1770
1771out:
1772 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001773 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774}
1775
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001776static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1777 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1778 u16 tx_seq_16)
1779{
1780 struct wl1271_ap_key *ap_key;
1781 int i;
1782
1783 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1784
1785 if (key_size > MAX_KEY_SIZE)
1786 return -EINVAL;
1787
1788 /*
1789 * Find next free entry in ap_keys. Also check we are not replacing
1790 * an existing key.
1791 */
1792 for (i = 0; i < MAX_NUM_KEYS; i++) {
1793 if (wl->recorded_ap_keys[i] == NULL)
1794 break;
1795
1796 if (wl->recorded_ap_keys[i]->id == id) {
1797 wl1271_warning("trying to record key replacement");
1798 return -EINVAL;
1799 }
1800 }
1801
1802 if (i == MAX_NUM_KEYS)
1803 return -EBUSY;
1804
1805 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1806 if (!ap_key)
1807 return -ENOMEM;
1808
1809 ap_key->id = id;
1810 ap_key->key_type = key_type;
1811 ap_key->key_size = key_size;
1812 memcpy(ap_key->key, key, key_size);
1813 ap_key->hlid = hlid;
1814 ap_key->tx_seq_32 = tx_seq_32;
1815 ap_key->tx_seq_16 = tx_seq_16;
1816
1817 wl->recorded_ap_keys[i] = ap_key;
1818 return 0;
1819}
1820
1821static void wl1271_free_ap_keys(struct wl1271 *wl)
1822{
1823 int i;
1824
1825 for (i = 0; i < MAX_NUM_KEYS; i++) {
1826 kfree(wl->recorded_ap_keys[i]);
1827 wl->recorded_ap_keys[i] = NULL;
1828 }
1829}
1830
1831static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1832{
1833 int i, ret = 0;
1834 struct wl1271_ap_key *key;
1835 bool wep_key_added = false;
1836
1837 for (i = 0; i < MAX_NUM_KEYS; i++) {
1838 if (wl->recorded_ap_keys[i] == NULL)
1839 break;
1840
1841 key = wl->recorded_ap_keys[i];
1842 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1843 key->id, key->key_type,
1844 key->key_size, key->key,
1845 key->hlid, key->tx_seq_32,
1846 key->tx_seq_16);
1847 if (ret < 0)
1848 goto out;
1849
1850 if (key->key_type == KEY_WEP)
1851 wep_key_added = true;
1852 }
1853
1854 if (wep_key_added) {
1855 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1856 if (ret < 0)
1857 goto out;
1858 }
1859
1860out:
1861 wl1271_free_ap_keys(wl);
1862 return ret;
1863}
1864
1865static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1866 u8 key_size, const u8 *key, u32 tx_seq_32,
1867 u16 tx_seq_16, struct ieee80211_sta *sta)
1868{
1869 int ret;
1870 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1871
1872 if (is_ap) {
1873 struct wl1271_station *wl_sta;
1874 u8 hlid;
1875
1876 if (sta) {
1877 wl_sta = (struct wl1271_station *)sta->drv_priv;
1878 hlid = wl_sta->hlid;
1879 } else {
1880 hlid = WL1271_AP_BROADCAST_HLID;
1881 }
1882
1883 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1884 /*
1885 * We do not support removing keys after AP shutdown.
1886 * Pretend we do to make mac80211 happy.
1887 */
1888 if (action != KEY_ADD_OR_REPLACE)
1889 return 0;
1890
1891 ret = wl1271_record_ap_key(wl, id,
1892 key_type, key_size,
1893 key, hlid, tx_seq_32,
1894 tx_seq_16);
1895 } else {
1896 ret = wl1271_cmd_set_ap_key(wl, action,
1897 id, key_type, key_size,
1898 key, hlid, tx_seq_32,
1899 tx_seq_16);
1900 }
1901
1902 if (ret < 0)
1903 return ret;
1904 } else {
1905 const u8 *addr;
1906 static const u8 bcast_addr[ETH_ALEN] = {
1907 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1908 };
1909
1910 addr = sta ? sta->addr : bcast_addr;
1911
1912 if (is_zero_ether_addr(addr)) {
1913 /* We dont support TX only encryption */
1914 return -EOPNOTSUPP;
1915 }
1916
1917 /* The wl1271 does not allow to remove unicast keys - they
1918 will be cleared automatically on next CMD_JOIN. Ignore the
1919 request silently, as we dont want the mac80211 to emit
1920 an error message. */
1921 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1922 return 0;
1923
1924 ret = wl1271_cmd_set_sta_key(wl, action,
1925 id, key_type, key_size,
1926 key, addr, tx_seq_32,
1927 tx_seq_16);
1928 if (ret < 0)
1929 return ret;
1930
1931 /* the default WEP key needs to be configured at least once */
1932 if (key_type == KEY_WEP) {
1933 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1934 wl->default_key);
1935 if (ret < 0)
1936 return ret;
1937 }
1938 }
1939
1940 return 0;
1941}
1942
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1944 struct ieee80211_vif *vif,
1945 struct ieee80211_sta *sta,
1946 struct ieee80211_key_conf *key_conf)
1947{
1948 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001950 u32 tx_seq_32 = 0;
1951 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 u8 key_type;
1953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1955
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001956 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001958 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 key_conf->keylen, key_conf->flags);
1960 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 mutex_lock(&wl->mutex);
1963
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001964 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1965 ret = -EAGAIN;
1966 goto out_unlock;
1967 }
1968
Ido Yariva6208652011-03-01 15:14:41 +02001969 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 if (ret < 0)
1971 goto out_unlock;
1972
Johannes Berg97359d12010-08-10 09:46:38 +02001973 switch (key_conf->cipher) {
1974 case WLAN_CIPHER_SUITE_WEP40:
1975 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976 key_type = KEY_WEP;
1977
1978 key_conf->hw_key_idx = key_conf->keyidx;
1979 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001980 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981 key_type = KEY_TKIP;
1982
1983 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001984 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1985 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001987 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988 key_type = KEY_AES;
1989
1990 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001991 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1992 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001993 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001994 case WL1271_CIPHER_SUITE_GEM:
1995 key_type = KEY_GEM;
1996 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1997 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1998 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002000 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001
2002 ret = -EOPNOTSUPP;
2003 goto out_sleep;
2004 }
2005
2006 switch (cmd) {
2007 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002008 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2009 key_conf->keyidx, key_type,
2010 key_conf->keylen, key_conf->key,
2011 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 if (ret < 0) {
2013 wl1271_error("Could not add or replace key");
2014 goto out_sleep;
2015 }
2016 break;
2017
2018 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002019 ret = wl1271_set_key(wl, KEY_REMOVE,
2020 key_conf->keyidx, key_type,
2021 key_conf->keylen, key_conf->key,
2022 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002023 if (ret < 0) {
2024 wl1271_error("Could not remove key");
2025 goto out_sleep;
2026 }
2027 break;
2028
2029 default:
2030 wl1271_error("Unsupported key cmd 0x%x", cmd);
2031 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 break;
2033 }
2034
2035out_sleep:
2036 wl1271_ps_elp_sleep(wl);
2037
2038out_unlock:
2039 mutex_unlock(&wl->mutex);
2040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 return ret;
2042}
2043
2044static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002045 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 struct cfg80211_scan_request *req)
2047{
2048 struct wl1271 *wl = hw->priv;
2049 int ret;
2050 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002051 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052
2053 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2054
2055 if (req->n_ssids) {
2056 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002057 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 }
2059
2060 mutex_lock(&wl->mutex);
2061
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002062 if (wl->state == WL1271_STATE_OFF) {
2063 /*
2064 * We cannot return -EBUSY here because cfg80211 will expect
2065 * a call to ieee80211_scan_completed if we do - in this case
2066 * there won't be any call.
2067 */
2068 ret = -EAGAIN;
2069 goto out;
2070 }
2071
Ido Yariva6208652011-03-01 15:14:41 +02002072 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073 if (ret < 0)
2074 goto out;
2075
Luciano Coelho5924f892010-08-04 03:46:22 +03002076 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077
2078 wl1271_ps_elp_sleep(wl);
2079
2080out:
2081 mutex_unlock(&wl->mutex);
2082
2083 return ret;
2084}
2085
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002086static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2087{
2088 struct wl1271 *wl = hw->priv;
2089 int ret = 0;
2090
2091 mutex_lock(&wl->mutex);
2092
2093 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2094 ret = -EAGAIN;
2095 goto out;
2096 }
2097
Ido Yariva6208652011-03-01 15:14:41 +02002098 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002099 if (ret < 0)
2100 goto out;
2101
2102 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2103 if (ret < 0)
2104 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2105
2106 wl1271_ps_elp_sleep(wl);
2107
2108out:
2109 mutex_unlock(&wl->mutex);
2110
2111 return ret;
2112}
2113
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2115{
2116 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002117 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002118
2119 mutex_lock(&wl->mutex);
2120
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002121 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2122 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002123 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002124 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002125
Ido Yariva6208652011-03-01 15:14:41 +02002126 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127 if (ret < 0)
2128 goto out;
2129
2130 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2131 if (ret < 0)
2132 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2133
2134 wl1271_ps_elp_sleep(wl);
2135
2136out:
2137 mutex_unlock(&wl->mutex);
2138
2139 return ret;
2140}
2141
Arik Nemtsove78a2872010-10-16 19:07:21 +02002142static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002143 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002144{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002145 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002146
2147 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002148 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002149 if (ptr[0] == WLAN_EID_SSID) {
2150 wl->ssid_len = ptr[1];
2151 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002152 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002153 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002154 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002155 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002156
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002157 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002158 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002159}
2160
Arik Nemtsove78a2872010-10-16 19:07:21 +02002161static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2162 struct ieee80211_bss_conf *bss_conf,
2163 u32 changed)
2164{
2165 int ret = 0;
2166
2167 if (changed & BSS_CHANGED_ERP_SLOT) {
2168 if (bss_conf->use_short_slot)
2169 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2170 else
2171 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2172 if (ret < 0) {
2173 wl1271_warning("Set slot time failed %d", ret);
2174 goto out;
2175 }
2176 }
2177
2178 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2179 if (bss_conf->use_short_preamble)
2180 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2181 else
2182 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2183 }
2184
2185 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2186 if (bss_conf->use_cts_prot)
2187 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2188 else
2189 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2190 if (ret < 0) {
2191 wl1271_warning("Set ctsprotect failed %d", ret);
2192 goto out;
2193 }
2194 }
2195
2196out:
2197 return ret;
2198}
2199
2200static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2201 struct ieee80211_vif *vif,
2202 struct ieee80211_bss_conf *bss_conf,
2203 u32 changed)
2204{
2205 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2206 int ret = 0;
2207
2208 if ((changed & BSS_CHANGED_BEACON_INT)) {
2209 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2210 bss_conf->beacon_int);
2211
2212 wl->beacon_int = bss_conf->beacon_int;
2213 }
2214
2215 if ((changed & BSS_CHANGED_BEACON)) {
2216 struct ieee80211_hdr *hdr;
2217 int ieoffset = offsetof(struct ieee80211_mgmt,
2218 u.beacon.variable);
2219 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2220 u16 tmpl_id;
2221
2222 if (!beacon)
2223 goto out;
2224
2225 wl1271_debug(DEBUG_MASTER, "beacon updated");
2226
2227 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2228 if (ret < 0) {
2229 dev_kfree_skb(beacon);
2230 goto out;
2231 }
2232 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2233 CMD_TEMPL_BEACON;
2234 ret = wl1271_cmd_template_set(wl, tmpl_id,
2235 beacon->data,
2236 beacon->len, 0,
2237 wl1271_tx_min_rate_get(wl));
2238 if (ret < 0) {
2239 dev_kfree_skb(beacon);
2240 goto out;
2241 }
2242
2243 hdr = (struct ieee80211_hdr *) beacon->data;
2244 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2245 IEEE80211_STYPE_PROBE_RESP);
2246
2247 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2248 CMD_TEMPL_PROBE_RESPONSE;
2249 ret = wl1271_cmd_template_set(wl,
2250 tmpl_id,
2251 beacon->data,
2252 beacon->len, 0,
2253 wl1271_tx_min_rate_get(wl));
2254 dev_kfree_skb(beacon);
2255 if (ret < 0)
2256 goto out;
2257 }
2258
2259out:
2260 return ret;
2261}
2262
2263/* AP mode changes */
2264static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002265 struct ieee80211_vif *vif,
2266 struct ieee80211_bss_conf *bss_conf,
2267 u32 changed)
2268{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002269 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270
Arik Nemtsove78a2872010-10-16 19:07:21 +02002271 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2272 u32 rates = bss_conf->basic_rates;
2273 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002274
Arik Nemtsove78a2872010-10-16 19:07:21 +02002275 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2276 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2277 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2278 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279
Arik Nemtsove78a2872010-10-16 19:07:21 +02002280 /* update the AP management rate policy with the new rates */
2281 mgmt_rc.enabled_rates = wl->basic_rate_set;
2282 mgmt_rc.long_retry_limit = 10;
2283 mgmt_rc.short_retry_limit = 10;
2284 mgmt_rc.aflags = 0;
2285 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2286 ACX_TX_AP_MODE_MGMT_RATE);
2287 if (ret < 0) {
2288 wl1271_error("AP mgmt policy change failed %d", ret);
2289 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002290 }
2291 }
2292
Arik Nemtsove78a2872010-10-16 19:07:21 +02002293 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2294 if (ret < 0)
2295 goto out;
2296
2297 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2298 if (bss_conf->enable_beacon) {
2299 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2300 ret = wl1271_cmd_start_bss(wl);
2301 if (ret < 0)
2302 goto out;
2303
2304 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2305 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002306
2307 ret = wl1271_ap_init_hwenc(wl);
2308 if (ret < 0)
2309 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002310 }
2311 } else {
2312 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2313 ret = wl1271_cmd_stop_bss(wl);
2314 if (ret < 0)
2315 goto out;
2316
2317 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2318 wl1271_debug(DEBUG_AP, "stopped AP");
2319 }
2320 }
2321 }
2322
2323 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2324 if (ret < 0)
2325 goto out;
2326out:
2327 return;
2328}
2329
2330/* STA/IBSS mode changes */
2331static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2332 struct ieee80211_vif *vif,
2333 struct ieee80211_bss_conf *bss_conf,
2334 u32 changed)
2335{
2336 bool do_join = false, set_assoc = false;
2337 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002338 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002339 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002340 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002341 bool sta_exists = false;
2342 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002343
2344 if (is_ibss) {
2345 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2346 changed);
2347 if (ret < 0)
2348 goto out;
2349 }
2350
2351 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2352 do_join = true;
2353
2354 /* Need to update the SSID (for filtering etc) */
2355 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2356 do_join = true;
2357
2358 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002359 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2360 bss_conf->enable_beacon ? "enabled" : "disabled");
2361
2362 if (bss_conf->enable_beacon)
2363 wl->set_bss_type = BSS_TYPE_IBSS;
2364 else
2365 wl->set_bss_type = BSS_TYPE_STA_BSS;
2366 do_join = true;
2367 }
2368
Arik Nemtsove78a2872010-10-16 19:07:21 +02002369 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002370 bool enable = false;
2371 if (bss_conf->cqm_rssi_thold)
2372 enable = true;
2373 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2374 bss_conf->cqm_rssi_thold,
2375 bss_conf->cqm_rssi_hyst);
2376 if (ret < 0)
2377 goto out;
2378 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2379 }
2380
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002381 if ((changed & BSS_CHANGED_BSSID) &&
2382 /*
2383 * Now we know the correct bssid, so we send a new join command
2384 * and enable the BSSID filter
2385 */
2386 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002387 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002388
Eliad Pellerfa287b82010-12-26 09:27:50 +01002389 if (!is_zero_ether_addr(wl->bssid)) {
2390 ret = wl1271_cmd_build_null_data(wl);
2391 if (ret < 0)
2392 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002393
Eliad Pellerfa287b82010-12-26 09:27:50 +01002394 ret = wl1271_build_qos_null_data(wl);
2395 if (ret < 0)
2396 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002397
Eliad Pellerfa287b82010-12-26 09:27:50 +01002398 /* filter out all packets not from this BSSID */
2399 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002400
Eliad Pellerfa287b82010-12-26 09:27:50 +01002401 /* Need to update the BSSID (for filtering etc) */
2402 do_join = true;
2403 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002404 }
2405
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002406 rcu_read_lock();
2407 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2408 if (sta) {
2409 /* save the supp_rates of the ap */
2410 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2411 if (sta->ht_cap.ht_supported)
2412 sta_rate_set |=
2413 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002414 sta_ht_cap = sta->ht_cap;
2415 sta_exists = true;
2416 }
2417 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002418
Arik Nemtsova1008852011-02-12 23:24:20 +02002419 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002420 /* handle new association with HT and HT information change */
2421 if ((changed & BSS_CHANGED_HT) &&
2422 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002423 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002424 true);
2425 if (ret < 0) {
2426 wl1271_warning("Set ht cap true failed %d",
2427 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002428 goto out;
2429 }
2430 ret = wl1271_acx_set_ht_information(wl,
2431 bss_conf->ht_operation_mode);
2432 if (ret < 0) {
2433 wl1271_warning("Set ht information failed %d",
2434 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002435 goto out;
2436 }
2437 }
2438 /* handle new association without HT and disassociation */
2439 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002440 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002441 false);
2442 if (ret < 0) {
2443 wl1271_warning("Set ht cap false failed %d",
2444 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002445 goto out;
2446 }
2447 }
2448 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002449
Arik Nemtsove78a2872010-10-16 19:07:21 +02002450 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002451 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002452 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002453 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002455 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002457 wl->ps_poll_failures = 0;
2458
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002459 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002460 * use basic rates from AP, and determine lowest rate
2461 * to use with control frames.
2462 */
2463 rates = bss_conf->basic_rates;
2464 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2465 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002466 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002467 if (sta_rate_set)
2468 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2469 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002470 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002472 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473
2474 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002475 * with wl1271, we don't need to update the
2476 * beacon_int and dtim_period, because the firmware
2477 * updates it by itself when the first beacon is
2478 * received after a join.
2479 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2481 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002482 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002484 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002485 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002486 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002487 dev_kfree_skb(wl->probereq);
2488 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2489 ieoffset = offsetof(struct ieee80211_mgmt,
2490 u.probe_req.variable);
2491 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002492
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002493 /* enable the connection monitoring feature */
2494 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002496 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002497
2498 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002499 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2500 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002501 enum wl1271_cmd_ps_mode mode;
2502
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002503 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002504 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002505 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002506 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002508 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002509 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002510 } else {
2511 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002512 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002513 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002514 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002515
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002516 /* free probe-request template */
2517 dev_kfree_skb(wl->probereq);
2518 wl->probereq = NULL;
2519
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002520 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002521 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002522
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002523 /* revert back to minimum rates for the current band */
2524 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002525 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002526 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002527 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002528 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002529
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002530 /* disable connection monitor features */
2531 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002532
2533 /* Disable the keep-alive feature */
2534 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002535 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002536 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002537
2538 /* restore the bssid filter and go to dummy bssid */
2539 wl1271_unjoin(wl);
2540 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 }
2542 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002543
Arik Nemtsove78a2872010-10-16 19:07:21 +02002544 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2545 if (ret < 0)
2546 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002547
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002548 if (changed & BSS_CHANGED_ARP_FILTER) {
2549 __be32 addr = bss_conf->arp_addr_list[0];
2550 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2551
Eliad Pellerc5312772010-12-09 11:31:27 +02002552 if (bss_conf->arp_addr_cnt == 1 &&
2553 bss_conf->arp_filter_enabled) {
2554 /*
2555 * The template should have been configured only upon
2556 * association. however, it seems that the correct ip
2557 * isn't being set (when sending), so we have to
2558 * reconfigure the template upon every ip change.
2559 */
2560 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2561 if (ret < 0) {
2562 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002563 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002564 }
2565
2566 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002567 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002568 addr);
2569 } else
2570 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002571
2572 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002573 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002574 }
2575
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002576 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002577 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002578 if (ret < 0) {
2579 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002580 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002581 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002582 }
2583
Arik Nemtsove78a2872010-10-16 19:07:21 +02002584out:
2585 return;
2586}
2587
2588static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2589 struct ieee80211_vif *vif,
2590 struct ieee80211_bss_conf *bss_conf,
2591 u32 changed)
2592{
2593 struct wl1271 *wl = hw->priv;
2594 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2595 int ret;
2596
2597 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2598 (int)changed);
2599
2600 mutex_lock(&wl->mutex);
2601
2602 if (unlikely(wl->state == WL1271_STATE_OFF))
2603 goto out;
2604
Ido Yariva6208652011-03-01 15:14:41 +02002605 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002606 if (ret < 0)
2607 goto out;
2608
2609 if (is_ap)
2610 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2611 else
2612 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2613
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002614 wl1271_ps_elp_sleep(wl);
2615
2616out:
2617 mutex_unlock(&wl->mutex);
2618}
2619
Kalle Valoc6999d82010-02-18 13:25:41 +02002620static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2621 const struct ieee80211_tx_queue_params *params)
2622{
2623 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002624 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002625 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002626
2627 mutex_lock(&wl->mutex);
2628
2629 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2630
Kalle Valo4695dc92010-03-18 12:26:38 +02002631 if (params->uapsd)
2632 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2633 else
2634 ps_scheme = CONF_PS_SCHEME_LEGACY;
2635
Arik Nemtsov488fc542010-10-16 20:33:45 +02002636 if (wl->state == WL1271_STATE_OFF) {
2637 /*
2638 * If the state is off, the parameters will be recorded and
2639 * configured on init. This happens in AP-mode.
2640 */
2641 struct conf_tx_ac_category *conf_ac =
2642 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2643 struct conf_tx_tid *conf_tid =
2644 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2645
2646 conf_ac->ac = wl1271_tx_get_queue(queue);
2647 conf_ac->cw_min = (u8)params->cw_min;
2648 conf_ac->cw_max = params->cw_max;
2649 conf_ac->aifsn = params->aifs;
2650 conf_ac->tx_op_limit = params->txop << 5;
2651
2652 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2653 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2654 conf_tid->tsid = wl1271_tx_get_queue(queue);
2655 conf_tid->ps_scheme = ps_scheme;
2656 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2657 conf_tid->apsd_conf[0] = 0;
2658 conf_tid->apsd_conf[1] = 0;
2659 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002660 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002661 if (ret < 0)
2662 goto out;
2663
2664 /*
2665 * the txop is confed in units of 32us by the mac80211,
2666 * we need us
2667 */
2668 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2669 params->cw_min, params->cw_max,
2670 params->aifs, params->txop << 5);
2671 if (ret < 0)
2672 goto out_sleep;
2673
2674 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2675 CONF_CHANNEL_TYPE_EDCF,
2676 wl1271_tx_get_queue(queue),
2677 ps_scheme, CONF_ACK_POLICY_LEGACY,
2678 0, 0);
2679 if (ret < 0)
2680 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002681
2682out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002683 wl1271_ps_elp_sleep(wl);
2684 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002685
2686out:
2687 mutex_unlock(&wl->mutex);
2688
2689 return ret;
2690}
2691
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002692static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2693{
2694
2695 struct wl1271 *wl = hw->priv;
2696 u64 mactime = ULLONG_MAX;
2697 int ret;
2698
2699 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2700
2701 mutex_lock(&wl->mutex);
2702
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002703 if (unlikely(wl->state == WL1271_STATE_OFF))
2704 goto out;
2705
Ido Yariva6208652011-03-01 15:14:41 +02002706 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002707 if (ret < 0)
2708 goto out;
2709
2710 ret = wl1271_acx_tsf_info(wl, &mactime);
2711 if (ret < 0)
2712 goto out_sleep;
2713
2714out_sleep:
2715 wl1271_ps_elp_sleep(wl);
2716
2717out:
2718 mutex_unlock(&wl->mutex);
2719 return mactime;
2720}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721
John W. Linvilleece550d2010-07-28 16:41:06 -04002722static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2723 struct survey_info *survey)
2724{
2725 struct wl1271 *wl = hw->priv;
2726 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002727
John W. Linvilleece550d2010-07-28 16:41:06 -04002728 if (idx != 0)
2729 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002730
John W. Linvilleece550d2010-07-28 16:41:06 -04002731 survey->channel = conf->channel;
2732 survey->filled = SURVEY_INFO_NOISE_DBM;
2733 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002734
John W. Linvilleece550d2010-07-28 16:41:06 -04002735 return 0;
2736}
2737
Arik Nemtsov409622e2011-02-23 00:22:29 +02002738static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002739 struct ieee80211_sta *sta,
2740 u8 *hlid)
2741{
2742 struct wl1271_station *wl_sta;
2743 int id;
2744
2745 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2746 if (id >= AP_MAX_STATIONS) {
2747 wl1271_warning("could not allocate HLID - too much stations");
2748 return -EBUSY;
2749 }
2750
2751 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002752 __set_bit(id, wl->ap_hlid_map);
2753 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2754 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002755 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002756 return 0;
2757}
2758
Arik Nemtsov409622e2011-02-23 00:22:29 +02002759static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002760{
2761 int id = hlid - WL1271_AP_STA_HLID_START;
2762
Arik Nemtsov409622e2011-02-23 00:22:29 +02002763 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2764 return;
2765
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002766 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002767 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002768 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002769 __clear_bit(hlid, &wl->ap_ps_map);
2770 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002771}
2772
2773static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2774 struct ieee80211_vif *vif,
2775 struct ieee80211_sta *sta)
2776{
2777 struct wl1271 *wl = hw->priv;
2778 int ret = 0;
2779 u8 hlid;
2780
2781 mutex_lock(&wl->mutex);
2782
2783 if (unlikely(wl->state == WL1271_STATE_OFF))
2784 goto out;
2785
2786 if (wl->bss_type != BSS_TYPE_AP_BSS)
2787 goto out;
2788
2789 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2790
Arik Nemtsov409622e2011-02-23 00:22:29 +02002791 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002792 if (ret < 0)
2793 goto out;
2794
Ido Yariva6208652011-03-01 15:14:41 +02002795 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002796 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002797 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002798
2799 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2800 if (ret < 0)
2801 goto out_sleep;
2802
2803out_sleep:
2804 wl1271_ps_elp_sleep(wl);
2805
Arik Nemtsov409622e2011-02-23 00:22:29 +02002806out_free_sta:
2807 if (ret < 0)
2808 wl1271_free_sta(wl, hlid);
2809
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002810out:
2811 mutex_unlock(&wl->mutex);
2812 return ret;
2813}
2814
2815static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2816 struct ieee80211_vif *vif,
2817 struct ieee80211_sta *sta)
2818{
2819 struct wl1271 *wl = hw->priv;
2820 struct wl1271_station *wl_sta;
2821 int ret = 0, id;
2822
2823 mutex_lock(&wl->mutex);
2824
2825 if (unlikely(wl->state == WL1271_STATE_OFF))
2826 goto out;
2827
2828 if (wl->bss_type != BSS_TYPE_AP_BSS)
2829 goto out;
2830
2831 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2832
2833 wl_sta = (struct wl1271_station *)sta->drv_priv;
2834 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2835 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2836 goto out;
2837
Ido Yariva6208652011-03-01 15:14:41 +02002838 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002839 if (ret < 0)
2840 goto out;
2841
2842 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2843 if (ret < 0)
2844 goto out_sleep;
2845
Arik Nemtsov409622e2011-02-23 00:22:29 +02002846 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002847
2848out_sleep:
2849 wl1271_ps_elp_sleep(wl);
2850
2851out:
2852 mutex_unlock(&wl->mutex);
2853 return ret;
2854}
2855
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002856int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002857 enum ieee80211_ampdu_mlme_action action,
2858 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2859 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002860{
2861 struct wl1271 *wl = hw->priv;
2862 int ret;
2863
2864 mutex_lock(&wl->mutex);
2865
2866 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2867 ret = -EAGAIN;
2868 goto out;
2869 }
2870
Ido Yariva6208652011-03-01 15:14:41 +02002871 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002872 if (ret < 0)
2873 goto out;
2874
2875 switch (action) {
2876 case IEEE80211_AMPDU_RX_START:
2877 if (wl->ba_support) {
2878 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2879 true);
2880 if (!ret)
2881 wl->ba_rx_bitmap |= BIT(tid);
2882 } else {
2883 ret = -ENOTSUPP;
2884 }
2885 break;
2886
2887 case IEEE80211_AMPDU_RX_STOP:
2888 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2889 if (!ret)
2890 wl->ba_rx_bitmap &= ~BIT(tid);
2891 break;
2892
2893 /*
2894 * The BA initiator session management in FW independently.
2895 * Falling break here on purpose for all TX APDU commands.
2896 */
2897 case IEEE80211_AMPDU_TX_START:
2898 case IEEE80211_AMPDU_TX_STOP:
2899 case IEEE80211_AMPDU_TX_OPERATIONAL:
2900 ret = -EINVAL;
2901 break;
2902
2903 default:
2904 wl1271_error("Incorrect ampdu action id=%x\n", action);
2905 ret = -EINVAL;
2906 }
2907
2908 wl1271_ps_elp_sleep(wl);
2909
2910out:
2911 mutex_unlock(&wl->mutex);
2912
2913 return ret;
2914}
2915
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002916/* can't be const, mac80211 writes to this */
2917static struct ieee80211_rate wl1271_rates[] = {
2918 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002919 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2920 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002922 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2923 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002924 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2925 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002926 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2927 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2929 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002930 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2931 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002932 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2933 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002934 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2935 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002937 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2938 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002940 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2941 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002943 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2944 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002946 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2947 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002949 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2950 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002952 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2953 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002955 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2956 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957};
2958
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002959/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002961 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002962 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002963 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2964 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2965 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002966 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002967 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2968 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2969 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002970 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002971 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2972 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2973 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002974 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975};
2976
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002977/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002978static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002979 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002980 7, /* CONF_HW_RXTX_RATE_MCS7 */
2981 6, /* CONF_HW_RXTX_RATE_MCS6 */
2982 5, /* CONF_HW_RXTX_RATE_MCS5 */
2983 4, /* CONF_HW_RXTX_RATE_MCS4 */
2984 3, /* CONF_HW_RXTX_RATE_MCS3 */
2985 2, /* CONF_HW_RXTX_RATE_MCS2 */
2986 1, /* CONF_HW_RXTX_RATE_MCS1 */
2987 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002988
2989 11, /* CONF_HW_RXTX_RATE_54 */
2990 10, /* CONF_HW_RXTX_RATE_48 */
2991 9, /* CONF_HW_RXTX_RATE_36 */
2992 8, /* CONF_HW_RXTX_RATE_24 */
2993
2994 /* TI-specific rate */
2995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2996
2997 7, /* CONF_HW_RXTX_RATE_18 */
2998 6, /* CONF_HW_RXTX_RATE_12 */
2999 3, /* CONF_HW_RXTX_RATE_11 */
3000 5, /* CONF_HW_RXTX_RATE_9 */
3001 4, /* CONF_HW_RXTX_RATE_6 */
3002 2, /* CONF_HW_RXTX_RATE_5_5 */
3003 1, /* CONF_HW_RXTX_RATE_2 */
3004 0 /* CONF_HW_RXTX_RATE_1 */
3005};
3006
Shahar Levie8b03a22010-10-13 16:09:39 +02003007/* 11n STA capabilities */
3008#define HW_RX_HIGHEST_RATE 72
3009
Shahar Levi00d20102010-11-08 11:20:10 +00003010#ifdef CONFIG_WL12XX_HT
3011#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003012 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3013 .ht_supported = true, \
3014 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3015 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3016 .mcs = { \
3017 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3018 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3019 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3020 }, \
3021}
Shahar Levi18357852010-10-13 16:09:41 +02003022#else
Shahar Levi00d20102010-11-08 11:20:10 +00003023#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003024 .ht_supported = false, \
3025}
3026#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028/* can't be const, mac80211 writes to this */
3029static struct ieee80211_supported_band wl1271_band_2ghz = {
3030 .channels = wl1271_channels,
3031 .n_channels = ARRAY_SIZE(wl1271_channels),
3032 .bitrates = wl1271_rates,
3033 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003034 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035};
3036
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003037/* 5 GHz data rates for WL1273 */
3038static struct ieee80211_rate wl1271_rates_5ghz[] = {
3039 { .bitrate = 60,
3040 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3041 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3042 { .bitrate = 90,
3043 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3044 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3045 { .bitrate = 120,
3046 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3047 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3048 { .bitrate = 180,
3049 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3050 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3051 { .bitrate = 240,
3052 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3053 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3054 { .bitrate = 360,
3055 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3056 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3057 { .bitrate = 480,
3058 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3059 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3060 { .bitrate = 540,
3061 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3062 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3063};
3064
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003065/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003066static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003067 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003068 { .hw_value = 8, .center_freq = 5040},
3069 { .hw_value = 9, .center_freq = 5045},
3070 { .hw_value = 11, .center_freq = 5055},
3071 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003072 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003073 { .hw_value = 34, .center_freq = 5170},
3074 { .hw_value = 36, .center_freq = 5180},
3075 { .hw_value = 38, .center_freq = 5190},
3076 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003077 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003078 { .hw_value = 44, .center_freq = 5220},
3079 { .hw_value = 46, .center_freq = 5230},
3080 { .hw_value = 48, .center_freq = 5240},
3081 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003082 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003083 { .hw_value = 60, .center_freq = 5300},
3084 { .hw_value = 64, .center_freq = 5320},
3085 { .hw_value = 100, .center_freq = 5500},
3086 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003087 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003088 { .hw_value = 112, .center_freq = 5560},
3089 { .hw_value = 116, .center_freq = 5580},
3090 { .hw_value = 120, .center_freq = 5600},
3091 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003092 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003093 { .hw_value = 132, .center_freq = 5660},
3094 { .hw_value = 136, .center_freq = 5680},
3095 { .hw_value = 140, .center_freq = 5700},
3096 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003097 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003098 { .hw_value = 157, .center_freq = 5785},
3099 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003100 { .hw_value = 165, .center_freq = 5825},
3101};
3102
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003103/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003104static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003105 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003106 7, /* CONF_HW_RXTX_RATE_MCS7 */
3107 6, /* CONF_HW_RXTX_RATE_MCS6 */
3108 5, /* CONF_HW_RXTX_RATE_MCS5 */
3109 4, /* CONF_HW_RXTX_RATE_MCS4 */
3110 3, /* CONF_HW_RXTX_RATE_MCS3 */
3111 2, /* CONF_HW_RXTX_RATE_MCS2 */
3112 1, /* CONF_HW_RXTX_RATE_MCS1 */
3113 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003114
3115 7, /* CONF_HW_RXTX_RATE_54 */
3116 6, /* CONF_HW_RXTX_RATE_48 */
3117 5, /* CONF_HW_RXTX_RATE_36 */
3118 4, /* CONF_HW_RXTX_RATE_24 */
3119
3120 /* TI-specific rate */
3121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3122
3123 3, /* CONF_HW_RXTX_RATE_18 */
3124 2, /* CONF_HW_RXTX_RATE_12 */
3125 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3126 1, /* CONF_HW_RXTX_RATE_9 */
3127 0, /* CONF_HW_RXTX_RATE_6 */
3128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3129 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3130 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3131};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003132
3133static struct ieee80211_supported_band wl1271_band_5ghz = {
3134 .channels = wl1271_channels_5ghz,
3135 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3136 .bitrates = wl1271_rates_5ghz,
3137 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003138 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003139};
3140
Tobias Klausera0ea9492010-05-20 10:38:11 +02003141static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003142 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3143 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3144};
3145
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003146static const struct ieee80211_ops wl1271_ops = {
3147 .start = wl1271_op_start,
3148 .stop = wl1271_op_stop,
3149 .add_interface = wl1271_op_add_interface,
3150 .remove_interface = wl1271_op_remove_interface,
3151 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003152 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003153 .configure_filter = wl1271_op_configure_filter,
3154 .tx = wl1271_op_tx,
3155 .set_key = wl1271_op_set_key,
3156 .hw_scan = wl1271_op_hw_scan,
3157 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003158 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003160 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003161 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003162 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003163 .sta_add = wl1271_op_sta_add,
3164 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003165 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003166 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003167};
3168
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003169
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003170u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003171{
3172 u8 idx;
3173
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003174 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003175
3176 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3177 wl1271_error("Illegal RX rate from HW: %d", rate);
3178 return 0;
3179 }
3180
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003181 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003182 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3183 wl1271_error("Unsupported RX rate from HW: %d", rate);
3184 return 0;
3185 }
3186
3187 return idx;
3188}
3189
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003190static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3191 struct device_attribute *attr,
3192 char *buf)
3193{
3194 struct wl1271 *wl = dev_get_drvdata(dev);
3195 ssize_t len;
3196
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003197 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003198
3199 mutex_lock(&wl->mutex);
3200 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3201 wl->sg_enabled);
3202 mutex_unlock(&wl->mutex);
3203
3204 return len;
3205
3206}
3207
3208static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3209 struct device_attribute *attr,
3210 const char *buf, size_t count)
3211{
3212 struct wl1271 *wl = dev_get_drvdata(dev);
3213 unsigned long res;
3214 int ret;
3215
3216 ret = strict_strtoul(buf, 10, &res);
3217
3218 if (ret < 0) {
3219 wl1271_warning("incorrect value written to bt_coex_mode");
3220 return count;
3221 }
3222
3223 mutex_lock(&wl->mutex);
3224
3225 res = !!res;
3226
3227 if (res == wl->sg_enabled)
3228 goto out;
3229
3230 wl->sg_enabled = res;
3231
3232 if (wl->state == WL1271_STATE_OFF)
3233 goto out;
3234
Ido Yariva6208652011-03-01 15:14:41 +02003235 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003236 if (ret < 0)
3237 goto out;
3238
3239 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3240 wl1271_ps_elp_sleep(wl);
3241
3242 out:
3243 mutex_unlock(&wl->mutex);
3244 return count;
3245}
3246
3247static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3248 wl1271_sysfs_show_bt_coex_state,
3249 wl1271_sysfs_store_bt_coex_state);
3250
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003251static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3252 struct device_attribute *attr,
3253 char *buf)
3254{
3255 struct wl1271 *wl = dev_get_drvdata(dev);
3256 ssize_t len;
3257
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003258 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003259
3260 mutex_lock(&wl->mutex);
3261 if (wl->hw_pg_ver >= 0)
3262 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3263 else
3264 len = snprintf(buf, len, "n/a\n");
3265 mutex_unlock(&wl->mutex);
3266
3267 return len;
3268}
3269
3270static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3271 wl1271_sysfs_show_hw_pg_ver, NULL);
3272
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003273int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003274{
3275 int ret;
3276
3277 if (wl->mac80211_registered)
3278 return 0;
3279
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003280 ret = wl1271_fetch_nvs(wl);
3281 if (ret == 0) {
3282 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3283
3284 wl->mac_addr[0] = nvs_ptr[11];
3285 wl->mac_addr[1] = nvs_ptr[10];
3286 wl->mac_addr[2] = nvs_ptr[6];
3287 wl->mac_addr[3] = nvs_ptr[5];
3288 wl->mac_addr[4] = nvs_ptr[4];
3289 wl->mac_addr[5] = nvs_ptr[3];
3290 }
3291
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003292 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3293
3294 ret = ieee80211_register_hw(wl->hw);
3295 if (ret < 0) {
3296 wl1271_error("unable to register mac80211 hw: %d", ret);
3297 return ret;
3298 }
3299
3300 wl->mac80211_registered = true;
3301
Eliad Pellerd60080a2010-11-24 12:53:16 +02003302 wl1271_debugfs_init(wl);
3303
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003304 register_netdevice_notifier(&wl1271_dev_notifier);
3305
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 wl1271_notice("loaded");
3307
3308 return 0;
3309}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003310EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003312void wl1271_unregister_hw(struct wl1271 *wl)
3313{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003314 if (wl->state == WL1271_STATE_PLT)
3315 __wl1271_plt_stop(wl);
3316
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003317 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003318 ieee80211_unregister_hw(wl->hw);
3319 wl->mac80211_registered = false;
3320
3321}
3322EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3323
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003324int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003326 static const u32 cipher_suites[] = {
3327 WLAN_CIPHER_SUITE_WEP40,
3328 WLAN_CIPHER_SUITE_WEP104,
3329 WLAN_CIPHER_SUITE_TKIP,
3330 WLAN_CIPHER_SUITE_CCMP,
3331 WL1271_CIPHER_SUITE_GEM,
3332 };
3333
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003334 /* The tx descriptor buffer and the TKIP space. */
3335 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3336 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003337
3338 /* unit us */
3339 /* FIXME: find a proper value */
3340 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003341 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003342
3343 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003344 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003345 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003346 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003347 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003348 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003349 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003350 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3351 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003352
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003353 wl->hw->wiphy->cipher_suites = cipher_suites;
3354 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3355
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003356 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003357 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003358 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003359 /*
3360 * Maximum length of elements in scanning probe request templates
3361 * should be the maximum length possible for a template, without
3362 * the IEEE80211 header of the template
3363 */
3364 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3365 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003366
3367 /*
3368 * We keep local copies of the band structs because we need to
3369 * modify them on a per-device basis.
3370 */
3371 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3372 sizeof(wl1271_band_2ghz));
3373 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3374 sizeof(wl1271_band_5ghz));
3375
3376 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3377 &wl->bands[IEEE80211_BAND_2GHZ];
3378 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3379 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003380
Kalle Valo12bd8942010-03-18 12:26:33 +02003381 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003382 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003383
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003384 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3385
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003386 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003387
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003388 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3389
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003390 wl->hw->max_rx_aggregation_subframes = 8;
3391
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003392 return 0;
3393}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003394EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003395
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003396#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003397
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003398struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003399{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003400 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003401 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003402 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003403 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003404 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003405
3406 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3407 if (!hw) {
3408 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003409 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003410 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003411 }
3412
Julia Lawall929ebd32010-05-15 23:16:39 +02003413 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003414 if (!plat_dev) {
3415 wl1271_error("could not allocate platform_device");
3416 ret = -ENOMEM;
3417 goto err_plat_alloc;
3418 }
3419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003420 wl = hw->priv;
3421 memset(wl, 0, sizeof(*wl));
3422
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003423 INIT_LIST_HEAD(&wl->list);
3424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003425 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003426 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003427
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003428 for (i = 0; i < NUM_TX_QUEUES; i++)
3429 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003430
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003431 for (i = 0; i < NUM_TX_QUEUES; i++)
3432 for (j = 0; j < AP_MAX_LINKS; j++)
3433 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3434
Ido Yariva6208652011-03-01 15:14:41 +02003435 skb_queue_head_init(&wl->deferred_rx_queue);
3436 skb_queue_head_init(&wl->deferred_tx_queue);
3437
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003438 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003439 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003440 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003441 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3442 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3443 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003444 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003445 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003447 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003448 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3449 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003450 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003451 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003452 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003453 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003454 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003455 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003456 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003457 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003458 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003459 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003460 wl->bss_type = MAX_BSS_TYPE;
3461 wl->set_bss_type = MAX_BSS_TYPE;
3462 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003463 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003464 wl->ap_ps_map = 0;
3465 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003466 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003467 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003468
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003469 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003470 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003471 wl->tx_frames[i] = NULL;
3472
3473 spin_lock_init(&wl->wl_lock);
3474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003475 wl->state = WL1271_STATE_OFF;
3476 mutex_init(&wl->mutex);
3477
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003478 /* Apply default driver configuration. */
3479 wl1271_conf_init(wl);
3480
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003481 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3482 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3483 if (!wl->aggr_buf) {
3484 ret = -ENOMEM;
3485 goto err_hw;
3486 }
3487
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003488 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003489 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003490 if (ret) {
3491 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003492 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003493 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003494 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003495
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003496 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003497 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003498 if (ret < 0) {
3499 wl1271_error("failed to create sysfs file bt_coex_state");
3500 goto err_platform;
3501 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003502
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003503 /* Create sysfs file to get HW PG version */
3504 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3505 if (ret < 0) {
3506 wl1271_error("failed to create sysfs file hw_pg_ver");
3507 goto err_bt_coex_state;
3508 }
3509
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003510 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003511
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003512err_bt_coex_state:
3513 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3514
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003515err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003516 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003517
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003518err_aggr:
3519 free_pages((unsigned long)wl->aggr_buf, order);
3520
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003521err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003522 wl1271_debugfs_exit(wl);
3523 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003524
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003525err_plat_alloc:
3526 ieee80211_free_hw(hw);
3527
3528err_hw_alloc:
3529
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003530 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003531}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003532EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003533
3534int wl1271_free_hw(struct wl1271 *wl)
3535{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003536 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003537 free_pages((unsigned long)wl->aggr_buf,
3538 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003539 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003540
3541 wl1271_debugfs_exit(wl);
3542
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003543 vfree(wl->fw);
3544 wl->fw = NULL;
3545 kfree(wl->nvs);
3546 wl->nvs = NULL;
3547
3548 kfree(wl->fw_status);
3549 kfree(wl->tx_res_if);
3550
3551 ieee80211_free_hw(wl->hw);
3552
3553 return 0;
3554}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003555EXPORT_SYMBOL_GPL(wl1271_free_hw);
3556
Guy Eilam491bbd62011-01-12 10:33:29 +01003557u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003558EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003559module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003560MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3561
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003562MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003563MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003564MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");