blob: fe0cf47a656cdf4b3008047c5a00a9c867093df2 [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
Shahar Levi49d750ca2011-03-06 16:32:09 +0200441 if (wl->chip.id == CHIP_ID_1283_PG20)
442 ret = wl128x_cmd_general_parms(wl);
443 else
444 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200445 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200446 return ret;
447
Shahar Levi49d750ca2011-03-06 16:32:09 +0200448 if (wl->chip.id == CHIP_ID_1283_PG20)
449 ret = wl128x_cmd_radio_parms(wl);
450 else
451 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200452 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200453 return ret;
454
Shahar Levi49d750ca2011-03-06 16:32:09 +0200455 if (wl->chip.id != CHIP_ID_1283_PG20) {
456 ret = wl1271_cmd_ext_radio_parms(wl);
457 if (ret < 0)
458 return ret;
459 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200460 if (ret < 0)
461 return ret;
462
Shahar Levi48a61472011-03-06 16:32:08 +0200463 /* Chip-specific initializations */
464 ret = wl1271_chip_specific_init(wl);
465 if (ret < 0)
466 return ret;
467
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200468 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200469 if (ret < 0)
470 return ret;
471
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 ret = wl1271_acx_init_mem_config(wl);
473 if (ret < 0)
474 return ret;
475
Luciano Coelho12419cc2010-02-18 13:25:44 +0200476 /* PHY layer config */
477 ret = wl1271_init_phy_config(wl);
478 if (ret < 0)
479 goto out_free_memmap;
480
481 ret = wl1271_acx_dco_itrim_params(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
485 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200486 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200487 if (ret < 0)
488 goto out_free_memmap;
489
490 /* Bluetooth WLAN coexistence */
491 ret = wl1271_init_pta(wl);
492 if (ret < 0)
493 goto out_free_memmap;
494
495 /* Energy detection */
496 ret = wl1271_init_energy_detection(wl);
497 if (ret < 0)
498 goto out_free_memmap;
499
Gery Kahn1ec610e2011-02-01 03:03:08 -0600500 ret = wl1271_acx_sta_mem_cfg(wl);
501 if (ret < 0)
502 goto out_free_memmap;
503
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100505 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200506 if (ret < 0)
507 goto out_free_memmap;
508
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200509 /* Default TID/AC configuration */
510 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200511 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200512 conf_ac = &wl->conf.tx.ac_conf[i];
513 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
514 conf_ac->cw_max, conf_ac->aifsn,
515 conf_ac->tx_op_limit);
516 if (ret < 0)
517 goto out_free_memmap;
518
Luciano Coelho12419cc2010-02-18 13:25:44 +0200519 conf_tid = &wl->conf.tx.tid_conf[i];
520 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
521 conf_tid->channel_type,
522 conf_tid->tsid,
523 conf_tid->ps_scheme,
524 conf_tid->ack_policy,
525 conf_tid->apsd_conf[0],
526 conf_tid->apsd_conf[1]);
527 if (ret < 0)
528 goto out_free_memmap;
529 }
530
Luciano Coelho12419cc2010-02-18 13:25:44 +0200531 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200532 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300533 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200534 goto out_free_memmap;
535
536 /* Configure for CAM power saving (ie. always active) */
537 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
538 if (ret < 0)
539 goto out_free_memmap;
540
541 /* configure PM */
542 ret = wl1271_acx_pm_config(wl);
543 if (ret < 0)
544 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300545
546 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200547
548 out_free_memmap:
549 kfree(wl->target_mem_map);
550 wl->target_mem_map = NULL;
551
552 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300553}
554
Arik Nemtsovb622d992011-02-23 00:22:31 +0200555static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
556{
557 bool fw_ps;
558
559 /* only regulate station links */
560 if (hlid < WL1271_AP_STA_HLID_START)
561 return;
562
563 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
564
565 /*
566 * Wake up from high level PS if the STA is asleep with too little
567 * blocks in FW or if the STA is awake.
568 */
569 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
570 wl1271_ps_link_end(wl, hlid);
571
572 /* Start high-level PS if the STA is asleep with enough blocks in FW */
573 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
574 wl1271_ps_link_start(wl, hlid, true);
575}
576
577static void wl1271_irq_update_links_status(struct wl1271 *wl,
578 struct wl1271_fw_ap_status *status)
579{
580 u32 cur_fw_ps_map;
581 u8 hlid;
582
583 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
584 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
585 wl1271_debug(DEBUG_PSM,
586 "link ps prev 0x%x cur 0x%x changed 0x%x",
587 wl->ap_fw_ps_map, cur_fw_ps_map,
588 wl->ap_fw_ps_map ^ cur_fw_ps_map);
589
590 wl->ap_fw_ps_map = cur_fw_ps_map;
591 }
592
593 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
594 u8 cnt = status->tx_lnk_free_blks[hlid] -
595 wl->links[hlid].prev_freed_blks;
596
597 wl->links[hlid].prev_freed_blks =
598 status->tx_lnk_free_blks[hlid];
599 wl->links[hlid].allocated_blks -= cnt;
600
601 wl1271_irq_ps_regulate_link(wl, hlid,
602 wl->links[hlid].allocated_blks);
603 }
604}
605
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300606static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200607 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200609 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200610 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611 u32 total = 0;
612 int i;
613
Eliad Pellerc8bde242011-02-02 09:59:35 +0200614 if (wl->bss_type == BSS_TYPE_AP_BSS)
615 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
616 sizeof(struct wl1271_fw_ap_status), false);
617 else
618 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
619 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620
621 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
622 "drv_rx_counter = %d, tx_results_counter = %d)",
623 status->intr,
624 status->fw_rx_counter,
625 status->drv_rx_counter,
626 status->tx_results_counter);
627
628 /* update number of available TX blocks */
629 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300630 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
631 wl->tx_blocks_freed[i];
632
633 wl->tx_blocks_freed[i] =
634 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635 wl->tx_blocks_available += cnt;
636 total += cnt;
637 }
638
Ido Yariva5225502010-10-12 14:49:10 +0200639 /* if more blocks are available now, tx work can be scheduled */
640 if (total)
641 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642
Arik Nemtsovb622d992011-02-23 00:22:31 +0200643 /* for AP update num of allocated TX blocks per link and ps status */
644 if (wl->bss_type == BSS_TYPE_AP_BSS)
645 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200646
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200648 getnstimeofday(&ts);
649 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
650 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651}
652
Ido Yariva6208652011-03-01 15:14:41 +0200653static void wl1271_flush_deferred_work(struct wl1271 *wl)
654{
655 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200656
Ido Yariva6208652011-03-01 15:14:41 +0200657 /* Pass all received frames to the network stack */
658 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
659 ieee80211_rx_ni(wl->hw, skb);
660
661 /* Return sent skbs to the network stack */
662 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
663 ieee80211_tx_status(wl->hw, skb);
664}
665
666static void wl1271_netstack_work(struct work_struct *work)
667{
668 struct wl1271 *wl =
669 container_of(work, struct wl1271, netstack_work);
670
671 do {
672 wl1271_flush_deferred_work(wl);
673 } while (skb_queue_len(&wl->deferred_rx_queue));
674}
675
676#define WL1271_IRQ_MAX_LOOPS 256
677
678irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300681 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200682 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200683 struct wl1271 *wl = (struct wl1271 *)cookie;
684 bool done = false;
685 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200686 unsigned long flags;
687
688 /* TX might be handled here, avoid redundant work */
689 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
690 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691
692 mutex_lock(&wl->mutex);
693
694 wl1271_debug(DEBUG_IRQ, "IRQ work");
695
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200696 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 goto out;
698
Ido Yariva6208652011-03-01 15:14:41 +0200699 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 if (ret < 0)
701 goto out;
702
Ido Yariva6208652011-03-01 15:14:41 +0200703 while (!done && loopcount--) {
704 /*
705 * In order to avoid a race with the hardirq, clear the flag
706 * before acknowledging the chip. Since the mutex is held,
707 * wl1271_ps_elp_wakeup cannot be called concurrently.
708 */
709 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
710 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200711
712 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200713 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200714 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200715 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200716 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200717 continue;
718 }
719
Eliad Pellerccc83b02010-10-27 14:09:57 +0200720 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
721 wl1271_error("watchdog interrupt received! "
722 "starting recovery.");
723 ieee80211_queue_work(wl->hw, &wl->recovery_work);
724
725 /* restarting the chip. ignore any other interrupt. */
726 goto out;
727 }
728
Ido Yariva6208652011-03-01 15:14:41 +0200729 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200730 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
731
Ido Yariv8aad2462011-03-01 15:14:38 +0200732 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200733
Ido Yariva5225502010-10-12 14:49:10 +0200734 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200735 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200736 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200737 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200738 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200739 /*
740 * In order to avoid starvation of the TX path,
741 * call the work function directly.
742 */
743 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200744 } else {
745 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200746 }
747
Ido Yariv8aad2462011-03-01 15:14:38 +0200748 /* check for tx results */
749 if (wl->fw_status->common.tx_results_counter !=
750 (wl->tx_results_count & 0xff))
751 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200752
753 /* Make sure the deferred queues don't get too long */
754 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
755 skb_queue_len(&wl->deferred_rx_queue);
756 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
757 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200758 }
759
760 if (intr & WL1271_ACX_INTR_EVENT_A) {
761 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
762 wl1271_event_handle(wl, 0);
763 }
764
765 if (intr & WL1271_ACX_INTR_EVENT_B) {
766 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
767 wl1271_event_handle(wl, 1);
768 }
769
770 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
771 wl1271_debug(DEBUG_IRQ,
772 "WL1271_ACX_INTR_INIT_COMPLETE");
773
774 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
775 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776 }
777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 wl1271_ps_elp_sleep(wl);
779
780out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200781 spin_lock_irqsave(&wl->wl_lock, flags);
782 /* In case TX was not handled here, queue TX work */
783 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
784 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
785 wl->tx_queue_count)
786 ieee80211_queue_work(wl->hw, &wl->tx_work);
787 spin_unlock_irqrestore(&wl->wl_lock, flags);
788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200790
791 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792}
Ido Yariva6208652011-03-01 15:14:41 +0200793EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300794
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795static int wl1271_fetch_firmware(struct wl1271 *wl)
796{
797 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200798 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300799 int ret;
800
Arik Nemtsov166d5042010-10-16 21:44:57 +0200801 switch (wl->bss_type) {
802 case BSS_TYPE_AP_BSS:
803 fw_name = WL1271_AP_FW_NAME;
804 break;
805 case BSS_TYPE_IBSS:
806 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200807 if (wl->chip.id == CHIP_ID_1283_PG20)
808 fw_name = WL128X_FW_NAME;
809 else
810 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200811 break;
812 default:
813 wl1271_error("no compatible firmware for bss_type %d",
814 wl->bss_type);
815 return -EINVAL;
816 }
817
818 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
819
820 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821
822 if (ret < 0) {
823 wl1271_error("could not get firmware: %d", ret);
824 return ret;
825 }
826
827 if (fw->size % 4) {
828 wl1271_error("firmware size is not multiple of 32 bits: %zu",
829 fw->size);
830 ret = -EILSEQ;
831 goto out;
832 }
833
Arik Nemtsov166d5042010-10-16 21:44:57 +0200834 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300835 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300836 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837
838 if (!wl->fw) {
839 wl1271_error("could not allocate memory for the firmware");
840 ret = -ENOMEM;
841 goto out;
842 }
843
844 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200845 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 ret = 0;
847
848out:
849 release_firmware(fw);
850
851 return ret;
852}
853
854static int wl1271_fetch_nvs(struct wl1271 *wl)
855{
856 const struct firmware *fw;
857 int ret;
858
Shahar Levi5aa42342011-03-06 16:32:07 +0200859 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860
861 if (ret < 0) {
862 wl1271_error("could not get nvs file: %d", ret);
863 return ret;
864 }
865
Shahar Levibc765bf2011-03-06 16:32:10 +0200866 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867
868 if (!wl->nvs) {
869 wl1271_error("could not allocate memory for the nvs file");
870 ret = -ENOMEM;
871 goto out;
872 }
873
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200874 wl->nvs_len = fw->size;
875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876out:
877 release_firmware(fw);
878
879 return ret;
880}
881
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200882static void wl1271_recovery_work(struct work_struct *work)
883{
884 struct wl1271 *wl =
885 container_of(work, struct wl1271, recovery_work);
886
887 mutex_lock(&wl->mutex);
888
889 if (wl->state != WL1271_STATE_ON)
890 goto out;
891
892 wl1271_info("Hardware recovery in progress.");
893
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200894 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
895 ieee80211_connection_loss(wl->vif);
896
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200897 /* reboot the chipset */
898 __wl1271_op_remove_interface(wl);
899 ieee80211_restart_hw(wl->hw);
900
901out:
902 mutex_unlock(&wl->mutex);
903}
904
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905static void wl1271_fw_wakeup(struct wl1271 *wl)
906{
907 u32 elp_reg;
908
909 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300910 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911}
912
913static int wl1271_setup(struct wl1271 *wl)
914{
915 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
916 if (!wl->fw_status)
917 return -ENOMEM;
918
919 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
920 if (!wl->tx_res_if) {
921 kfree(wl->fw_status);
922 return -ENOMEM;
923 }
924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 return 0;
926}
927
928static int wl1271_chip_wakeup(struct wl1271 *wl)
929{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300930 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 int ret = 0;
932
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200933 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200934 ret = wl1271_power_on(wl);
935 if (ret < 0)
936 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200938 wl1271_io_reset(wl);
939 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
941 /* We don't need a real memory partition here, because we only want
942 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300943 memset(&partition, 0, sizeof(partition));
944 partition.reg.start = REGISTERS_BASE;
945 partition.reg.size = REGISTERS_DOWN_SIZE;
946 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947
948 /* ELP module wake up */
949 wl1271_fw_wakeup(wl);
950
951 /* whal_FwCtrl_BootSm() */
952
953 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200954 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
956 /* 1. check if chip id is valid */
957
958 switch (wl->chip.id) {
959 case CHIP_ID_1271_PG10:
960 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
961 wl->chip.id);
962
963 ret = wl1271_setup(wl);
964 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200965 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 break;
967 case CHIP_ID_1271_PG20:
968 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
969 wl->chip.id);
970
971 ret = wl1271_setup(wl);
972 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200973 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 break;
975 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200976 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200978 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 }
980
Arik Nemtsov166d5042010-10-16 21:44:57 +0200981 /* Make sure the firmware type matches the BSS type */
982 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 ret = wl1271_fetch_firmware(wl);
984 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200985 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986 }
987
988 /* No NVS from netlink, try to get it from the filesystem */
989 if (wl->nvs == NULL) {
990 ret = wl1271_fetch_nvs(wl);
991 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200992 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 }
994
995out:
996 return ret;
997}
998
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999int wl1271_plt_start(struct wl1271 *wl)
1000{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001001 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002 int ret;
1003
1004 mutex_lock(&wl->mutex);
1005
1006 wl1271_notice("power up");
1007
1008 if (wl->state != WL1271_STATE_OFF) {
1009 wl1271_error("cannot go into PLT state because not "
1010 "in off state: %d", wl->state);
1011 ret = -EBUSY;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 wl->bss_type = BSS_TYPE_STA_BSS;
1016
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001017 while (retries) {
1018 retries--;
1019 ret = wl1271_chip_wakeup(wl);
1020 if (ret < 0)
1021 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001023 ret = wl1271_boot(wl);
1024 if (ret < 0)
1025 goto power_off;
1026
1027 ret = wl1271_plt_init(wl);
1028 if (ret < 0)
1029 goto irq_disable;
1030
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001031 wl->state = WL1271_STATE_PLT;
1032 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001033 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 goto out;
1035
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001036irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001037 mutex_unlock(&wl->mutex);
1038 /* Unlocking the mutex in the middle of handling is
1039 inherently unsafe. In this case we deem it safe to do,
1040 because we need to let any possibly pending IRQ out of
1041 the system (and while we are WL1271_STATE_OFF the IRQ
1042 work function will not do anything.) Also, any other
1043 possible concurrent operations will fail due to the
1044 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001045 wl1271_disable_interrupts(wl);
1046 wl1271_flush_deferred_work(wl);
1047 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001048 mutex_lock(&wl->mutex);
1049power_off:
1050 wl1271_power_off(wl);
1051 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001053 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1054 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055out:
1056 mutex_unlock(&wl->mutex);
1057
1058 return ret;
1059}
1060
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001061int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062{
1063 int ret = 0;
1064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065 wl1271_notice("power down");
1066
1067 if (wl->state != WL1271_STATE_PLT) {
1068 wl1271_error("cannot power down because not in PLT "
1069 "state: %d", wl->state);
1070 ret = -EBUSY;
1071 goto out;
1072 }
1073
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074 wl1271_power_off(wl);
1075
1076 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001077 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001080 wl1271_disable_interrupts(wl);
1081 wl1271_flush_deferred_work(wl);
1082 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001083 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001084 mutex_lock(&wl->mutex);
1085out:
1086 return ret;
1087}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001088
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001089int wl1271_plt_stop(struct wl1271 *wl)
1090{
1091 int ret;
1092
1093 mutex_lock(&wl->mutex);
1094 ret = __wl1271_plt_stop(wl);
1095 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 return ret;
1097}
1098
Johannes Berg7bb45682011-02-24 14:42:06 +01001099static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100{
1101 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001102 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001103 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001104 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105
Ido Yarivb07d4032011-03-01 15:14:43 +02001106 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1107
1108 if (wl->bss_type == BSS_TYPE_AP_BSS)
1109 hlid = wl1271_tx_get_hlid(skb);
1110
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001111 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001112
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001113 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001114
1115 /*
1116 * The workqueue is slow to process the tx_queue and we need stop
1117 * the queue here, otherwise the queue will get too long.
1118 */
1119 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1120 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1121 ieee80211_stop_queues(wl->hw);
1122 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1123 }
1124
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001125 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001126 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001127 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1128 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1129 } else {
1130 skb_queue_tail(&wl->tx_queue[q], skb);
1131 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132
1133 /*
1134 * The chip specific setup must run before the first TX packet -
1135 * before that, the tx_work will not be initialized!
1136 */
1137
Ido Yarivb07d4032011-03-01 15:14:43 +02001138 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1139 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001140 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001141
1142 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143}
1144
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001145static struct notifier_block wl1271_dev_notifier = {
1146 .notifier_call = wl1271_dev_notify,
1147};
1148
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001149static int wl1271_op_start(struct ieee80211_hw *hw)
1150{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001151 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1152
1153 /*
1154 * We have to delay the booting of the hardware because
1155 * we need to know the local MAC address before downloading and
1156 * initializing the firmware. The MAC address cannot be changed
1157 * after boot, and without the proper MAC address, the firmware
1158 * will not function properly.
1159 *
1160 * The MAC address is first known when the corresponding interface
1161 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001162 *
1163 * In addition, we currently have different firmwares for AP and managed
1164 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001165 */
1166
1167 return 0;
1168}
1169
1170static void wl1271_op_stop(struct ieee80211_hw *hw)
1171{
1172 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1173}
1174
1175static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1176 struct ieee80211_vif *vif)
1177{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001179 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001180 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001182 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001184 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1185 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186
1187 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001188 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001189 wl1271_debug(DEBUG_MAC80211,
1190 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001191 ret = -EBUSY;
1192 goto out;
1193 }
1194
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001195 switch (vif->type) {
1196 case NL80211_IFTYPE_STATION:
1197 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001198 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001199 break;
1200 case NL80211_IFTYPE_ADHOC:
1201 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001202 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001203 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001204 case NL80211_IFTYPE_AP:
1205 wl->bss_type = BSS_TYPE_AP_BSS;
1206 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001207 default:
1208 ret = -EOPNOTSUPP;
1209 goto out;
1210 }
1211
1212 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213
1214 if (wl->state != WL1271_STATE_OFF) {
1215 wl1271_error("cannot start because not in off state: %d",
1216 wl->state);
1217 ret = -EBUSY;
1218 goto out;
1219 }
1220
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001221 while (retries) {
1222 retries--;
1223 ret = wl1271_chip_wakeup(wl);
1224 if (ret < 0)
1225 goto power_off;
1226
1227 ret = wl1271_boot(wl);
1228 if (ret < 0)
1229 goto power_off;
1230
1231 ret = wl1271_hw_init(wl);
1232 if (ret < 0)
1233 goto irq_disable;
1234
Eliad Peller71125ab2010-10-28 21:46:43 +02001235 booted = true;
1236 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001238irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001239 mutex_unlock(&wl->mutex);
1240 /* Unlocking the mutex in the middle of handling is
1241 inherently unsafe. In this case we deem it safe to do,
1242 because we need to let any possibly pending IRQ out of
1243 the system (and while we are WL1271_STATE_OFF the IRQ
1244 work function will not do anything.) Also, any other
1245 possible concurrent operations will fail due to the
1246 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001247 wl1271_disable_interrupts(wl);
1248 wl1271_flush_deferred_work(wl);
1249 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001250 mutex_lock(&wl->mutex);
1251power_off:
1252 wl1271_power_off(wl);
1253 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Eliad Peller71125ab2010-10-28 21:46:43 +02001255 if (!booted) {
1256 wl1271_error("firmware boot failed despite %d retries",
1257 WL1271_BOOT_RETRIES);
1258 goto out;
1259 }
1260
1261 wl->vif = vif;
1262 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001263 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001264
1265 /* update hw/fw version info in wiphy struct */
1266 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001267 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001268 sizeof(wiphy->fw_version));
1269
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001270 /*
1271 * Now we know if 11a is supported (info from the NVS), so disable
1272 * 11a channels if not supported
1273 */
1274 if (!wl->enable_11a)
1275 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1276
1277 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1278 wl->enable_11a ? "" : "not ");
1279
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001280out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 mutex_unlock(&wl->mutex);
1282
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001283 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001284 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 return ret;
1287}
1288
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001289static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int i;
1292
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001293 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001295 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001297 list_del(&wl->list);
1298
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299 WARN_ON(wl->state != WL1271_STATE_ON);
1300
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001301 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001302 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001303 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001304
Luciano Coelho08688d62010-07-08 17:50:07 +03001305 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001306 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1307 kfree(wl->scan.scanned_ch);
1308 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001309 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001310 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 }
1312
1313 wl->state = WL1271_STATE_OFF;
1314
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 mutex_unlock(&wl->mutex);
1316
Ido Yariva6208652011-03-01 15:14:41 +02001317 wl1271_disable_interrupts(wl);
1318 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001319 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001320 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001322 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001323 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324
1325 mutex_lock(&wl->mutex);
1326
1327 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001328 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 wl1271_power_off(wl);
1330
1331 memset(wl->bssid, 0, ETH_ALEN);
1332 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1333 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001335 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001336 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337
1338 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001339 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1341 wl->tx_blocks_available = 0;
1342 wl->tx_results_count = 0;
1343 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001344 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001345 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 wl->time_offset = 0;
1347 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001348 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001349 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001350 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001351 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001352 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001353 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001354 wl->ap_fw_ps_map = 0;
1355 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001356 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 for (i = 0; i < NUM_TX_QUEUES; i++)
1359 wl->tx_blocks_freed[i] = 0;
1360
1361 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001362
1363 kfree(wl->fw_status);
1364 wl->fw_status = NULL;
1365 kfree(wl->tx_res_if);
1366 wl->tx_res_if = NULL;
1367 kfree(wl->target_mem_map);
1368 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001369}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001370
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001371static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1372 struct ieee80211_vif *vif)
1373{
1374 struct wl1271 *wl = hw->priv;
1375
1376 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001377 /*
1378 * wl->vif can be null here if someone shuts down the interface
1379 * just when hardware recovery has been started.
1380 */
1381 if (wl->vif) {
1382 WARN_ON(wl->vif != vif);
1383 __wl1271_op_remove_interface(wl);
1384 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001385
Juuso Oikarinen67353292010-11-18 15:19:02 +02001386 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001387 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388}
1389
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001390static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1391{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001392 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001393
1394 /* combine requested filters with current filter config */
1395 filters = wl->filters | filters;
1396
1397 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1398
1399 if (filters & FIF_PROMISC_IN_BSS) {
1400 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1401 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1402 wl->rx_config |= CFG_BSSID_FILTER_EN;
1403 }
1404 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1405 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1406 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1407 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1408 }
1409 if (filters & FIF_OTHER_BSS) {
1410 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1411 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1412 }
1413 if (filters & FIF_CONTROL) {
1414 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1415 wl->rx_filter |= CFG_RX_CTL_EN;
1416 }
1417 if (filters & FIF_FCSFAIL) {
1418 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1419 wl->rx_filter |= CFG_RX_FCS_ERROR;
1420 }
1421}
1422
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001423static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001424{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001425 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001426 /* we need to use a dummy BSSID for now */
1427 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1428 0xad, 0xbe, 0xef };
1429
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001430 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1431
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001432 /* pass through frames from all BSS */
1433 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1434
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001435 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001436 if (ret < 0)
1437 goto out;
1438
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001439 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001440
1441out:
1442 return ret;
1443}
1444
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001445static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001446{
1447 int ret;
1448
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001449 /*
1450 * One of the side effects of the JOIN command is that is clears
1451 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1452 * to a WPA/WPA2 access point will therefore kill the data-path.
1453 * Currently there is no supported scenario for JOIN during
1454 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1455 * must be handled somehow.
1456 *
1457 */
1458 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1459 wl1271_info("JOIN while associated.");
1460
1461 if (set_assoc)
1462 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1463
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001464 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1465 if (ret < 0)
1466 goto out;
1467
1468 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1469
1470 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1471 goto out;
1472
1473 /*
1474 * The join command disable the keep-alive mode, shut down its process,
1475 * and also clear the template config, so we need to reset it all after
1476 * the join. The acx_aid starts the keep-alive process, and the order
1477 * of the commands below is relevant.
1478 */
1479 ret = wl1271_acx_keep_alive_mode(wl, true);
1480 if (ret < 0)
1481 goto out;
1482
1483 ret = wl1271_acx_aid(wl, wl->aid);
1484 if (ret < 0)
1485 goto out;
1486
1487 ret = wl1271_cmd_build_klv_null_data(wl);
1488 if (ret < 0)
1489 goto out;
1490
1491 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1492 ACX_KEEP_ALIVE_TPL_VALID);
1493 if (ret < 0)
1494 goto out;
1495
1496out:
1497 return ret;
1498}
1499
1500static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001501{
1502 int ret;
1503
1504 /* to stop listening to a channel, we disconnect */
1505 ret = wl1271_cmd_disconnect(wl);
1506 if (ret < 0)
1507 goto out;
1508
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001509 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001510 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001511
1512 /* stop filterting packets based on bssid */
1513 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001514
1515out:
1516 return ret;
1517}
1518
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001519static void wl1271_set_band_rate(struct wl1271 *wl)
1520{
1521 if (wl->band == IEEE80211_BAND_2GHZ)
1522 wl->basic_rate_set = wl->conf.tx.basic_rate;
1523 else
1524 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1525}
1526
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001527static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001528{
1529 int ret;
1530
1531 if (idle) {
1532 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1533 ret = wl1271_unjoin(wl);
1534 if (ret < 0)
1535 goto out;
1536 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001537 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001538 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001539 if (ret < 0)
1540 goto out;
1541 ret = wl1271_acx_keep_alive_config(
1542 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1543 ACX_KEEP_ALIVE_TPL_INVALID);
1544 if (ret < 0)
1545 goto out;
1546 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1547 } else {
1548 /* increment the session counter */
1549 wl->session_counter++;
1550 if (wl->session_counter >= SESSION_COUNTER_MAX)
1551 wl->session_counter = 0;
1552 ret = wl1271_dummy_join(wl);
1553 if (ret < 0)
1554 goto out;
1555 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1556 }
1557
1558out:
1559 return ret;
1560}
1561
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001562static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1563{
1564 struct wl1271 *wl = hw->priv;
1565 struct ieee80211_conf *conf = &hw->conf;
1566 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001567 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001568
1569 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1570
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001571 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1572 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573 channel,
1574 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001575 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001576 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1577 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001579 /*
1580 * mac80211 will go to idle nearly immediately after transmitting some
1581 * frames, such as the deauth. To make sure those frames reach the air,
1582 * wait here until the TX queue is fully flushed.
1583 */
1584 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1585 (conf->flags & IEEE80211_CONF_IDLE))
1586 wl1271_tx_flush(wl);
1587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588 mutex_lock(&wl->mutex);
1589
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001590 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1591 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001592 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001593 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001594
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001595 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1596
Ido Yariva6208652011-03-01 15:14:41 +02001597 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001598 if (ret < 0)
1599 goto out;
1600
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001601 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001602 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1603 ((wl->band != conf->channel->band) ||
1604 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001605 wl->band = conf->channel->band;
1606 wl->channel = channel;
1607
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001608 if (!is_ap) {
1609 /*
1610 * FIXME: the mac80211 should really provide a fixed
1611 * rate to use here. for now, just use the smallest
1612 * possible rate for the band as a fixed rate for
1613 * association frames and other control messages.
1614 */
1615 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1616 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001617
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001618 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1619 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001620 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001621 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001622 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001623
1624 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1625 ret = wl1271_join(wl, false);
1626 if (ret < 0)
1627 wl1271_warning("cmd join on channel "
1628 "failed %d", ret);
1629 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001630 }
1631 }
1632
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001633 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1634 ret = wl1271_sta_handle_idle(wl,
1635 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001636 if (ret < 0)
1637 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001638 }
1639
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001640 /*
1641 * if mac80211 changes the PSM mode, make sure the mode is not
1642 * incorrectly changed after the pspoll failure active window.
1643 */
1644 if (changed & IEEE80211_CONF_CHANGE_PS)
1645 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1646
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001647 if (conf->flags & IEEE80211_CONF_PS &&
1648 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1649 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650
1651 /*
1652 * We enter PSM only if we're already associated.
1653 * If we're not, we'll enter it when joining an SSID,
1654 * through the bss_info_changed() hook.
1655 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001656 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001657 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001658 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001659 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001660 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001662 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001663 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001665 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001666
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001667 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001668 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001669 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001670 }
1671
1672 if (conf->power_level != wl->power_level) {
1673 ret = wl1271_acx_tx_power(wl, conf->power_level);
1674 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001675 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676
1677 wl->power_level = conf->power_level;
1678 }
1679
1680out_sleep:
1681 wl1271_ps_elp_sleep(wl);
1682
1683out:
1684 mutex_unlock(&wl->mutex);
1685
1686 return ret;
1687}
1688
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001689struct wl1271_filter_params {
1690 bool enabled;
1691 int mc_list_length;
1692 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1693};
1694
Jiri Pirko22bedad32010-04-01 21:22:57 +00001695static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1696 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001697{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001698 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001699 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001700 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001701
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001702 if (unlikely(wl->state == WL1271_STATE_OFF))
1703 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001704
Juuso Oikarinen74441132009-10-13 12:47:53 +03001705 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001706 if (!fp) {
1707 wl1271_error("Out of memory setting filters.");
1708 return 0;
1709 }
1710
1711 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001712 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001713 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1714 fp->enabled = false;
1715 } else {
1716 fp->enabled = true;
1717 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001718 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001719 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001720 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001721 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001722 }
1723
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001724 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001725}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001727#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1728 FIF_ALLMULTI | \
1729 FIF_FCSFAIL | \
1730 FIF_BCN_PRBRESP_PROMISC | \
1731 FIF_CONTROL | \
1732 FIF_OTHER_BSS)
1733
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1735 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001736 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001737{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001738 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001740 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001741
Arik Nemtsov7d057862010-10-16 19:25:35 +02001742 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1743 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001744
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001745 mutex_lock(&wl->mutex);
1746
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001747 *total &= WL1271_SUPPORTED_FILTERS;
1748 changed &= WL1271_SUPPORTED_FILTERS;
1749
1750 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001751 goto out;
1752
Ido Yariva6208652011-03-01 15:14:41 +02001753 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001754 if (ret < 0)
1755 goto out;
1756
Arik Nemtsov7d057862010-10-16 19:25:35 +02001757 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1758 if (*total & FIF_ALLMULTI)
1759 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1760 else if (fp)
1761 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1762 fp->mc_list,
1763 fp->mc_list_length);
1764 if (ret < 0)
1765 goto out_sleep;
1766 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001768 /* determine, whether supported filter values have changed */
1769 if (changed == 0)
1770 goto out_sleep;
1771
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001772 /* configure filters */
1773 wl->filters = *total;
1774 wl1271_configure_filters(wl, 0);
1775
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001776 /* apply configured filters */
1777 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1778 if (ret < 0)
1779 goto out_sleep;
1780
1781out_sleep:
1782 wl1271_ps_elp_sleep(wl);
1783
1784out:
1785 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001786 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001787}
1788
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001789static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1790 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1791 u16 tx_seq_16)
1792{
1793 struct wl1271_ap_key *ap_key;
1794 int i;
1795
1796 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1797
1798 if (key_size > MAX_KEY_SIZE)
1799 return -EINVAL;
1800
1801 /*
1802 * Find next free entry in ap_keys. Also check we are not replacing
1803 * an existing key.
1804 */
1805 for (i = 0; i < MAX_NUM_KEYS; i++) {
1806 if (wl->recorded_ap_keys[i] == NULL)
1807 break;
1808
1809 if (wl->recorded_ap_keys[i]->id == id) {
1810 wl1271_warning("trying to record key replacement");
1811 return -EINVAL;
1812 }
1813 }
1814
1815 if (i == MAX_NUM_KEYS)
1816 return -EBUSY;
1817
1818 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1819 if (!ap_key)
1820 return -ENOMEM;
1821
1822 ap_key->id = id;
1823 ap_key->key_type = key_type;
1824 ap_key->key_size = key_size;
1825 memcpy(ap_key->key, key, key_size);
1826 ap_key->hlid = hlid;
1827 ap_key->tx_seq_32 = tx_seq_32;
1828 ap_key->tx_seq_16 = tx_seq_16;
1829
1830 wl->recorded_ap_keys[i] = ap_key;
1831 return 0;
1832}
1833
1834static void wl1271_free_ap_keys(struct wl1271 *wl)
1835{
1836 int i;
1837
1838 for (i = 0; i < MAX_NUM_KEYS; i++) {
1839 kfree(wl->recorded_ap_keys[i]);
1840 wl->recorded_ap_keys[i] = NULL;
1841 }
1842}
1843
1844static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1845{
1846 int i, ret = 0;
1847 struct wl1271_ap_key *key;
1848 bool wep_key_added = false;
1849
1850 for (i = 0; i < MAX_NUM_KEYS; i++) {
1851 if (wl->recorded_ap_keys[i] == NULL)
1852 break;
1853
1854 key = wl->recorded_ap_keys[i];
1855 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1856 key->id, key->key_type,
1857 key->key_size, key->key,
1858 key->hlid, key->tx_seq_32,
1859 key->tx_seq_16);
1860 if (ret < 0)
1861 goto out;
1862
1863 if (key->key_type == KEY_WEP)
1864 wep_key_added = true;
1865 }
1866
1867 if (wep_key_added) {
1868 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1869 if (ret < 0)
1870 goto out;
1871 }
1872
1873out:
1874 wl1271_free_ap_keys(wl);
1875 return ret;
1876}
1877
1878static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1879 u8 key_size, const u8 *key, u32 tx_seq_32,
1880 u16 tx_seq_16, struct ieee80211_sta *sta)
1881{
1882 int ret;
1883 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1884
1885 if (is_ap) {
1886 struct wl1271_station *wl_sta;
1887 u8 hlid;
1888
1889 if (sta) {
1890 wl_sta = (struct wl1271_station *)sta->drv_priv;
1891 hlid = wl_sta->hlid;
1892 } else {
1893 hlid = WL1271_AP_BROADCAST_HLID;
1894 }
1895
1896 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1897 /*
1898 * We do not support removing keys after AP shutdown.
1899 * Pretend we do to make mac80211 happy.
1900 */
1901 if (action != KEY_ADD_OR_REPLACE)
1902 return 0;
1903
1904 ret = wl1271_record_ap_key(wl, id,
1905 key_type, key_size,
1906 key, hlid, tx_seq_32,
1907 tx_seq_16);
1908 } else {
1909 ret = wl1271_cmd_set_ap_key(wl, action,
1910 id, key_type, key_size,
1911 key, hlid, tx_seq_32,
1912 tx_seq_16);
1913 }
1914
1915 if (ret < 0)
1916 return ret;
1917 } else {
1918 const u8 *addr;
1919 static const u8 bcast_addr[ETH_ALEN] = {
1920 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1921 };
1922
1923 addr = sta ? sta->addr : bcast_addr;
1924
1925 if (is_zero_ether_addr(addr)) {
1926 /* We dont support TX only encryption */
1927 return -EOPNOTSUPP;
1928 }
1929
1930 /* The wl1271 does not allow to remove unicast keys - they
1931 will be cleared automatically on next CMD_JOIN. Ignore the
1932 request silently, as we dont want the mac80211 to emit
1933 an error message. */
1934 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1935 return 0;
1936
1937 ret = wl1271_cmd_set_sta_key(wl, action,
1938 id, key_type, key_size,
1939 key, addr, tx_seq_32,
1940 tx_seq_16);
1941 if (ret < 0)
1942 return ret;
1943
1944 /* the default WEP key needs to be configured at least once */
1945 if (key_type == KEY_WEP) {
1946 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1947 wl->default_key);
1948 if (ret < 0)
1949 return ret;
1950 }
1951 }
1952
1953 return 0;
1954}
1955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1957 struct ieee80211_vif *vif,
1958 struct ieee80211_sta *sta,
1959 struct ieee80211_key_conf *key_conf)
1960{
1961 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001963 u32 tx_seq_32 = 0;
1964 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 u8 key_type;
1966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1968
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001969 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001971 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972 key_conf->keylen, key_conf->flags);
1973 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975 mutex_lock(&wl->mutex);
1976
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001977 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1978 ret = -EAGAIN;
1979 goto out_unlock;
1980 }
1981
Ido Yariva6208652011-03-01 15:14:41 +02001982 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983 if (ret < 0)
1984 goto out_unlock;
1985
Johannes Berg97359d12010-08-10 09:46:38 +02001986 switch (key_conf->cipher) {
1987 case WLAN_CIPHER_SUITE_WEP40:
1988 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 key_type = KEY_WEP;
1990
1991 key_conf->hw_key_idx = key_conf->keyidx;
1992 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001993 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001994 key_type = KEY_TKIP;
1995
1996 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001997 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1998 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001999 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002000 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001 key_type = KEY_AES;
2002
2003 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002004 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2005 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002007 case WL1271_CIPHER_SUITE_GEM:
2008 key_type = KEY_GEM;
2009 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2010 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2011 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002013 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002014
2015 ret = -EOPNOTSUPP;
2016 goto out_sleep;
2017 }
2018
2019 switch (cmd) {
2020 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002021 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2022 key_conf->keyidx, key_type,
2023 key_conf->keylen, key_conf->key,
2024 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 if (ret < 0) {
2026 wl1271_error("Could not add or replace key");
2027 goto out_sleep;
2028 }
2029 break;
2030
2031 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002032 ret = wl1271_set_key(wl, KEY_REMOVE,
2033 key_conf->keyidx, key_type,
2034 key_conf->keylen, key_conf->key,
2035 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 if (ret < 0) {
2037 wl1271_error("Could not remove key");
2038 goto out_sleep;
2039 }
2040 break;
2041
2042 default:
2043 wl1271_error("Unsupported key cmd 0x%x", cmd);
2044 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045 break;
2046 }
2047
2048out_sleep:
2049 wl1271_ps_elp_sleep(wl);
2050
2051out_unlock:
2052 mutex_unlock(&wl->mutex);
2053
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054 return ret;
2055}
2056
2057static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002058 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 struct cfg80211_scan_request *req)
2060{
2061 struct wl1271 *wl = hw->priv;
2062 int ret;
2063 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002064 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065
2066 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2067
2068 if (req->n_ssids) {
2069 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002070 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071 }
2072
2073 mutex_lock(&wl->mutex);
2074
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002075 if (wl->state == WL1271_STATE_OFF) {
2076 /*
2077 * We cannot return -EBUSY here because cfg80211 will expect
2078 * a call to ieee80211_scan_completed if we do - in this case
2079 * there won't be any call.
2080 */
2081 ret = -EAGAIN;
2082 goto out;
2083 }
2084
Ido Yariva6208652011-03-01 15:14:41 +02002085 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086 if (ret < 0)
2087 goto out;
2088
Luciano Coelho5924f892010-08-04 03:46:22 +03002089 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002090
2091 wl1271_ps_elp_sleep(wl);
2092
2093out:
2094 mutex_unlock(&wl->mutex);
2095
2096 return ret;
2097}
2098
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002099static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2100{
2101 struct wl1271 *wl = hw->priv;
2102 int ret = 0;
2103
2104 mutex_lock(&wl->mutex);
2105
2106 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2107 ret = -EAGAIN;
2108 goto out;
2109 }
2110
Ido Yariva6208652011-03-01 15:14:41 +02002111 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002112 if (ret < 0)
2113 goto out;
2114
2115 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2116 if (ret < 0)
2117 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2118
2119 wl1271_ps_elp_sleep(wl);
2120
2121out:
2122 mutex_unlock(&wl->mutex);
2123
2124 return ret;
2125}
2126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2128{
2129 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002130 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131
2132 mutex_lock(&wl->mutex);
2133
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002134 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2135 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002136 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002137 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002138
Ido Yariva6208652011-03-01 15:14:41 +02002139 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140 if (ret < 0)
2141 goto out;
2142
2143 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2144 if (ret < 0)
2145 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2146
2147 wl1271_ps_elp_sleep(wl);
2148
2149out:
2150 mutex_unlock(&wl->mutex);
2151
2152 return ret;
2153}
2154
Arik Nemtsove78a2872010-10-16 19:07:21 +02002155static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002156 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002157{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002158 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002159
2160 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002161 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002162 if (ptr[0] == WLAN_EID_SSID) {
2163 wl->ssid_len = ptr[1];
2164 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002165 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002166 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002167 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002168 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002169
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002170 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002171 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002172}
2173
Arik Nemtsove78a2872010-10-16 19:07:21 +02002174static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2175 struct ieee80211_bss_conf *bss_conf,
2176 u32 changed)
2177{
2178 int ret = 0;
2179
2180 if (changed & BSS_CHANGED_ERP_SLOT) {
2181 if (bss_conf->use_short_slot)
2182 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2183 else
2184 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2185 if (ret < 0) {
2186 wl1271_warning("Set slot time failed %d", ret);
2187 goto out;
2188 }
2189 }
2190
2191 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2192 if (bss_conf->use_short_preamble)
2193 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2194 else
2195 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2196 }
2197
2198 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2199 if (bss_conf->use_cts_prot)
2200 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2201 else
2202 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2203 if (ret < 0) {
2204 wl1271_warning("Set ctsprotect failed %d", ret);
2205 goto out;
2206 }
2207 }
2208
2209out:
2210 return ret;
2211}
2212
2213static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2214 struct ieee80211_vif *vif,
2215 struct ieee80211_bss_conf *bss_conf,
2216 u32 changed)
2217{
2218 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2219 int ret = 0;
2220
2221 if ((changed & BSS_CHANGED_BEACON_INT)) {
2222 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2223 bss_conf->beacon_int);
2224
2225 wl->beacon_int = bss_conf->beacon_int;
2226 }
2227
2228 if ((changed & BSS_CHANGED_BEACON)) {
2229 struct ieee80211_hdr *hdr;
2230 int ieoffset = offsetof(struct ieee80211_mgmt,
2231 u.beacon.variable);
2232 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2233 u16 tmpl_id;
2234
2235 if (!beacon)
2236 goto out;
2237
2238 wl1271_debug(DEBUG_MASTER, "beacon updated");
2239
2240 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2241 if (ret < 0) {
2242 dev_kfree_skb(beacon);
2243 goto out;
2244 }
2245 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2246 CMD_TEMPL_BEACON;
2247 ret = wl1271_cmd_template_set(wl, tmpl_id,
2248 beacon->data,
2249 beacon->len, 0,
2250 wl1271_tx_min_rate_get(wl));
2251 if (ret < 0) {
2252 dev_kfree_skb(beacon);
2253 goto out;
2254 }
2255
2256 hdr = (struct ieee80211_hdr *) beacon->data;
2257 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2258 IEEE80211_STYPE_PROBE_RESP);
2259
2260 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2261 CMD_TEMPL_PROBE_RESPONSE;
2262 ret = wl1271_cmd_template_set(wl,
2263 tmpl_id,
2264 beacon->data,
2265 beacon->len, 0,
2266 wl1271_tx_min_rate_get(wl));
2267 dev_kfree_skb(beacon);
2268 if (ret < 0)
2269 goto out;
2270 }
2271
2272out:
2273 return ret;
2274}
2275
2276/* AP mode changes */
2277static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002278 struct ieee80211_vif *vif,
2279 struct ieee80211_bss_conf *bss_conf,
2280 u32 changed)
2281{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002282 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283
Arik Nemtsove78a2872010-10-16 19:07:21 +02002284 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2285 u32 rates = bss_conf->basic_rates;
2286 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
Arik Nemtsove78a2872010-10-16 19:07:21 +02002288 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2289 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2290 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2291 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
Arik Nemtsove78a2872010-10-16 19:07:21 +02002293 /* update the AP management rate policy with the new rates */
2294 mgmt_rc.enabled_rates = wl->basic_rate_set;
2295 mgmt_rc.long_retry_limit = 10;
2296 mgmt_rc.short_retry_limit = 10;
2297 mgmt_rc.aflags = 0;
2298 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2299 ACX_TX_AP_MODE_MGMT_RATE);
2300 if (ret < 0) {
2301 wl1271_error("AP mgmt policy change failed %d", ret);
2302 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002303 }
2304 }
2305
Arik Nemtsove78a2872010-10-16 19:07:21 +02002306 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2307 if (ret < 0)
2308 goto out;
2309
2310 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2311 if (bss_conf->enable_beacon) {
2312 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2313 ret = wl1271_cmd_start_bss(wl);
2314 if (ret < 0)
2315 goto out;
2316
2317 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2318 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002319
2320 ret = wl1271_ap_init_hwenc(wl);
2321 if (ret < 0)
2322 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002323 }
2324 } else {
2325 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2326 ret = wl1271_cmd_stop_bss(wl);
2327 if (ret < 0)
2328 goto out;
2329
2330 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2331 wl1271_debug(DEBUG_AP, "stopped AP");
2332 }
2333 }
2334 }
2335
2336 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2337 if (ret < 0)
2338 goto out;
2339out:
2340 return;
2341}
2342
2343/* STA/IBSS mode changes */
2344static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2345 struct ieee80211_vif *vif,
2346 struct ieee80211_bss_conf *bss_conf,
2347 u32 changed)
2348{
2349 bool do_join = false, set_assoc = false;
2350 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002351 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002352 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002353 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002354 bool sta_exists = false;
2355 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002356
2357 if (is_ibss) {
2358 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2359 changed);
2360 if (ret < 0)
2361 goto out;
2362 }
2363
2364 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2365 do_join = true;
2366
2367 /* Need to update the SSID (for filtering etc) */
2368 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2369 do_join = true;
2370
2371 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002372 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2373 bss_conf->enable_beacon ? "enabled" : "disabled");
2374
2375 if (bss_conf->enable_beacon)
2376 wl->set_bss_type = BSS_TYPE_IBSS;
2377 else
2378 wl->set_bss_type = BSS_TYPE_STA_BSS;
2379 do_join = true;
2380 }
2381
Arik Nemtsove78a2872010-10-16 19:07:21 +02002382 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002383 bool enable = false;
2384 if (bss_conf->cqm_rssi_thold)
2385 enable = true;
2386 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2387 bss_conf->cqm_rssi_thold,
2388 bss_conf->cqm_rssi_hyst);
2389 if (ret < 0)
2390 goto out;
2391 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2392 }
2393
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002394 if ((changed & BSS_CHANGED_BSSID) &&
2395 /*
2396 * Now we know the correct bssid, so we send a new join command
2397 * and enable the BSSID filter
2398 */
2399 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002400 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002401
Eliad Pellerfa287b82010-12-26 09:27:50 +01002402 if (!is_zero_ether_addr(wl->bssid)) {
2403 ret = wl1271_cmd_build_null_data(wl);
2404 if (ret < 0)
2405 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002406
Eliad Pellerfa287b82010-12-26 09:27:50 +01002407 ret = wl1271_build_qos_null_data(wl);
2408 if (ret < 0)
2409 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002410
Eliad Pellerfa287b82010-12-26 09:27:50 +01002411 /* filter out all packets not from this BSSID */
2412 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002413
Eliad Pellerfa287b82010-12-26 09:27:50 +01002414 /* Need to update the BSSID (for filtering etc) */
2415 do_join = true;
2416 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002417 }
2418
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002419 rcu_read_lock();
2420 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2421 if (sta) {
2422 /* save the supp_rates of the ap */
2423 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2424 if (sta->ht_cap.ht_supported)
2425 sta_rate_set |=
2426 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002427 sta_ht_cap = sta->ht_cap;
2428 sta_exists = true;
2429 }
2430 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002431
Arik Nemtsova1008852011-02-12 23:24:20 +02002432 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002433 /* handle new association with HT and HT information change */
2434 if ((changed & BSS_CHANGED_HT) &&
2435 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002436 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002437 true);
2438 if (ret < 0) {
2439 wl1271_warning("Set ht cap true failed %d",
2440 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002441 goto out;
2442 }
2443 ret = wl1271_acx_set_ht_information(wl,
2444 bss_conf->ht_operation_mode);
2445 if (ret < 0) {
2446 wl1271_warning("Set ht information failed %d",
2447 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002448 goto out;
2449 }
2450 }
2451 /* handle new association without HT and disassociation */
2452 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002453 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002454 false);
2455 if (ret < 0) {
2456 wl1271_warning("Set ht cap false failed %d",
2457 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002458 goto out;
2459 }
2460 }
2461 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002462
Arik Nemtsove78a2872010-10-16 19:07:21 +02002463 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002465 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002466 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002467 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002468 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002469
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002470 wl->ps_poll_failures = 0;
2471
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002472 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473 * use basic rates from AP, and determine lowest rate
2474 * to use with control frames.
2475 */
2476 rates = bss_conf->basic_rates;
2477 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2478 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002479 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002480 if (sta_rate_set)
2481 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2482 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002483 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002484 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002485 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002486
2487 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002488 * with wl1271, we don't need to update the
2489 * beacon_int and dtim_period, because the firmware
2490 * updates it by itself when the first beacon is
2491 * received after a join.
2492 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002493 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2494 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002495 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002497 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002498 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002499 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002500 dev_kfree_skb(wl->probereq);
2501 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2502 ieoffset = offsetof(struct ieee80211_mgmt,
2503 u.probe_req.variable);
2504 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002505
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002506 /* enable the connection monitoring feature */
2507 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002509 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002510
2511 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002512 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2513 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002514 enum wl1271_cmd_ps_mode mode;
2515
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002516 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002517 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002518 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002519 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002521 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002522 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002523 } else {
2524 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002525 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002526 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002527 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002528
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002529 /* free probe-request template */
2530 dev_kfree_skb(wl->probereq);
2531 wl->probereq = NULL;
2532
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002533 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002534 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002535
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002536 /* revert back to minimum rates for the current band */
2537 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002538 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002539 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002540 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002541 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002542
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002543 /* disable connection monitor features */
2544 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002545
2546 /* Disable the keep-alive feature */
2547 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002548 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002549 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002550
2551 /* restore the bssid filter and go to dummy bssid */
2552 wl1271_unjoin(wl);
2553 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554 }
2555 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002556
Arik Nemtsove78a2872010-10-16 19:07:21 +02002557 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2558 if (ret < 0)
2559 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002560
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002561 if (changed & BSS_CHANGED_ARP_FILTER) {
2562 __be32 addr = bss_conf->arp_addr_list[0];
2563 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2564
Eliad Pellerc5312772010-12-09 11:31:27 +02002565 if (bss_conf->arp_addr_cnt == 1 &&
2566 bss_conf->arp_filter_enabled) {
2567 /*
2568 * The template should have been configured only upon
2569 * association. however, it seems that the correct ip
2570 * isn't being set (when sending), so we have to
2571 * reconfigure the template upon every ip change.
2572 */
2573 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2574 if (ret < 0) {
2575 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002576 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002577 }
2578
2579 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002580 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002581 addr);
2582 } else
2583 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002584
2585 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002586 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002587 }
2588
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002589 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002590 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002591 if (ret < 0) {
2592 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002593 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002594 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002595 }
2596
Arik Nemtsove78a2872010-10-16 19:07:21 +02002597out:
2598 return;
2599}
2600
2601static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2602 struct ieee80211_vif *vif,
2603 struct ieee80211_bss_conf *bss_conf,
2604 u32 changed)
2605{
2606 struct wl1271 *wl = hw->priv;
2607 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2608 int ret;
2609
2610 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2611 (int)changed);
2612
2613 mutex_lock(&wl->mutex);
2614
2615 if (unlikely(wl->state == WL1271_STATE_OFF))
2616 goto out;
2617
Ido Yariva6208652011-03-01 15:14:41 +02002618 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002619 if (ret < 0)
2620 goto out;
2621
2622 if (is_ap)
2623 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2624 else
2625 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627 wl1271_ps_elp_sleep(wl);
2628
2629out:
2630 mutex_unlock(&wl->mutex);
2631}
2632
Kalle Valoc6999d82010-02-18 13:25:41 +02002633static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2634 const struct ieee80211_tx_queue_params *params)
2635{
2636 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002637 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002638 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002639
2640 mutex_lock(&wl->mutex);
2641
2642 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2643
Kalle Valo4695dc92010-03-18 12:26:38 +02002644 if (params->uapsd)
2645 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2646 else
2647 ps_scheme = CONF_PS_SCHEME_LEGACY;
2648
Arik Nemtsov488fc542010-10-16 20:33:45 +02002649 if (wl->state == WL1271_STATE_OFF) {
2650 /*
2651 * If the state is off, the parameters will be recorded and
2652 * configured on init. This happens in AP-mode.
2653 */
2654 struct conf_tx_ac_category *conf_ac =
2655 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2656 struct conf_tx_tid *conf_tid =
2657 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2658
2659 conf_ac->ac = wl1271_tx_get_queue(queue);
2660 conf_ac->cw_min = (u8)params->cw_min;
2661 conf_ac->cw_max = params->cw_max;
2662 conf_ac->aifsn = params->aifs;
2663 conf_ac->tx_op_limit = params->txop << 5;
2664
2665 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2666 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2667 conf_tid->tsid = wl1271_tx_get_queue(queue);
2668 conf_tid->ps_scheme = ps_scheme;
2669 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2670 conf_tid->apsd_conf[0] = 0;
2671 conf_tid->apsd_conf[1] = 0;
2672 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002673 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002674 if (ret < 0)
2675 goto out;
2676
2677 /*
2678 * the txop is confed in units of 32us by the mac80211,
2679 * we need us
2680 */
2681 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2682 params->cw_min, params->cw_max,
2683 params->aifs, params->txop << 5);
2684 if (ret < 0)
2685 goto out_sleep;
2686
2687 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2688 CONF_CHANNEL_TYPE_EDCF,
2689 wl1271_tx_get_queue(queue),
2690 ps_scheme, CONF_ACK_POLICY_LEGACY,
2691 0, 0);
2692 if (ret < 0)
2693 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002694
2695out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002696 wl1271_ps_elp_sleep(wl);
2697 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002698
2699out:
2700 mutex_unlock(&wl->mutex);
2701
2702 return ret;
2703}
2704
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002705static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2706{
2707
2708 struct wl1271 *wl = hw->priv;
2709 u64 mactime = ULLONG_MAX;
2710 int ret;
2711
2712 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2713
2714 mutex_lock(&wl->mutex);
2715
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002716 if (unlikely(wl->state == WL1271_STATE_OFF))
2717 goto out;
2718
Ido Yariva6208652011-03-01 15:14:41 +02002719 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002720 if (ret < 0)
2721 goto out;
2722
2723 ret = wl1271_acx_tsf_info(wl, &mactime);
2724 if (ret < 0)
2725 goto out_sleep;
2726
2727out_sleep:
2728 wl1271_ps_elp_sleep(wl);
2729
2730out:
2731 mutex_unlock(&wl->mutex);
2732 return mactime;
2733}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734
John W. Linvilleece550d2010-07-28 16:41:06 -04002735static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2736 struct survey_info *survey)
2737{
2738 struct wl1271 *wl = hw->priv;
2739 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002740
John W. Linvilleece550d2010-07-28 16:41:06 -04002741 if (idx != 0)
2742 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002743
John W. Linvilleece550d2010-07-28 16:41:06 -04002744 survey->channel = conf->channel;
2745 survey->filled = SURVEY_INFO_NOISE_DBM;
2746 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002747
John W. Linvilleece550d2010-07-28 16:41:06 -04002748 return 0;
2749}
2750
Arik Nemtsov409622e2011-02-23 00:22:29 +02002751static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002752 struct ieee80211_sta *sta,
2753 u8 *hlid)
2754{
2755 struct wl1271_station *wl_sta;
2756 int id;
2757
2758 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2759 if (id >= AP_MAX_STATIONS) {
2760 wl1271_warning("could not allocate HLID - too much stations");
2761 return -EBUSY;
2762 }
2763
2764 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002765 __set_bit(id, wl->ap_hlid_map);
2766 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2767 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002768 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002769 return 0;
2770}
2771
Arik Nemtsov409622e2011-02-23 00:22:29 +02002772static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002773{
2774 int id = hlid - WL1271_AP_STA_HLID_START;
2775
Arik Nemtsov409622e2011-02-23 00:22:29 +02002776 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2777 return;
2778
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002779 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002780 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002781 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002782 __clear_bit(hlid, &wl->ap_ps_map);
2783 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002784}
2785
2786static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2787 struct ieee80211_vif *vif,
2788 struct ieee80211_sta *sta)
2789{
2790 struct wl1271 *wl = hw->priv;
2791 int ret = 0;
2792 u8 hlid;
2793
2794 mutex_lock(&wl->mutex);
2795
2796 if (unlikely(wl->state == WL1271_STATE_OFF))
2797 goto out;
2798
2799 if (wl->bss_type != BSS_TYPE_AP_BSS)
2800 goto out;
2801
2802 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2803
Arik Nemtsov409622e2011-02-23 00:22:29 +02002804 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002805 if (ret < 0)
2806 goto out;
2807
Ido Yariva6208652011-03-01 15:14:41 +02002808 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002809 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002810 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002811
2812 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2813 if (ret < 0)
2814 goto out_sleep;
2815
2816out_sleep:
2817 wl1271_ps_elp_sleep(wl);
2818
Arik Nemtsov409622e2011-02-23 00:22:29 +02002819out_free_sta:
2820 if (ret < 0)
2821 wl1271_free_sta(wl, hlid);
2822
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002823out:
2824 mutex_unlock(&wl->mutex);
2825 return ret;
2826}
2827
2828static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2829 struct ieee80211_vif *vif,
2830 struct ieee80211_sta *sta)
2831{
2832 struct wl1271 *wl = hw->priv;
2833 struct wl1271_station *wl_sta;
2834 int ret = 0, id;
2835
2836 mutex_lock(&wl->mutex);
2837
2838 if (unlikely(wl->state == WL1271_STATE_OFF))
2839 goto out;
2840
2841 if (wl->bss_type != BSS_TYPE_AP_BSS)
2842 goto out;
2843
2844 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2845
2846 wl_sta = (struct wl1271_station *)sta->drv_priv;
2847 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2848 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2849 goto out;
2850
Ido Yariva6208652011-03-01 15:14:41 +02002851 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002852 if (ret < 0)
2853 goto out;
2854
2855 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2856 if (ret < 0)
2857 goto out_sleep;
2858
Arik Nemtsov409622e2011-02-23 00:22:29 +02002859 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002860
2861out_sleep:
2862 wl1271_ps_elp_sleep(wl);
2863
2864out:
2865 mutex_unlock(&wl->mutex);
2866 return ret;
2867}
2868
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002869int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002870 enum ieee80211_ampdu_mlme_action action,
2871 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2872 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002873{
2874 struct wl1271 *wl = hw->priv;
2875 int ret;
2876
2877 mutex_lock(&wl->mutex);
2878
2879 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2880 ret = -EAGAIN;
2881 goto out;
2882 }
2883
Ido Yariva6208652011-03-01 15:14:41 +02002884 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002885 if (ret < 0)
2886 goto out;
2887
2888 switch (action) {
2889 case IEEE80211_AMPDU_RX_START:
2890 if (wl->ba_support) {
2891 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2892 true);
2893 if (!ret)
2894 wl->ba_rx_bitmap |= BIT(tid);
2895 } else {
2896 ret = -ENOTSUPP;
2897 }
2898 break;
2899
2900 case IEEE80211_AMPDU_RX_STOP:
2901 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2902 if (!ret)
2903 wl->ba_rx_bitmap &= ~BIT(tid);
2904 break;
2905
2906 /*
2907 * The BA initiator session management in FW independently.
2908 * Falling break here on purpose for all TX APDU commands.
2909 */
2910 case IEEE80211_AMPDU_TX_START:
2911 case IEEE80211_AMPDU_TX_STOP:
2912 case IEEE80211_AMPDU_TX_OPERATIONAL:
2913 ret = -EINVAL;
2914 break;
2915
2916 default:
2917 wl1271_error("Incorrect ampdu action id=%x\n", action);
2918 ret = -EINVAL;
2919 }
2920
2921 wl1271_ps_elp_sleep(wl);
2922
2923out:
2924 mutex_unlock(&wl->mutex);
2925
2926 return ret;
2927}
2928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929/* can't be const, mac80211 writes to this */
2930static struct ieee80211_rate wl1271_rates[] = {
2931 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002932 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2933 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002935 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2936 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2938 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002939 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2940 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2942 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002943 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2944 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2946 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002947 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2948 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002950 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2951 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002953 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2954 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002956 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2957 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002959 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2960 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002962 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2963 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002965 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2966 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002968 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2969 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970};
2971
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002972/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002974 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002975 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002976 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2977 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2978 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002979 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002980 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2981 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2982 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002983 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002984 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2985 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2986 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002987 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988};
2989
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002990/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002991static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002992 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002993 7, /* CONF_HW_RXTX_RATE_MCS7 */
2994 6, /* CONF_HW_RXTX_RATE_MCS6 */
2995 5, /* CONF_HW_RXTX_RATE_MCS5 */
2996 4, /* CONF_HW_RXTX_RATE_MCS4 */
2997 3, /* CONF_HW_RXTX_RATE_MCS3 */
2998 2, /* CONF_HW_RXTX_RATE_MCS2 */
2999 1, /* CONF_HW_RXTX_RATE_MCS1 */
3000 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003001
3002 11, /* CONF_HW_RXTX_RATE_54 */
3003 10, /* CONF_HW_RXTX_RATE_48 */
3004 9, /* CONF_HW_RXTX_RATE_36 */
3005 8, /* CONF_HW_RXTX_RATE_24 */
3006
3007 /* TI-specific rate */
3008 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3009
3010 7, /* CONF_HW_RXTX_RATE_18 */
3011 6, /* CONF_HW_RXTX_RATE_12 */
3012 3, /* CONF_HW_RXTX_RATE_11 */
3013 5, /* CONF_HW_RXTX_RATE_9 */
3014 4, /* CONF_HW_RXTX_RATE_6 */
3015 2, /* CONF_HW_RXTX_RATE_5_5 */
3016 1, /* CONF_HW_RXTX_RATE_2 */
3017 0 /* CONF_HW_RXTX_RATE_1 */
3018};
3019
Shahar Levie8b03a22010-10-13 16:09:39 +02003020/* 11n STA capabilities */
3021#define HW_RX_HIGHEST_RATE 72
3022
Shahar Levi00d20102010-11-08 11:20:10 +00003023#ifdef CONFIG_WL12XX_HT
3024#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003025 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3026 .ht_supported = true, \
3027 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3028 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3029 .mcs = { \
3030 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3031 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3032 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3033 }, \
3034}
Shahar Levi18357852010-10-13 16:09:41 +02003035#else
Shahar Levi00d20102010-11-08 11:20:10 +00003036#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003037 .ht_supported = false, \
3038}
3039#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041/* can't be const, mac80211 writes to this */
3042static struct ieee80211_supported_band wl1271_band_2ghz = {
3043 .channels = wl1271_channels,
3044 .n_channels = ARRAY_SIZE(wl1271_channels),
3045 .bitrates = wl1271_rates,
3046 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003047 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003048};
3049
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003050/* 5 GHz data rates for WL1273 */
3051static struct ieee80211_rate wl1271_rates_5ghz[] = {
3052 { .bitrate = 60,
3053 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3054 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3055 { .bitrate = 90,
3056 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3057 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3058 { .bitrate = 120,
3059 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3060 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3061 { .bitrate = 180,
3062 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3063 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3064 { .bitrate = 240,
3065 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3066 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3067 { .bitrate = 360,
3068 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3069 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3070 { .bitrate = 480,
3071 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3072 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3073 { .bitrate = 540,
3074 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3075 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3076};
3077
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003078/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003079static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003080 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003081 { .hw_value = 8, .center_freq = 5040},
3082 { .hw_value = 9, .center_freq = 5045},
3083 { .hw_value = 11, .center_freq = 5055},
3084 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003085 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003086 { .hw_value = 34, .center_freq = 5170},
3087 { .hw_value = 36, .center_freq = 5180},
3088 { .hw_value = 38, .center_freq = 5190},
3089 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003090 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003091 { .hw_value = 44, .center_freq = 5220},
3092 { .hw_value = 46, .center_freq = 5230},
3093 { .hw_value = 48, .center_freq = 5240},
3094 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003095 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003096 { .hw_value = 60, .center_freq = 5300},
3097 { .hw_value = 64, .center_freq = 5320},
3098 { .hw_value = 100, .center_freq = 5500},
3099 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003100 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003101 { .hw_value = 112, .center_freq = 5560},
3102 { .hw_value = 116, .center_freq = 5580},
3103 { .hw_value = 120, .center_freq = 5600},
3104 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003105 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003106 { .hw_value = 132, .center_freq = 5660},
3107 { .hw_value = 136, .center_freq = 5680},
3108 { .hw_value = 140, .center_freq = 5700},
3109 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003110 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003111 { .hw_value = 157, .center_freq = 5785},
3112 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003113 { .hw_value = 165, .center_freq = 5825},
3114};
3115
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003116/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003117static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003118 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003119 7, /* CONF_HW_RXTX_RATE_MCS7 */
3120 6, /* CONF_HW_RXTX_RATE_MCS6 */
3121 5, /* CONF_HW_RXTX_RATE_MCS5 */
3122 4, /* CONF_HW_RXTX_RATE_MCS4 */
3123 3, /* CONF_HW_RXTX_RATE_MCS3 */
3124 2, /* CONF_HW_RXTX_RATE_MCS2 */
3125 1, /* CONF_HW_RXTX_RATE_MCS1 */
3126 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003127
3128 7, /* CONF_HW_RXTX_RATE_54 */
3129 6, /* CONF_HW_RXTX_RATE_48 */
3130 5, /* CONF_HW_RXTX_RATE_36 */
3131 4, /* CONF_HW_RXTX_RATE_24 */
3132
3133 /* TI-specific rate */
3134 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3135
3136 3, /* CONF_HW_RXTX_RATE_18 */
3137 2, /* CONF_HW_RXTX_RATE_12 */
3138 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3139 1, /* CONF_HW_RXTX_RATE_9 */
3140 0, /* CONF_HW_RXTX_RATE_6 */
3141 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3142 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3143 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3144};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003145
3146static struct ieee80211_supported_band wl1271_band_5ghz = {
3147 .channels = wl1271_channels_5ghz,
3148 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3149 .bitrates = wl1271_rates_5ghz,
3150 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003151 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003152};
3153
Tobias Klausera0ea9492010-05-20 10:38:11 +02003154static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003155 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3156 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3157};
3158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003159static const struct ieee80211_ops wl1271_ops = {
3160 .start = wl1271_op_start,
3161 .stop = wl1271_op_stop,
3162 .add_interface = wl1271_op_add_interface,
3163 .remove_interface = wl1271_op_remove_interface,
3164 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003165 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003166 .configure_filter = wl1271_op_configure_filter,
3167 .tx = wl1271_op_tx,
3168 .set_key = wl1271_op_set_key,
3169 .hw_scan = wl1271_op_hw_scan,
3170 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003171 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003172 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003173 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003174 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003175 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003176 .sta_add = wl1271_op_sta_add,
3177 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003178 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003179 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003180};
3181
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003182
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003183u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003184{
3185 u8 idx;
3186
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003187 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003188
3189 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3190 wl1271_error("Illegal RX rate from HW: %d", rate);
3191 return 0;
3192 }
3193
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003194 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003195 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3196 wl1271_error("Unsupported RX rate from HW: %d", rate);
3197 return 0;
3198 }
3199
3200 return idx;
3201}
3202
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003203static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3204 struct device_attribute *attr,
3205 char *buf)
3206{
3207 struct wl1271 *wl = dev_get_drvdata(dev);
3208 ssize_t len;
3209
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003210 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003211
3212 mutex_lock(&wl->mutex);
3213 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3214 wl->sg_enabled);
3215 mutex_unlock(&wl->mutex);
3216
3217 return len;
3218
3219}
3220
3221static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3222 struct device_attribute *attr,
3223 const char *buf, size_t count)
3224{
3225 struct wl1271 *wl = dev_get_drvdata(dev);
3226 unsigned long res;
3227 int ret;
3228
3229 ret = strict_strtoul(buf, 10, &res);
3230
3231 if (ret < 0) {
3232 wl1271_warning("incorrect value written to bt_coex_mode");
3233 return count;
3234 }
3235
3236 mutex_lock(&wl->mutex);
3237
3238 res = !!res;
3239
3240 if (res == wl->sg_enabled)
3241 goto out;
3242
3243 wl->sg_enabled = res;
3244
3245 if (wl->state == WL1271_STATE_OFF)
3246 goto out;
3247
Ido Yariva6208652011-03-01 15:14:41 +02003248 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003249 if (ret < 0)
3250 goto out;
3251
3252 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3253 wl1271_ps_elp_sleep(wl);
3254
3255 out:
3256 mutex_unlock(&wl->mutex);
3257 return count;
3258}
3259
3260static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3261 wl1271_sysfs_show_bt_coex_state,
3262 wl1271_sysfs_store_bt_coex_state);
3263
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003264static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3265 struct device_attribute *attr,
3266 char *buf)
3267{
3268 struct wl1271 *wl = dev_get_drvdata(dev);
3269 ssize_t len;
3270
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003271 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003272
3273 mutex_lock(&wl->mutex);
3274 if (wl->hw_pg_ver >= 0)
3275 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3276 else
3277 len = snprintf(buf, len, "n/a\n");
3278 mutex_unlock(&wl->mutex);
3279
3280 return len;
3281}
3282
3283static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3284 wl1271_sysfs_show_hw_pg_ver, NULL);
3285
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003286int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003287{
3288 int ret;
3289
3290 if (wl->mac80211_registered)
3291 return 0;
3292
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003293 ret = wl1271_fetch_nvs(wl);
3294 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003295 /* NOTE: The wl->nvs->nvs element must be first, in
3296 * order to simplify the casting, we assume it is at
3297 * the beginning of the wl->nvs structure.
3298 */
3299 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003300
3301 wl->mac_addr[0] = nvs_ptr[11];
3302 wl->mac_addr[1] = nvs_ptr[10];
3303 wl->mac_addr[2] = nvs_ptr[6];
3304 wl->mac_addr[3] = nvs_ptr[5];
3305 wl->mac_addr[4] = nvs_ptr[4];
3306 wl->mac_addr[5] = nvs_ptr[3];
3307 }
3308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3310
3311 ret = ieee80211_register_hw(wl->hw);
3312 if (ret < 0) {
3313 wl1271_error("unable to register mac80211 hw: %d", ret);
3314 return ret;
3315 }
3316
3317 wl->mac80211_registered = true;
3318
Eliad Pellerd60080a2010-11-24 12:53:16 +02003319 wl1271_debugfs_init(wl);
3320
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003321 register_netdevice_notifier(&wl1271_dev_notifier);
3322
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003323 wl1271_notice("loaded");
3324
3325 return 0;
3326}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003327EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003329void wl1271_unregister_hw(struct wl1271 *wl)
3330{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003331 if (wl->state == WL1271_STATE_PLT)
3332 __wl1271_plt_stop(wl);
3333
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003334 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003335 ieee80211_unregister_hw(wl->hw);
3336 wl->mac80211_registered = false;
3337
3338}
3339EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3340
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003341int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003342{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003343 static const u32 cipher_suites[] = {
3344 WLAN_CIPHER_SUITE_WEP40,
3345 WLAN_CIPHER_SUITE_WEP104,
3346 WLAN_CIPHER_SUITE_TKIP,
3347 WLAN_CIPHER_SUITE_CCMP,
3348 WL1271_CIPHER_SUITE_GEM,
3349 };
3350
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003351 /* The tx descriptor buffer and the TKIP space. */
3352 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3353 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003354
3355 /* unit us */
3356 /* FIXME: find a proper value */
3357 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003358 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003359
3360 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003361 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003362 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003363 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003364 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003365 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003366 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003367 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3368 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003369
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003370 wl->hw->wiphy->cipher_suites = cipher_suites;
3371 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3372
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003373 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003374 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003375 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003376 /*
3377 * Maximum length of elements in scanning probe request templates
3378 * should be the maximum length possible for a template, without
3379 * the IEEE80211 header of the template
3380 */
3381 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3382 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003383
3384 /*
3385 * We keep local copies of the band structs because we need to
3386 * modify them on a per-device basis.
3387 */
3388 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3389 sizeof(wl1271_band_2ghz));
3390 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3391 sizeof(wl1271_band_5ghz));
3392
3393 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3394 &wl->bands[IEEE80211_BAND_2GHZ];
3395 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3396 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003397
Kalle Valo12bd8942010-03-18 12:26:33 +02003398 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003399 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003400
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003401 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3402
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003403 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003404
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003405 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3406
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003407 wl->hw->max_rx_aggregation_subframes = 8;
3408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003409 return 0;
3410}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003411EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003412
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003413#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003414
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003415struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003416{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003417 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003418 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003420 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003421 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003422
3423 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3424 if (!hw) {
3425 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003426 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003427 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428 }
3429
Julia Lawall929ebd32010-05-15 23:16:39 +02003430 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003431 if (!plat_dev) {
3432 wl1271_error("could not allocate platform_device");
3433 ret = -ENOMEM;
3434 goto err_plat_alloc;
3435 }
3436
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003437 wl = hw->priv;
3438 memset(wl, 0, sizeof(*wl));
3439
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003440 INIT_LIST_HEAD(&wl->list);
3441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003442 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003443 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003444
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003445 for (i = 0; i < NUM_TX_QUEUES; i++)
3446 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003447
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003448 for (i = 0; i < NUM_TX_QUEUES; i++)
3449 for (j = 0; j < AP_MAX_LINKS; j++)
3450 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3451
Ido Yariva6208652011-03-01 15:14:41 +02003452 skb_queue_head_init(&wl->deferred_rx_queue);
3453 skb_queue_head_init(&wl->deferred_tx_queue);
3454
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003455 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003456 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003457 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003458 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3459 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3460 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003462 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003463 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003464 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003465 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3466 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003467 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003468 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003469 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003470 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003471 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003472 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003473 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003474 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003475 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003476 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003477 wl->bss_type = MAX_BSS_TYPE;
3478 wl->set_bss_type = MAX_BSS_TYPE;
3479 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003480 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003481 wl->ap_ps_map = 0;
3482 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003483 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003484 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003486 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003487 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003488 wl->tx_frames[i] = NULL;
3489
3490 spin_lock_init(&wl->wl_lock);
3491
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003492 wl->state = WL1271_STATE_OFF;
3493 mutex_init(&wl->mutex);
3494
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003495 /* Apply default driver configuration. */
3496 wl1271_conf_init(wl);
3497
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003498 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3499 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3500 if (!wl->aggr_buf) {
3501 ret = -ENOMEM;
3502 goto err_hw;
3503 }
3504
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003505 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003506 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003507 if (ret) {
3508 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003509 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003510 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003511 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003512
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003513 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003514 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003515 if (ret < 0) {
3516 wl1271_error("failed to create sysfs file bt_coex_state");
3517 goto err_platform;
3518 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003519
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003520 /* Create sysfs file to get HW PG version */
3521 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3522 if (ret < 0) {
3523 wl1271_error("failed to create sysfs file hw_pg_ver");
3524 goto err_bt_coex_state;
3525 }
3526
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003527 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003528
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003529err_bt_coex_state:
3530 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3531
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003532err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003533 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003534
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003535err_aggr:
3536 free_pages((unsigned long)wl->aggr_buf, order);
3537
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003538err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003539 wl1271_debugfs_exit(wl);
3540 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003541
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003542err_plat_alloc:
3543 ieee80211_free_hw(hw);
3544
3545err_hw_alloc:
3546
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003547 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003548}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003549EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003550
3551int wl1271_free_hw(struct wl1271 *wl)
3552{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003553 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003554 free_pages((unsigned long)wl->aggr_buf,
3555 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003556 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003557
3558 wl1271_debugfs_exit(wl);
3559
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003560 vfree(wl->fw);
3561 wl->fw = NULL;
3562 kfree(wl->nvs);
3563 wl->nvs = NULL;
3564
3565 kfree(wl->fw_status);
3566 kfree(wl->tx_res_if);
3567
3568 ieee80211_free_hw(wl->hw);
3569
3570 return 0;
3571}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003572EXPORT_SYMBOL_GPL(wl1271_free_hw);
3573
Guy Eilam491bbd62011-01-12 10:33:29 +01003574u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003575EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003576module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003577MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3578
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003579MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003580MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003581MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");