blob: 54ac6757c39ba105843bf6782ad399ad26f17a4f [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 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200301 .mem_wl127x = {
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,
Shahar Levi13b107d2011-03-06 16:32:12 +0200310 },
311 .mem_wl128x = {
312 .num_stations = 1,
313 .ssid_profiles = 1,
314 .rx_block_num = 40,
315 .tx_min_block_num = 40,
316 .dynamic_memory = 1,
317 .min_req_tx_blocks = 45,
318 .min_req_rx_blocks = 22,
319 .tx_min = 27,
320 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300321};
322
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200323static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200324static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200325
326
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200327static void wl1271_device_release(struct device *dev)
328{
329
330}
331
332static struct platform_device wl1271_device = {
333 .name = "wl1271",
334 .id = -1,
335
336 /* device model insists to have a release function */
337 .dev = {
338 .release = wl1271_device_release,
339 },
340};
341
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300342static LIST_HEAD(wl_list);
343
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300344static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
345 void *arg)
346{
347 struct net_device *dev = arg;
348 struct wireless_dev *wdev;
349 struct wiphy *wiphy;
350 struct ieee80211_hw *hw;
351 struct wl1271 *wl;
352 struct wl1271 *wl_temp;
353 int ret = 0;
354
355 /* Check that this notification is for us. */
356 if (what != NETDEV_CHANGE)
357 return NOTIFY_DONE;
358
359 wdev = dev->ieee80211_ptr;
360 if (wdev == NULL)
361 return NOTIFY_DONE;
362
363 wiphy = wdev->wiphy;
364 if (wiphy == NULL)
365 return NOTIFY_DONE;
366
367 hw = wiphy_priv(wiphy);
368 if (hw == NULL)
369 return NOTIFY_DONE;
370
371 wl_temp = hw->priv;
372 list_for_each_entry(wl, &wl_list, list) {
373 if (wl == wl_temp)
374 break;
375 }
376 if (wl != wl_temp)
377 return NOTIFY_DONE;
378
379 mutex_lock(&wl->mutex);
380
381 if (wl->state == WL1271_STATE_OFF)
382 goto out;
383
384 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
385 goto out;
386
Ido Yariva6208652011-03-01 15:14:41 +0200387 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300388 if (ret < 0)
389 goto out;
390
391 if ((dev->operstate == IF_OPER_UP) &&
392 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
393 wl1271_cmd_set_sta_state(wl);
394 wl1271_info("Association completed.");
395 }
396
397 wl1271_ps_elp_sleep(wl);
398
399out:
400 mutex_unlock(&wl->mutex);
401
402 return NOTIFY_OK;
403}
404
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100405static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200406 struct regulatory_request *request)
407{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100408 struct ieee80211_supported_band *band;
409 struct ieee80211_channel *ch;
410 int i;
411
412 band = wiphy->bands[IEEE80211_BAND_5GHZ];
413 for (i = 0; i < band->n_channels; i++) {
414 ch = &band->channels[i];
415 if (ch->flags & IEEE80211_CHAN_DISABLED)
416 continue;
417
418 if (ch->flags & IEEE80211_CHAN_RADAR)
419 ch->flags |= IEEE80211_CHAN_NO_IBSS |
420 IEEE80211_CHAN_PASSIVE_SCAN;
421
422 }
423
424 return 0;
425}
426
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300427static void wl1271_conf_init(struct wl1271 *wl)
428{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300429
430 /*
431 * This function applies the default configuration to the driver. This
432 * function is invoked upon driver load (spi probe.)
433 *
434 * The configuration is stored in a run-time structure in order to
435 * facilitate for run-time adjustment of any of the parameters. Making
436 * changes to the configuration structure will apply the new values on
437 * the next interface up (wl1271_op_start.)
438 */
439
440 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300441 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300442}
443
444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445static int wl1271_plt_init(struct wl1271 *wl)
446{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200447 struct conf_tx_ac_category *conf_ac;
448 struct conf_tx_tid *conf_tid;
449 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450
Shahar Levi49d750ca2011-03-06 16:32:09 +0200451 if (wl->chip.id == CHIP_ID_1283_PG20)
452 ret = wl128x_cmd_general_parms(wl);
453 else
454 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200455 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200456 return ret;
457
Shahar Levi49d750ca2011-03-06 16:32:09 +0200458 if (wl->chip.id == CHIP_ID_1283_PG20)
459 ret = wl128x_cmd_radio_parms(wl);
460 else
461 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200462 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200463 return ret;
464
Shahar Levi49d750ca2011-03-06 16:32:09 +0200465 if (wl->chip.id != CHIP_ID_1283_PG20) {
466 ret = wl1271_cmd_ext_radio_parms(wl);
467 if (ret < 0)
468 return ret;
469 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200470 if (ret < 0)
471 return ret;
472
Shahar Levi48a61472011-03-06 16:32:08 +0200473 /* Chip-specific initializations */
474 ret = wl1271_chip_specific_init(wl);
475 if (ret < 0)
476 return ret;
477
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200478 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200479 if (ret < 0)
480 return ret;
481
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300482 ret = wl1271_acx_init_mem_config(wl);
483 if (ret < 0)
484 return ret;
485
Luciano Coelho12419cc2010-02-18 13:25:44 +0200486 /* PHY layer config */
487 ret = wl1271_init_phy_config(wl);
488 if (ret < 0)
489 goto out_free_memmap;
490
491 ret = wl1271_acx_dco_itrim_params(wl);
492 if (ret < 0)
493 goto out_free_memmap;
494
495 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200496 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200497 if (ret < 0)
498 goto out_free_memmap;
499
500 /* Bluetooth WLAN coexistence */
501 ret = wl1271_init_pta(wl);
502 if (ret < 0)
503 goto out_free_memmap;
504
505 /* Energy detection */
506 ret = wl1271_init_energy_detection(wl);
507 if (ret < 0)
508 goto out_free_memmap;
509
Gery Kahn1ec610e2011-02-01 03:03:08 -0600510 ret = wl1271_acx_sta_mem_cfg(wl);
511 if (ret < 0)
512 goto out_free_memmap;
513
Luciano Coelho12419cc2010-02-18 13:25:44 +0200514 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100515 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200516 if (ret < 0)
517 goto out_free_memmap;
518
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200519 /* Default TID/AC configuration */
520 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200521 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200522 conf_ac = &wl->conf.tx.ac_conf[i];
523 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
524 conf_ac->cw_max, conf_ac->aifsn,
525 conf_ac->tx_op_limit);
526 if (ret < 0)
527 goto out_free_memmap;
528
Luciano Coelho12419cc2010-02-18 13:25:44 +0200529 conf_tid = &wl->conf.tx.tid_conf[i];
530 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
531 conf_tid->channel_type,
532 conf_tid->tsid,
533 conf_tid->ps_scheme,
534 conf_tid->ack_policy,
535 conf_tid->apsd_conf[0],
536 conf_tid->apsd_conf[1]);
537 if (ret < 0)
538 goto out_free_memmap;
539 }
540
Luciano Coelho12419cc2010-02-18 13:25:44 +0200541 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200542 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300543 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200544 goto out_free_memmap;
545
546 /* Configure for CAM power saving (ie. always active) */
547 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
548 if (ret < 0)
549 goto out_free_memmap;
550
551 /* configure PM */
552 ret = wl1271_acx_pm_config(wl);
553 if (ret < 0)
554 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200557
558 out_free_memmap:
559 kfree(wl->target_mem_map);
560 wl->target_mem_map = NULL;
561
562 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300563}
564
Arik Nemtsovb622d992011-02-23 00:22:31 +0200565static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
566{
567 bool fw_ps;
568
569 /* only regulate station links */
570 if (hlid < WL1271_AP_STA_HLID_START)
571 return;
572
573 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
574
575 /*
576 * Wake up from high level PS if the STA is asleep with too little
577 * blocks in FW or if the STA is awake.
578 */
579 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
580 wl1271_ps_link_end(wl, hlid);
581
582 /* Start high-level PS if the STA is asleep with enough blocks in FW */
583 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
584 wl1271_ps_link_start(wl, hlid, true);
585}
586
587static void wl1271_irq_update_links_status(struct wl1271 *wl,
588 struct wl1271_fw_ap_status *status)
589{
590 u32 cur_fw_ps_map;
591 u8 hlid;
592
593 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
594 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
595 wl1271_debug(DEBUG_PSM,
596 "link ps prev 0x%x cur 0x%x changed 0x%x",
597 wl->ap_fw_ps_map, cur_fw_ps_map,
598 wl->ap_fw_ps_map ^ cur_fw_ps_map);
599
600 wl->ap_fw_ps_map = cur_fw_ps_map;
601 }
602
603 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
604 u8 cnt = status->tx_lnk_free_blks[hlid] -
605 wl->links[hlid].prev_freed_blks;
606
607 wl->links[hlid].prev_freed_blks =
608 status->tx_lnk_free_blks[hlid];
609 wl->links[hlid].allocated_blks -= cnt;
610
611 wl1271_irq_ps_regulate_link(wl, hlid,
612 wl->links[hlid].allocated_blks);
613 }
614}
615
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300616static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200617 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200619 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200620 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200621 u32 old_tx_blk_count = wl->tx_blocks_available;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 u32 total = 0;
623 int i;
624
Shahar Levi13b107d2011-03-06 16:32:12 +0200625 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200626 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
627 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200628 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200629 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
630 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300631
Shahar Levi13b107d2011-03-06 16:32:12 +0200632 /* Update tx total blocks change */
633 wl->tx_total_diff +=
634 ((struct wl1271_fw_sta_status *)status)->tx_total -
635 wl->tx_new_total;
636
637 /* Update total tx blocks */
638 wl->tx_new_total =
639 ((struct wl1271_fw_sta_status *)status)->tx_total;
640 }
641
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
643 "drv_rx_counter = %d, tx_results_counter = %d)",
644 status->intr,
645 status->fw_rx_counter,
646 status->drv_rx_counter,
647 status->tx_results_counter);
648
649 /* update number of available TX blocks */
650 for (i = 0; i < NUM_TX_QUEUES; i++) {
Shahar Levi13b107d2011-03-06 16:32:12 +0200651 total += le32_to_cpu(status->tx_released_blks[i]) -
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300652 wl->tx_blocks_freed[i];
653
654 wl->tx_blocks_freed[i] =
655 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200656
657 }
658
659 /*
660 * By adding the freed blocks to tx_total_diff we are actually
661 * moving them to the RX pool.
662 */
663 wl->tx_total_diff += total;
664
665 /* if we have positive difference, add the blocks to the TX pool */
666 if (wl->tx_total_diff >= 0) {
667 wl->tx_blocks_available += wl->tx_total_diff;
668 wl->tx_total_diff = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 }
670
Ido Yariva5225502010-10-12 14:49:10 +0200671 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200672 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200673 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674
Arik Nemtsovb622d992011-02-23 00:22:31 +0200675 /* for AP update num of allocated TX blocks per link and ps status */
676 if (wl->bss_type == BSS_TYPE_AP_BSS)
677 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200680 getnstimeofday(&ts);
681 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
682 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683}
684
Ido Yariva6208652011-03-01 15:14:41 +0200685static void wl1271_flush_deferred_work(struct wl1271 *wl)
686{
687 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200688
Ido Yariva6208652011-03-01 15:14:41 +0200689 /* Pass all received frames to the network stack */
690 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
691 ieee80211_rx_ni(wl->hw, skb);
692
693 /* Return sent skbs to the network stack */
694 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
695 ieee80211_tx_status(wl->hw, skb);
696}
697
698static void wl1271_netstack_work(struct work_struct *work)
699{
700 struct wl1271 *wl =
701 container_of(work, struct wl1271, netstack_work);
702
703 do {
704 wl1271_flush_deferred_work(wl);
705 } while (skb_queue_len(&wl->deferred_rx_queue));
706}
707
708#define WL1271_IRQ_MAX_LOOPS 256
709
710irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300713 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200714 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200715 struct wl1271 *wl = (struct wl1271 *)cookie;
716 bool done = false;
717 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200718 unsigned long flags;
719
720 /* TX might be handled here, avoid redundant work */
721 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
722 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723
724 mutex_lock(&wl->mutex);
725
726 wl1271_debug(DEBUG_IRQ, "IRQ work");
727
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200728 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300729 goto out;
730
Ido Yariva6208652011-03-01 15:14:41 +0200731 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732 if (ret < 0)
733 goto out;
734
Ido Yariva6208652011-03-01 15:14:41 +0200735 while (!done && loopcount--) {
736 /*
737 * In order to avoid a race with the hardirq, clear the flag
738 * before acknowledging the chip. Since the mutex is held,
739 * wl1271_ps_elp_wakeup cannot be called concurrently.
740 */
741 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
742 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200743
744 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200745 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200746 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200747 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200748 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200749 continue;
750 }
751
Eliad Pellerccc83b02010-10-27 14:09:57 +0200752 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
753 wl1271_error("watchdog interrupt received! "
754 "starting recovery.");
755 ieee80211_queue_work(wl->hw, &wl->recovery_work);
756
757 /* restarting the chip. ignore any other interrupt. */
758 goto out;
759 }
760
Ido Yariva6208652011-03-01 15:14:41 +0200761 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200762 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
763
Ido Yariv8aad2462011-03-01 15:14:38 +0200764 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200765
Ido Yariva5225502010-10-12 14:49:10 +0200766 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200767 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200768 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200769 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200770 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200771 /*
772 * In order to avoid starvation of the TX path,
773 * call the work function directly.
774 */
775 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200776 } else {
777 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200778 }
779
Ido Yariv8aad2462011-03-01 15:14:38 +0200780 /* check for tx results */
781 if (wl->fw_status->common.tx_results_counter !=
782 (wl->tx_results_count & 0xff))
783 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200784
785 /* Make sure the deferred queues don't get too long */
786 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
787 skb_queue_len(&wl->deferred_rx_queue);
788 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
789 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200790 }
791
792 if (intr & WL1271_ACX_INTR_EVENT_A) {
793 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
794 wl1271_event_handle(wl, 0);
795 }
796
797 if (intr & WL1271_ACX_INTR_EVENT_B) {
798 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
799 wl1271_event_handle(wl, 1);
800 }
801
802 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
803 wl1271_debug(DEBUG_IRQ,
804 "WL1271_ACX_INTR_INIT_COMPLETE");
805
806 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
807 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 }
809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810 wl1271_ps_elp_sleep(wl);
811
812out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200813 spin_lock_irqsave(&wl->wl_lock, flags);
814 /* In case TX was not handled here, queue TX work */
815 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
816 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
817 wl->tx_queue_count)
818 ieee80211_queue_work(wl->hw, &wl->tx_work);
819 spin_unlock_irqrestore(&wl->wl_lock, flags);
820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200822
823 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824}
Ido Yariva6208652011-03-01 15:14:41 +0200825EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300827static int wl1271_fetch_firmware(struct wl1271 *wl)
828{
829 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200830 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831 int ret;
832
Arik Nemtsov166d5042010-10-16 21:44:57 +0200833 switch (wl->bss_type) {
834 case BSS_TYPE_AP_BSS:
835 fw_name = WL1271_AP_FW_NAME;
836 break;
837 case BSS_TYPE_IBSS:
838 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200839 if (wl->chip.id == CHIP_ID_1283_PG20)
840 fw_name = WL128X_FW_NAME;
841 else
842 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200843 break;
844 default:
845 wl1271_error("no compatible firmware for bss_type %d",
846 wl->bss_type);
847 return -EINVAL;
848 }
849
850 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
851
852 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853
854 if (ret < 0) {
855 wl1271_error("could not get firmware: %d", ret);
856 return ret;
857 }
858
859 if (fw->size % 4) {
860 wl1271_error("firmware size is not multiple of 32 bits: %zu",
861 fw->size);
862 ret = -EILSEQ;
863 goto out;
864 }
865
Arik Nemtsov166d5042010-10-16 21:44:57 +0200866 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300868 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869
870 if (!wl->fw) {
871 wl1271_error("could not allocate memory for the firmware");
872 ret = -ENOMEM;
873 goto out;
874 }
875
876 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200877 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 ret = 0;
879
880out:
881 release_firmware(fw);
882
883 return ret;
884}
885
886static int wl1271_fetch_nvs(struct wl1271 *wl)
887{
888 const struct firmware *fw;
889 int ret;
890
Shahar Levi5aa42342011-03-06 16:32:07 +0200891 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892
893 if (ret < 0) {
894 wl1271_error("could not get nvs file: %d", ret);
895 return ret;
896 }
897
Shahar Levibc765bf2011-03-06 16:32:10 +0200898 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
900 if (!wl->nvs) {
901 wl1271_error("could not allocate memory for the nvs file");
902 ret = -ENOMEM;
903 goto out;
904 }
905
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200906 wl->nvs_len = fw->size;
907
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908out:
909 release_firmware(fw);
910
911 return ret;
912}
913
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200914static void wl1271_recovery_work(struct work_struct *work)
915{
916 struct wl1271 *wl =
917 container_of(work, struct wl1271, recovery_work);
918
919 mutex_lock(&wl->mutex);
920
921 if (wl->state != WL1271_STATE_ON)
922 goto out;
923
924 wl1271_info("Hardware recovery in progress.");
925
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200926 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
927 ieee80211_connection_loss(wl->vif);
928
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200929 /* reboot the chipset */
930 __wl1271_op_remove_interface(wl);
931 ieee80211_restart_hw(wl->hw);
932
933out:
934 mutex_unlock(&wl->mutex);
935}
936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937static void wl1271_fw_wakeup(struct wl1271 *wl)
938{
939 u32 elp_reg;
940
941 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300942 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943}
944
945static int wl1271_setup(struct wl1271 *wl)
946{
947 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
948 if (!wl->fw_status)
949 return -ENOMEM;
950
951 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
952 if (!wl->tx_res_if) {
953 kfree(wl->fw_status);
954 return -ENOMEM;
955 }
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957 return 0;
958}
959
960static int wl1271_chip_wakeup(struct wl1271 *wl)
961{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300962 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 int ret = 0;
964
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200965 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200966 ret = wl1271_power_on(wl);
967 if (ret < 0)
968 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200970 wl1271_io_reset(wl);
971 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 /* We don't need a real memory partition here, because we only want
974 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300975 memset(&partition, 0, sizeof(partition));
976 partition.reg.start = REGISTERS_BASE;
977 partition.reg.size = REGISTERS_DOWN_SIZE;
978 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979
980 /* ELP module wake up */
981 wl1271_fw_wakeup(wl);
982
983 /* whal_FwCtrl_BootSm() */
984
985 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200986 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987
988 /* 1. check if chip id is valid */
989
990 switch (wl->chip.id) {
991 case CHIP_ID_1271_PG10:
992 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
993 wl->chip.id);
994
995 ret = wl1271_setup(wl);
996 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 break;
999 case CHIP_ID_1271_PG20:
1000 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1001 wl->chip.id);
1002
1003 ret = wl1271_setup(wl);
1004 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001005 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 break;
1007 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001010 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 }
1012
Arik Nemtsov166d5042010-10-16 21:44:57 +02001013 /* Make sure the firmware type matches the BSS type */
1014 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015 ret = wl1271_fetch_firmware(wl);
1016 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001017 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 }
1019
1020 /* No NVS from netlink, try to get it from the filesystem */
1021 if (wl->nvs == NULL) {
1022 ret = wl1271_fetch_nvs(wl);
1023 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001024 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 }
1026
1027out:
1028 return ret;
1029}
1030
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031int wl1271_plt_start(struct wl1271 *wl)
1032{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001033 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 int ret;
1035
1036 mutex_lock(&wl->mutex);
1037
1038 wl1271_notice("power up");
1039
1040 if (wl->state != WL1271_STATE_OFF) {
1041 wl1271_error("cannot go into PLT state because not "
1042 "in off state: %d", wl->state);
1043 ret = -EBUSY;
1044 goto out;
1045 }
1046
Arik Nemtsov166d5042010-10-16 21:44:57 +02001047 wl->bss_type = BSS_TYPE_STA_BSS;
1048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001049 while (retries) {
1050 retries--;
1051 ret = wl1271_chip_wakeup(wl);
1052 if (ret < 0)
1053 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001055 ret = wl1271_boot(wl);
1056 if (ret < 0)
1057 goto power_off;
1058
1059 ret = wl1271_plt_init(wl);
1060 if (ret < 0)
1061 goto irq_disable;
1062
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001063 wl->state = WL1271_STATE_PLT;
1064 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001065 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 goto out;
1067
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001068irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001069 mutex_unlock(&wl->mutex);
1070 /* Unlocking the mutex in the middle of handling is
1071 inherently unsafe. In this case we deem it safe to do,
1072 because we need to let any possibly pending IRQ out of
1073 the system (and while we are WL1271_STATE_OFF the IRQ
1074 work function will not do anything.) Also, any other
1075 possible concurrent operations will fail due to the
1076 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001077 wl1271_disable_interrupts(wl);
1078 wl1271_flush_deferred_work(wl);
1079 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001080 mutex_lock(&wl->mutex);
1081power_off:
1082 wl1271_power_off(wl);
1083 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001085 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1086 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087out:
1088 mutex_unlock(&wl->mutex);
1089
1090 return ret;
1091}
1092
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001093int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094{
1095 int ret = 0;
1096
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 wl1271_notice("power down");
1098
1099 if (wl->state != WL1271_STATE_PLT) {
1100 wl1271_error("cannot power down because not in PLT "
1101 "state: %d", wl->state);
1102 ret = -EBUSY;
1103 goto out;
1104 }
1105
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 wl1271_power_off(wl);
1107
1108 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001109 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001112 wl1271_disable_interrupts(wl);
1113 wl1271_flush_deferred_work(wl);
1114 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001115 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001116 mutex_lock(&wl->mutex);
1117out:
1118 return ret;
1119}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001120
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001121int wl1271_plt_stop(struct wl1271 *wl)
1122{
1123 int ret;
1124
1125 mutex_lock(&wl->mutex);
1126 ret = __wl1271_plt_stop(wl);
1127 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128 return ret;
1129}
1130
Johannes Berg7bb45682011-02-24 14:42:06 +01001131static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132{
1133 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001134 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001135 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001136 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
Ido Yarivb07d4032011-03-01 15:14:43 +02001138 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1139
1140 if (wl->bss_type == BSS_TYPE_AP_BSS)
1141 hlid = wl1271_tx_get_hlid(skb);
1142
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001143 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001144
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001145 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001146
1147 /*
1148 * The workqueue is slow to process the tx_queue and we need stop
1149 * the queue here, otherwise the queue will get too long.
1150 */
1151 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1152 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1153 ieee80211_stop_queues(wl->hw);
1154 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1155 }
1156
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001157 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001158 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001159 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1160 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1161 } else {
1162 skb_queue_tail(&wl->tx_queue[q], skb);
1163 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164
1165 /*
1166 * The chip specific setup must run before the first TX packet -
1167 * before that, the tx_work will not be initialized!
1168 */
1169
Ido Yarivb07d4032011-03-01 15:14:43 +02001170 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1171 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001172 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001173
1174 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175}
1176
Shahar Leviae47c452011-03-06 16:32:14 +02001177#define TX_DUMMY_PACKET_SIZE 1400
1178int wl1271_tx_dummy_packet(struct wl1271 *wl)
1179{
1180 struct sk_buff *skb = NULL;
1181 struct ieee80211_hdr_3addr *hdr;
1182 int ret = 0;
1183
1184 skb = dev_alloc_skb(
1185 sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
1186 TX_DUMMY_PACKET_SIZE);
1187 if (!skb) {
1188 wl1271_warning("failed to allocate buffer for dummy packet");
1189 ret = -ENOMEM;
1190 goto out;
1191 }
1192
1193 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1194
1195 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1196 memset(hdr, 0, sizeof(*hdr));
1197 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1198 IEEE80211_FCTL_TODS |
1199 IEEE80211_STYPE_NULLFUNC);
1200
1201 memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
1202 memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
1203 memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
1204
1205 skb_put(skb, TX_DUMMY_PACKET_SIZE);
1206
1207 memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
1208
1209 skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
1210 /* CONF_TX_AC_VO */
1211 skb->queue_mapping = 0;
1212
1213 wl1271_op_tx(wl->hw, skb);
1214
1215out:
1216 return ret;
1217}
1218
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001219static struct notifier_block wl1271_dev_notifier = {
1220 .notifier_call = wl1271_dev_notify,
1221};
1222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223static int wl1271_op_start(struct ieee80211_hw *hw)
1224{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001225 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1226
1227 /*
1228 * We have to delay the booting of the hardware because
1229 * we need to know the local MAC address before downloading and
1230 * initializing the firmware. The MAC address cannot be changed
1231 * after boot, and without the proper MAC address, the firmware
1232 * will not function properly.
1233 *
1234 * The MAC address is first known when the corresponding interface
1235 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001236 *
1237 * In addition, we currently have different firmwares for AP and managed
1238 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001239 */
1240
1241 return 0;
1242}
1243
1244static void wl1271_op_stop(struct ieee80211_hw *hw)
1245{
1246 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1247}
1248
1249static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1250 struct ieee80211_vif *vif)
1251{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001253 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001254 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001256 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001258 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1259 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260
1261 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001262 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001263 wl1271_debug(DEBUG_MAC80211,
1264 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001265 ret = -EBUSY;
1266 goto out;
1267 }
1268
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001269 switch (vif->type) {
1270 case NL80211_IFTYPE_STATION:
1271 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001272 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001273 break;
1274 case NL80211_IFTYPE_ADHOC:
1275 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001276 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001277 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001278 case NL80211_IFTYPE_AP:
1279 wl->bss_type = BSS_TYPE_AP_BSS;
1280 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001281 default:
1282 ret = -EOPNOTSUPP;
1283 goto out;
1284 }
1285
1286 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287
1288 if (wl->state != WL1271_STATE_OFF) {
1289 wl1271_error("cannot start because not in off state: %d",
1290 wl->state);
1291 ret = -EBUSY;
1292 goto out;
1293 }
1294
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001295 while (retries) {
1296 retries--;
1297 ret = wl1271_chip_wakeup(wl);
1298 if (ret < 0)
1299 goto power_off;
1300
1301 ret = wl1271_boot(wl);
1302 if (ret < 0)
1303 goto power_off;
1304
1305 ret = wl1271_hw_init(wl);
1306 if (ret < 0)
1307 goto irq_disable;
1308
Eliad Peller71125ab2010-10-28 21:46:43 +02001309 booted = true;
1310 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001312irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 mutex_unlock(&wl->mutex);
1314 /* Unlocking the mutex in the middle of handling is
1315 inherently unsafe. In this case we deem it safe to do,
1316 because we need to let any possibly pending IRQ out of
1317 the system (and while we are WL1271_STATE_OFF the IRQ
1318 work function will not do anything.) Also, any other
1319 possible concurrent operations will fail due to the
1320 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001321 wl1271_disable_interrupts(wl);
1322 wl1271_flush_deferred_work(wl);
1323 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001324 mutex_lock(&wl->mutex);
1325power_off:
1326 wl1271_power_off(wl);
1327 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
Eliad Peller71125ab2010-10-28 21:46:43 +02001329 if (!booted) {
1330 wl1271_error("firmware boot failed despite %d retries",
1331 WL1271_BOOT_RETRIES);
1332 goto out;
1333 }
1334
1335 wl->vif = vif;
1336 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001337 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001338
1339 /* update hw/fw version info in wiphy struct */
1340 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001341 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001342 sizeof(wiphy->fw_version));
1343
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001344 /*
1345 * Now we know if 11a is supported (info from the NVS), so disable
1346 * 11a channels if not supported
1347 */
1348 if (!wl->enable_11a)
1349 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1350
1351 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1352 wl->enable_11a ? "" : "not ");
1353
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001354out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 mutex_unlock(&wl->mutex);
1356
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001357 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001358 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 return ret;
1361}
1362
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001363static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 int i;
1366
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001367 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001369 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001371 list_del(&wl->list);
1372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 WARN_ON(wl->state != WL1271_STATE_ON);
1374
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001375 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001376 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001377 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001378
Luciano Coelho08688d62010-07-08 17:50:07 +03001379 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001380 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1381 kfree(wl->scan.scanned_ch);
1382 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001383 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001384 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385 }
1386
1387 wl->state = WL1271_STATE_OFF;
1388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389 mutex_unlock(&wl->mutex);
1390
Ido Yariva6208652011-03-01 15:14:41 +02001391 wl1271_disable_interrupts(wl);
1392 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001393 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001394 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001396 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001397 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398
1399 mutex_lock(&wl->mutex);
1400
1401 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001402 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403 wl1271_power_off(wl);
1404
1405 memset(wl->bssid, 0, ETH_ALEN);
1406 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1407 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001409 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001410 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
1412 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001413 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1415 wl->tx_blocks_available = 0;
1416 wl->tx_results_count = 0;
1417 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001418 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001419 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 wl->time_offset = 0;
1421 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001422 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001423 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001424 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001425 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001426 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001427 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001428 wl->ap_fw_ps_map = 0;
1429 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001430 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001431
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 for (i = 0; i < NUM_TX_QUEUES; i++)
1433 wl->tx_blocks_freed[i] = 0;
1434
1435 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001436
1437 kfree(wl->fw_status);
1438 wl->fw_status = NULL;
1439 kfree(wl->tx_res_if);
1440 wl->tx_res_if = NULL;
1441 kfree(wl->target_mem_map);
1442 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001443}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001444
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001445static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1446 struct ieee80211_vif *vif)
1447{
1448 struct wl1271 *wl = hw->priv;
1449
1450 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001451 /*
1452 * wl->vif can be null here if someone shuts down the interface
1453 * just when hardware recovery has been started.
1454 */
1455 if (wl->vif) {
1456 WARN_ON(wl->vif != vif);
1457 __wl1271_op_remove_interface(wl);
1458 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001459
Juuso Oikarinen67353292010-11-18 15:19:02 +02001460 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001461 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462}
1463
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001464static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1465{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001466 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001467
1468 /* combine requested filters with current filter config */
1469 filters = wl->filters | filters;
1470
1471 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1472
1473 if (filters & FIF_PROMISC_IN_BSS) {
1474 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1475 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1476 wl->rx_config |= CFG_BSSID_FILTER_EN;
1477 }
1478 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1479 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1480 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1481 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1482 }
1483 if (filters & FIF_OTHER_BSS) {
1484 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1485 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1486 }
1487 if (filters & FIF_CONTROL) {
1488 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1489 wl->rx_filter |= CFG_RX_CTL_EN;
1490 }
1491 if (filters & FIF_FCSFAIL) {
1492 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1493 wl->rx_filter |= CFG_RX_FCS_ERROR;
1494 }
1495}
1496
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001497static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001498{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001499 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001500 /* we need to use a dummy BSSID for now */
1501 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1502 0xad, 0xbe, 0xef };
1503
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001504 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1505
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001506 /* pass through frames from all BSS */
1507 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1508
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001509 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001510 if (ret < 0)
1511 goto out;
1512
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001513 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001514
1515out:
1516 return ret;
1517}
1518
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001519static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001520{
1521 int ret;
1522
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001523 /*
1524 * One of the side effects of the JOIN command is that is clears
1525 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1526 * to a WPA/WPA2 access point will therefore kill the data-path.
1527 * Currently there is no supported scenario for JOIN during
1528 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1529 * must be handled somehow.
1530 *
1531 */
1532 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1533 wl1271_info("JOIN while associated.");
1534
1535 if (set_assoc)
1536 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1537
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001538 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1539 if (ret < 0)
1540 goto out;
1541
1542 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1543
1544 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1545 goto out;
1546
1547 /*
1548 * The join command disable the keep-alive mode, shut down its process,
1549 * and also clear the template config, so we need to reset it all after
1550 * the join. The acx_aid starts the keep-alive process, and the order
1551 * of the commands below is relevant.
1552 */
1553 ret = wl1271_acx_keep_alive_mode(wl, true);
1554 if (ret < 0)
1555 goto out;
1556
1557 ret = wl1271_acx_aid(wl, wl->aid);
1558 if (ret < 0)
1559 goto out;
1560
1561 ret = wl1271_cmd_build_klv_null_data(wl);
1562 if (ret < 0)
1563 goto out;
1564
1565 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1566 ACX_KEEP_ALIVE_TPL_VALID);
1567 if (ret < 0)
1568 goto out;
1569
1570out:
1571 return ret;
1572}
1573
1574static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001575{
1576 int ret;
1577
1578 /* to stop listening to a channel, we disconnect */
1579 ret = wl1271_cmd_disconnect(wl);
1580 if (ret < 0)
1581 goto out;
1582
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001583 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001584 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001585
1586 /* stop filterting packets based on bssid */
1587 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001588
1589out:
1590 return ret;
1591}
1592
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001593static void wl1271_set_band_rate(struct wl1271 *wl)
1594{
1595 if (wl->band == IEEE80211_BAND_2GHZ)
1596 wl->basic_rate_set = wl->conf.tx.basic_rate;
1597 else
1598 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1599}
1600
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001601static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001602{
1603 int ret;
1604
1605 if (idle) {
1606 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1607 ret = wl1271_unjoin(wl);
1608 if (ret < 0)
1609 goto out;
1610 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001611 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001612 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001613 if (ret < 0)
1614 goto out;
1615 ret = wl1271_acx_keep_alive_config(
1616 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1617 ACX_KEEP_ALIVE_TPL_INVALID);
1618 if (ret < 0)
1619 goto out;
1620 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1621 } else {
1622 /* increment the session counter */
1623 wl->session_counter++;
1624 if (wl->session_counter >= SESSION_COUNTER_MAX)
1625 wl->session_counter = 0;
1626 ret = wl1271_dummy_join(wl);
1627 if (ret < 0)
1628 goto out;
1629 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1630 }
1631
1632out:
1633 return ret;
1634}
1635
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001636static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1637{
1638 struct wl1271 *wl = hw->priv;
1639 struct ieee80211_conf *conf = &hw->conf;
1640 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001641 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642
1643 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1644
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001645 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1646 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647 channel,
1648 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001649 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001650 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1651 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001652
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001653 /*
1654 * mac80211 will go to idle nearly immediately after transmitting some
1655 * frames, such as the deauth. To make sure those frames reach the air,
1656 * wait here until the TX queue is fully flushed.
1657 */
1658 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1659 (conf->flags & IEEE80211_CONF_IDLE))
1660 wl1271_tx_flush(wl);
1661
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 mutex_lock(&wl->mutex);
1663
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001664 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1665 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001666 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001667 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001668
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001669 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1670
Ido Yariva6208652011-03-01 15:14:41 +02001671 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672 if (ret < 0)
1673 goto out;
1674
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001675 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001676 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1677 ((wl->band != conf->channel->band) ||
1678 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001679 wl->band = conf->channel->band;
1680 wl->channel = channel;
1681
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001682 if (!is_ap) {
1683 /*
1684 * FIXME: the mac80211 should really provide a fixed
1685 * rate to use here. for now, just use the smallest
1686 * possible rate for the band as a fixed rate for
1687 * association frames and other control messages.
1688 */
1689 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1690 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001691
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001692 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1693 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001694 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001695 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001696 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001697
1698 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1699 ret = wl1271_join(wl, false);
1700 if (ret < 0)
1701 wl1271_warning("cmd join on channel "
1702 "failed %d", ret);
1703 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001704 }
1705 }
1706
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001707 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1708 ret = wl1271_sta_handle_idle(wl,
1709 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001710 if (ret < 0)
1711 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 }
1713
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001714 /*
1715 * if mac80211 changes the PSM mode, make sure the mode is not
1716 * incorrectly changed after the pspoll failure active window.
1717 */
1718 if (changed & IEEE80211_CONF_CHANGE_PS)
1719 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1720
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001721 if (conf->flags & IEEE80211_CONF_PS &&
1722 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1723 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724
1725 /*
1726 * We enter PSM only if we're already associated.
1727 * If we're not, we'll enter it when joining an SSID,
1728 * through the bss_info_changed() hook.
1729 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001730 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001731 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001732 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001733 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001734 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001735 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001736 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001737 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001738
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001739 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001740
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001741 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001742 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001743 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001744 }
1745
1746 if (conf->power_level != wl->power_level) {
1747 ret = wl1271_acx_tx_power(wl, conf->power_level);
1748 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001749 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750
1751 wl->power_level = conf->power_level;
1752 }
1753
1754out_sleep:
1755 wl1271_ps_elp_sleep(wl);
1756
1757out:
1758 mutex_unlock(&wl->mutex);
1759
1760 return ret;
1761}
1762
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001763struct wl1271_filter_params {
1764 bool enabled;
1765 int mc_list_length;
1766 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1767};
1768
Jiri Pirko22bedad2010-04-01 21:22:57 +00001769static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1770 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001771{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001772 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001773 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001774 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001775
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001776 if (unlikely(wl->state == WL1271_STATE_OFF))
1777 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001778
Juuso Oikarinen74441132009-10-13 12:47:53 +03001779 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001780 if (!fp) {
1781 wl1271_error("Out of memory setting filters.");
1782 return 0;
1783 }
1784
1785 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001786 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001787 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1788 fp->enabled = false;
1789 } else {
1790 fp->enabled = true;
1791 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001792 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001793 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001794 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001795 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001796 }
1797
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001798 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001799}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001801#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1802 FIF_ALLMULTI | \
1803 FIF_FCSFAIL | \
1804 FIF_BCN_PRBRESP_PROMISC | \
1805 FIF_CONTROL | \
1806 FIF_OTHER_BSS)
1807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1809 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001810 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001812 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001814 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815
Arik Nemtsov7d057862010-10-16 19:25:35 +02001816 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1817 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001819 mutex_lock(&wl->mutex);
1820
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001821 *total &= WL1271_SUPPORTED_FILTERS;
1822 changed &= WL1271_SUPPORTED_FILTERS;
1823
1824 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001825 goto out;
1826
Ido Yariva6208652011-03-01 15:14:41 +02001827 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001828 if (ret < 0)
1829 goto out;
1830
Arik Nemtsov7d057862010-10-16 19:25:35 +02001831 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1832 if (*total & FIF_ALLMULTI)
1833 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1834 else if (fp)
1835 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1836 fp->mc_list,
1837 fp->mc_list_length);
1838 if (ret < 0)
1839 goto out_sleep;
1840 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001842 /* determine, whether supported filter values have changed */
1843 if (changed == 0)
1844 goto out_sleep;
1845
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001846 /* configure filters */
1847 wl->filters = *total;
1848 wl1271_configure_filters(wl, 0);
1849
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001850 /* apply configured filters */
1851 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1852 if (ret < 0)
1853 goto out_sleep;
1854
1855out_sleep:
1856 wl1271_ps_elp_sleep(wl);
1857
1858out:
1859 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001860 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861}
1862
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001863static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1864 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1865 u16 tx_seq_16)
1866{
1867 struct wl1271_ap_key *ap_key;
1868 int i;
1869
1870 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1871
1872 if (key_size > MAX_KEY_SIZE)
1873 return -EINVAL;
1874
1875 /*
1876 * Find next free entry in ap_keys. Also check we are not replacing
1877 * an existing key.
1878 */
1879 for (i = 0; i < MAX_NUM_KEYS; i++) {
1880 if (wl->recorded_ap_keys[i] == NULL)
1881 break;
1882
1883 if (wl->recorded_ap_keys[i]->id == id) {
1884 wl1271_warning("trying to record key replacement");
1885 return -EINVAL;
1886 }
1887 }
1888
1889 if (i == MAX_NUM_KEYS)
1890 return -EBUSY;
1891
1892 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1893 if (!ap_key)
1894 return -ENOMEM;
1895
1896 ap_key->id = id;
1897 ap_key->key_type = key_type;
1898 ap_key->key_size = key_size;
1899 memcpy(ap_key->key, key, key_size);
1900 ap_key->hlid = hlid;
1901 ap_key->tx_seq_32 = tx_seq_32;
1902 ap_key->tx_seq_16 = tx_seq_16;
1903
1904 wl->recorded_ap_keys[i] = ap_key;
1905 return 0;
1906}
1907
1908static void wl1271_free_ap_keys(struct wl1271 *wl)
1909{
1910 int i;
1911
1912 for (i = 0; i < MAX_NUM_KEYS; i++) {
1913 kfree(wl->recorded_ap_keys[i]);
1914 wl->recorded_ap_keys[i] = NULL;
1915 }
1916}
1917
1918static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1919{
1920 int i, ret = 0;
1921 struct wl1271_ap_key *key;
1922 bool wep_key_added = false;
1923
1924 for (i = 0; i < MAX_NUM_KEYS; i++) {
1925 if (wl->recorded_ap_keys[i] == NULL)
1926 break;
1927
1928 key = wl->recorded_ap_keys[i];
1929 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1930 key->id, key->key_type,
1931 key->key_size, key->key,
1932 key->hlid, key->tx_seq_32,
1933 key->tx_seq_16);
1934 if (ret < 0)
1935 goto out;
1936
1937 if (key->key_type == KEY_WEP)
1938 wep_key_added = true;
1939 }
1940
1941 if (wep_key_added) {
1942 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1943 if (ret < 0)
1944 goto out;
1945 }
1946
1947out:
1948 wl1271_free_ap_keys(wl);
1949 return ret;
1950}
1951
1952static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1953 u8 key_size, const u8 *key, u32 tx_seq_32,
1954 u16 tx_seq_16, struct ieee80211_sta *sta)
1955{
1956 int ret;
1957 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1958
1959 if (is_ap) {
1960 struct wl1271_station *wl_sta;
1961 u8 hlid;
1962
1963 if (sta) {
1964 wl_sta = (struct wl1271_station *)sta->drv_priv;
1965 hlid = wl_sta->hlid;
1966 } else {
1967 hlid = WL1271_AP_BROADCAST_HLID;
1968 }
1969
1970 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1971 /*
1972 * We do not support removing keys after AP shutdown.
1973 * Pretend we do to make mac80211 happy.
1974 */
1975 if (action != KEY_ADD_OR_REPLACE)
1976 return 0;
1977
1978 ret = wl1271_record_ap_key(wl, id,
1979 key_type, key_size,
1980 key, hlid, tx_seq_32,
1981 tx_seq_16);
1982 } else {
1983 ret = wl1271_cmd_set_ap_key(wl, action,
1984 id, key_type, key_size,
1985 key, hlid, tx_seq_32,
1986 tx_seq_16);
1987 }
1988
1989 if (ret < 0)
1990 return ret;
1991 } else {
1992 const u8 *addr;
1993 static const u8 bcast_addr[ETH_ALEN] = {
1994 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1995 };
1996
1997 addr = sta ? sta->addr : bcast_addr;
1998
1999 if (is_zero_ether_addr(addr)) {
2000 /* We dont support TX only encryption */
2001 return -EOPNOTSUPP;
2002 }
2003
2004 /* The wl1271 does not allow to remove unicast keys - they
2005 will be cleared automatically on next CMD_JOIN. Ignore the
2006 request silently, as we dont want the mac80211 to emit
2007 an error message. */
2008 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2009 return 0;
2010
2011 ret = wl1271_cmd_set_sta_key(wl, action,
2012 id, key_type, key_size,
2013 key, addr, tx_seq_32,
2014 tx_seq_16);
2015 if (ret < 0)
2016 return ret;
2017
2018 /* the default WEP key needs to be configured at least once */
2019 if (key_type == KEY_WEP) {
2020 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2021 wl->default_key);
2022 if (ret < 0)
2023 return ret;
2024 }
2025 }
2026
2027 return 0;
2028}
2029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002030static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2031 struct ieee80211_vif *vif,
2032 struct ieee80211_sta *sta,
2033 struct ieee80211_key_conf *key_conf)
2034{
2035 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002037 u32 tx_seq_32 = 0;
2038 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039 u8 key_type;
2040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2042
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002043 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002045 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 key_conf->keylen, key_conf->flags);
2047 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2048
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 mutex_lock(&wl->mutex);
2050
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002051 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2052 ret = -EAGAIN;
2053 goto out_unlock;
2054 }
2055
Ido Yariva6208652011-03-01 15:14:41 +02002056 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057 if (ret < 0)
2058 goto out_unlock;
2059
Johannes Berg97359d12010-08-10 09:46:38 +02002060 switch (key_conf->cipher) {
2061 case WLAN_CIPHER_SUITE_WEP40:
2062 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 key_type = KEY_WEP;
2064
2065 key_conf->hw_key_idx = key_conf->keyidx;
2066 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002067 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068 key_type = KEY_TKIP;
2069
2070 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002071 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2072 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002074 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075 key_type = KEY_AES;
2076
2077 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002078 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2079 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002081 case WL1271_CIPHER_SUITE_GEM:
2082 key_type = KEY_GEM;
2083 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2084 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2085 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002087 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002088
2089 ret = -EOPNOTSUPP;
2090 goto out_sleep;
2091 }
2092
2093 switch (cmd) {
2094 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002095 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2096 key_conf->keyidx, key_type,
2097 key_conf->keylen, key_conf->key,
2098 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099 if (ret < 0) {
2100 wl1271_error("Could not add or replace key");
2101 goto out_sleep;
2102 }
2103 break;
2104
2105 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002106 ret = wl1271_set_key(wl, KEY_REMOVE,
2107 key_conf->keyidx, key_type,
2108 key_conf->keylen, key_conf->key,
2109 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002110 if (ret < 0) {
2111 wl1271_error("Could not remove key");
2112 goto out_sleep;
2113 }
2114 break;
2115
2116 default:
2117 wl1271_error("Unsupported key cmd 0x%x", cmd);
2118 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119 break;
2120 }
2121
2122out_sleep:
2123 wl1271_ps_elp_sleep(wl);
2124
2125out_unlock:
2126 mutex_unlock(&wl->mutex);
2127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128 return ret;
2129}
2130
2131static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002132 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133 struct cfg80211_scan_request *req)
2134{
2135 struct wl1271 *wl = hw->priv;
2136 int ret;
2137 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002138 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002139
2140 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2141
2142 if (req->n_ssids) {
2143 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002144 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 }
2146
2147 mutex_lock(&wl->mutex);
2148
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002149 if (wl->state == WL1271_STATE_OFF) {
2150 /*
2151 * We cannot return -EBUSY here because cfg80211 will expect
2152 * a call to ieee80211_scan_completed if we do - in this case
2153 * there won't be any call.
2154 */
2155 ret = -EAGAIN;
2156 goto out;
2157 }
2158
Ido Yariva6208652011-03-01 15:14:41 +02002159 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 if (ret < 0)
2161 goto out;
2162
Luciano Coelho5924f892010-08-04 03:46:22 +03002163 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164
2165 wl1271_ps_elp_sleep(wl);
2166
2167out:
2168 mutex_unlock(&wl->mutex);
2169
2170 return ret;
2171}
2172
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002173static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2174{
2175 struct wl1271 *wl = hw->priv;
2176 int ret = 0;
2177
2178 mutex_lock(&wl->mutex);
2179
2180 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2181 ret = -EAGAIN;
2182 goto out;
2183 }
2184
Ido Yariva6208652011-03-01 15:14:41 +02002185 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002186 if (ret < 0)
2187 goto out;
2188
2189 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2190 if (ret < 0)
2191 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2192
2193 wl1271_ps_elp_sleep(wl);
2194
2195out:
2196 mutex_unlock(&wl->mutex);
2197
2198 return ret;
2199}
2200
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2202{
2203 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002204 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205
2206 mutex_lock(&wl->mutex);
2207
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002208 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2209 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002210 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002211 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002212
Ido Yariva6208652011-03-01 15:14:41 +02002213 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214 if (ret < 0)
2215 goto out;
2216
2217 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2218 if (ret < 0)
2219 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2220
2221 wl1271_ps_elp_sleep(wl);
2222
2223out:
2224 mutex_unlock(&wl->mutex);
2225
2226 return ret;
2227}
2228
Arik Nemtsove78a2872010-10-16 19:07:21 +02002229static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002230 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002231{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002232 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002233
2234 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002235 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002236 if (ptr[0] == WLAN_EID_SSID) {
2237 wl->ssid_len = ptr[1];
2238 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002239 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002240 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002241 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002242 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002243
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002244 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002245 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002246}
2247
Arik Nemtsove78a2872010-10-16 19:07:21 +02002248static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2249 struct ieee80211_bss_conf *bss_conf,
2250 u32 changed)
2251{
2252 int ret = 0;
2253
2254 if (changed & BSS_CHANGED_ERP_SLOT) {
2255 if (bss_conf->use_short_slot)
2256 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2257 else
2258 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2259 if (ret < 0) {
2260 wl1271_warning("Set slot time failed %d", ret);
2261 goto out;
2262 }
2263 }
2264
2265 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2266 if (bss_conf->use_short_preamble)
2267 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2268 else
2269 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2270 }
2271
2272 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2273 if (bss_conf->use_cts_prot)
2274 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2275 else
2276 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2277 if (ret < 0) {
2278 wl1271_warning("Set ctsprotect failed %d", ret);
2279 goto out;
2280 }
2281 }
2282
2283out:
2284 return ret;
2285}
2286
2287static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2288 struct ieee80211_vif *vif,
2289 struct ieee80211_bss_conf *bss_conf,
2290 u32 changed)
2291{
2292 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2293 int ret = 0;
2294
2295 if ((changed & BSS_CHANGED_BEACON_INT)) {
2296 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2297 bss_conf->beacon_int);
2298
2299 wl->beacon_int = bss_conf->beacon_int;
2300 }
2301
2302 if ((changed & BSS_CHANGED_BEACON)) {
2303 struct ieee80211_hdr *hdr;
2304 int ieoffset = offsetof(struct ieee80211_mgmt,
2305 u.beacon.variable);
2306 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2307 u16 tmpl_id;
2308
2309 if (!beacon)
2310 goto out;
2311
2312 wl1271_debug(DEBUG_MASTER, "beacon updated");
2313
2314 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2315 if (ret < 0) {
2316 dev_kfree_skb(beacon);
2317 goto out;
2318 }
2319 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2320 CMD_TEMPL_BEACON;
2321 ret = wl1271_cmd_template_set(wl, tmpl_id,
2322 beacon->data,
2323 beacon->len, 0,
2324 wl1271_tx_min_rate_get(wl));
2325 if (ret < 0) {
2326 dev_kfree_skb(beacon);
2327 goto out;
2328 }
2329
2330 hdr = (struct ieee80211_hdr *) beacon->data;
2331 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2332 IEEE80211_STYPE_PROBE_RESP);
2333
2334 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2335 CMD_TEMPL_PROBE_RESPONSE;
2336 ret = wl1271_cmd_template_set(wl,
2337 tmpl_id,
2338 beacon->data,
2339 beacon->len, 0,
2340 wl1271_tx_min_rate_get(wl));
2341 dev_kfree_skb(beacon);
2342 if (ret < 0)
2343 goto out;
2344 }
2345
2346out:
2347 return ret;
2348}
2349
2350/* AP mode changes */
2351static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 struct ieee80211_vif *vif,
2353 struct ieee80211_bss_conf *bss_conf,
2354 u32 changed)
2355{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002356 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002357
Arik Nemtsove78a2872010-10-16 19:07:21 +02002358 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2359 u32 rates = bss_conf->basic_rates;
2360 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361
Arik Nemtsove78a2872010-10-16 19:07:21 +02002362 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2363 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2364 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2365 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366
Arik Nemtsove78a2872010-10-16 19:07:21 +02002367 /* update the AP management rate policy with the new rates */
2368 mgmt_rc.enabled_rates = wl->basic_rate_set;
2369 mgmt_rc.long_retry_limit = 10;
2370 mgmt_rc.short_retry_limit = 10;
2371 mgmt_rc.aflags = 0;
2372 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2373 ACX_TX_AP_MODE_MGMT_RATE);
2374 if (ret < 0) {
2375 wl1271_error("AP mgmt policy change failed %d", ret);
2376 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002377 }
2378 }
2379
Arik Nemtsove78a2872010-10-16 19:07:21 +02002380 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2381 if (ret < 0)
2382 goto out;
2383
2384 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2385 if (bss_conf->enable_beacon) {
2386 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2387 ret = wl1271_cmd_start_bss(wl);
2388 if (ret < 0)
2389 goto out;
2390
2391 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2392 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002393
2394 ret = wl1271_ap_init_hwenc(wl);
2395 if (ret < 0)
2396 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002397 }
2398 } else {
2399 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2400 ret = wl1271_cmd_stop_bss(wl);
2401 if (ret < 0)
2402 goto out;
2403
2404 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2405 wl1271_debug(DEBUG_AP, "stopped AP");
2406 }
2407 }
2408 }
2409
2410 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2411 if (ret < 0)
2412 goto out;
2413out:
2414 return;
2415}
2416
2417/* STA/IBSS mode changes */
2418static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2419 struct ieee80211_vif *vif,
2420 struct ieee80211_bss_conf *bss_conf,
2421 u32 changed)
2422{
2423 bool do_join = false, set_assoc = false;
2424 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002425 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002426 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002427 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002428 bool sta_exists = false;
2429 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002430
2431 if (is_ibss) {
2432 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2433 changed);
2434 if (ret < 0)
2435 goto out;
2436 }
2437
2438 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2439 do_join = true;
2440
2441 /* Need to update the SSID (for filtering etc) */
2442 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2443 do_join = true;
2444
2445 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002446 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2447 bss_conf->enable_beacon ? "enabled" : "disabled");
2448
2449 if (bss_conf->enable_beacon)
2450 wl->set_bss_type = BSS_TYPE_IBSS;
2451 else
2452 wl->set_bss_type = BSS_TYPE_STA_BSS;
2453 do_join = true;
2454 }
2455
Arik Nemtsove78a2872010-10-16 19:07:21 +02002456 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002457 bool enable = false;
2458 if (bss_conf->cqm_rssi_thold)
2459 enable = true;
2460 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2461 bss_conf->cqm_rssi_thold,
2462 bss_conf->cqm_rssi_hyst);
2463 if (ret < 0)
2464 goto out;
2465 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2466 }
2467
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002468 if ((changed & BSS_CHANGED_BSSID) &&
2469 /*
2470 * Now we know the correct bssid, so we send a new join command
2471 * and enable the BSSID filter
2472 */
2473 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002474 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002475
Eliad Pellerfa287b82010-12-26 09:27:50 +01002476 if (!is_zero_ether_addr(wl->bssid)) {
2477 ret = wl1271_cmd_build_null_data(wl);
2478 if (ret < 0)
2479 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002480
Eliad Pellerfa287b82010-12-26 09:27:50 +01002481 ret = wl1271_build_qos_null_data(wl);
2482 if (ret < 0)
2483 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002484
Eliad Pellerfa287b82010-12-26 09:27:50 +01002485 /* filter out all packets not from this BSSID */
2486 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002487
Eliad Pellerfa287b82010-12-26 09:27:50 +01002488 /* Need to update the BSSID (for filtering etc) */
2489 do_join = true;
2490 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002491 }
2492
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002493 rcu_read_lock();
2494 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2495 if (sta) {
2496 /* save the supp_rates of the ap */
2497 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2498 if (sta->ht_cap.ht_supported)
2499 sta_rate_set |=
2500 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002501 sta_ht_cap = sta->ht_cap;
2502 sta_exists = true;
2503 }
2504 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002505
Arik Nemtsova1008852011-02-12 23:24:20 +02002506 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002507 /* handle new association with HT and HT information change */
2508 if ((changed & BSS_CHANGED_HT) &&
2509 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002510 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002511 true);
2512 if (ret < 0) {
2513 wl1271_warning("Set ht cap true failed %d",
2514 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002515 goto out;
2516 }
2517 ret = wl1271_acx_set_ht_information(wl,
2518 bss_conf->ht_operation_mode);
2519 if (ret < 0) {
2520 wl1271_warning("Set ht information failed %d",
2521 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002522 goto out;
2523 }
2524 }
2525 /* handle new association without HT and disassociation */
2526 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002527 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002528 false);
2529 if (ret < 0) {
2530 wl1271_warning("Set ht cap false failed %d",
2531 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002532 goto out;
2533 }
2534 }
2535 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002536
Arik Nemtsove78a2872010-10-16 19:07:21 +02002537 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002539 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002540 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002542 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002543
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002544 wl->ps_poll_failures = 0;
2545
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002546 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002547 * use basic rates from AP, and determine lowest rate
2548 * to use with control frames.
2549 */
2550 rates = bss_conf->basic_rates;
2551 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2552 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002553 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002554 if (sta_rate_set)
2555 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2556 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002557 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002558 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002559 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002560
2561 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002562 * with wl1271, we don't need to update the
2563 * beacon_int and dtim_period, because the firmware
2564 * updates it by itself when the first beacon is
2565 * received after a join.
2566 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2568 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002569 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002571 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002572 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002573 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002574 dev_kfree_skb(wl->probereq);
2575 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2576 ieoffset = offsetof(struct ieee80211_mgmt,
2577 u.probe_req.variable);
2578 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002579
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002580 /* enable the connection monitoring feature */
2581 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002583 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584
2585 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002586 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2587 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002588 enum wl1271_cmd_ps_mode mode;
2589
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002591 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002592 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002593 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002595 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002596 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002597 } else {
2598 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002599 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002600 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002601 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002602
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002603 /* free probe-request template */
2604 dev_kfree_skb(wl->probereq);
2605 wl->probereq = NULL;
2606
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002607 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002608 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002609
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002610 /* revert back to minimum rates for the current band */
2611 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002612 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002613 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002614 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002615 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002616
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002617 /* disable connection monitor features */
2618 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002619
2620 /* Disable the keep-alive feature */
2621 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002622 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002623 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002624
2625 /* restore the bssid filter and go to dummy bssid */
2626 wl1271_unjoin(wl);
2627 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002628 }
2629 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002630
Arik Nemtsove78a2872010-10-16 19:07:21 +02002631 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2632 if (ret < 0)
2633 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002634
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002635 if (changed & BSS_CHANGED_ARP_FILTER) {
2636 __be32 addr = bss_conf->arp_addr_list[0];
2637 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2638
Eliad Pellerc5312772010-12-09 11:31:27 +02002639 if (bss_conf->arp_addr_cnt == 1 &&
2640 bss_conf->arp_filter_enabled) {
2641 /*
2642 * The template should have been configured only upon
2643 * association. however, it seems that the correct ip
2644 * isn't being set (when sending), so we have to
2645 * reconfigure the template upon every ip change.
2646 */
2647 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2648 if (ret < 0) {
2649 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002650 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002651 }
2652
2653 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002654 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002655 addr);
2656 } else
2657 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002658
2659 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002660 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002661 }
2662
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002663 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002664 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002665 if (ret < 0) {
2666 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002667 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002668 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002669 }
2670
Arik Nemtsove78a2872010-10-16 19:07:21 +02002671out:
2672 return;
2673}
2674
2675static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2676 struct ieee80211_vif *vif,
2677 struct ieee80211_bss_conf *bss_conf,
2678 u32 changed)
2679{
2680 struct wl1271 *wl = hw->priv;
2681 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2682 int ret;
2683
2684 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2685 (int)changed);
2686
2687 mutex_lock(&wl->mutex);
2688
2689 if (unlikely(wl->state == WL1271_STATE_OFF))
2690 goto out;
2691
Ido Yariva6208652011-03-01 15:14:41 +02002692 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002693 if (ret < 0)
2694 goto out;
2695
2696 if (is_ap)
2697 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2698 else
2699 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2700
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701 wl1271_ps_elp_sleep(wl);
2702
2703out:
2704 mutex_unlock(&wl->mutex);
2705}
2706
Kalle Valoc6999d82010-02-18 13:25:41 +02002707static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2708 const struct ieee80211_tx_queue_params *params)
2709{
2710 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002711 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002712 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002713
2714 mutex_lock(&wl->mutex);
2715
2716 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2717
Kalle Valo4695dc92010-03-18 12:26:38 +02002718 if (params->uapsd)
2719 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2720 else
2721 ps_scheme = CONF_PS_SCHEME_LEGACY;
2722
Arik Nemtsov488fc542010-10-16 20:33:45 +02002723 if (wl->state == WL1271_STATE_OFF) {
2724 /*
2725 * If the state is off, the parameters will be recorded and
2726 * configured on init. This happens in AP-mode.
2727 */
2728 struct conf_tx_ac_category *conf_ac =
2729 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2730 struct conf_tx_tid *conf_tid =
2731 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2732
2733 conf_ac->ac = wl1271_tx_get_queue(queue);
2734 conf_ac->cw_min = (u8)params->cw_min;
2735 conf_ac->cw_max = params->cw_max;
2736 conf_ac->aifsn = params->aifs;
2737 conf_ac->tx_op_limit = params->txop << 5;
2738
2739 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2740 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2741 conf_tid->tsid = wl1271_tx_get_queue(queue);
2742 conf_tid->ps_scheme = ps_scheme;
2743 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2744 conf_tid->apsd_conf[0] = 0;
2745 conf_tid->apsd_conf[1] = 0;
2746 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002747 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002748 if (ret < 0)
2749 goto out;
2750
2751 /*
2752 * the txop is confed in units of 32us by the mac80211,
2753 * we need us
2754 */
2755 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2756 params->cw_min, params->cw_max,
2757 params->aifs, params->txop << 5);
2758 if (ret < 0)
2759 goto out_sleep;
2760
2761 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2762 CONF_CHANNEL_TYPE_EDCF,
2763 wl1271_tx_get_queue(queue),
2764 ps_scheme, CONF_ACK_POLICY_LEGACY,
2765 0, 0);
2766 if (ret < 0)
2767 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002768
2769out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002770 wl1271_ps_elp_sleep(wl);
2771 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002772
2773out:
2774 mutex_unlock(&wl->mutex);
2775
2776 return ret;
2777}
2778
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002779static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2780{
2781
2782 struct wl1271 *wl = hw->priv;
2783 u64 mactime = ULLONG_MAX;
2784 int ret;
2785
2786 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2787
2788 mutex_lock(&wl->mutex);
2789
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002790 if (unlikely(wl->state == WL1271_STATE_OFF))
2791 goto out;
2792
Ido Yariva6208652011-03-01 15:14:41 +02002793 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002794 if (ret < 0)
2795 goto out;
2796
2797 ret = wl1271_acx_tsf_info(wl, &mactime);
2798 if (ret < 0)
2799 goto out_sleep;
2800
2801out_sleep:
2802 wl1271_ps_elp_sleep(wl);
2803
2804out:
2805 mutex_unlock(&wl->mutex);
2806 return mactime;
2807}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808
John W. Linvilleece550d2010-07-28 16:41:06 -04002809static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2810 struct survey_info *survey)
2811{
2812 struct wl1271 *wl = hw->priv;
2813 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002814
John W. Linvilleece550d2010-07-28 16:41:06 -04002815 if (idx != 0)
2816 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002817
John W. Linvilleece550d2010-07-28 16:41:06 -04002818 survey->channel = conf->channel;
2819 survey->filled = SURVEY_INFO_NOISE_DBM;
2820 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002821
John W. Linvilleece550d2010-07-28 16:41:06 -04002822 return 0;
2823}
2824
Arik Nemtsov409622e2011-02-23 00:22:29 +02002825static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002826 struct ieee80211_sta *sta,
2827 u8 *hlid)
2828{
2829 struct wl1271_station *wl_sta;
2830 int id;
2831
2832 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2833 if (id >= AP_MAX_STATIONS) {
2834 wl1271_warning("could not allocate HLID - too much stations");
2835 return -EBUSY;
2836 }
2837
2838 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002839 __set_bit(id, wl->ap_hlid_map);
2840 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2841 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002842 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002843 return 0;
2844}
2845
Arik Nemtsov409622e2011-02-23 00:22:29 +02002846static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002847{
2848 int id = hlid - WL1271_AP_STA_HLID_START;
2849
Arik Nemtsov409622e2011-02-23 00:22:29 +02002850 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2851 return;
2852
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002853 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002854 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002855 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002856 __clear_bit(hlid, &wl->ap_ps_map);
2857 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002858}
2859
2860static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2861 struct ieee80211_vif *vif,
2862 struct ieee80211_sta *sta)
2863{
2864 struct wl1271 *wl = hw->priv;
2865 int ret = 0;
2866 u8 hlid;
2867
2868 mutex_lock(&wl->mutex);
2869
2870 if (unlikely(wl->state == WL1271_STATE_OFF))
2871 goto out;
2872
2873 if (wl->bss_type != BSS_TYPE_AP_BSS)
2874 goto out;
2875
2876 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2877
Arik Nemtsov409622e2011-02-23 00:22:29 +02002878 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002879 if (ret < 0)
2880 goto out;
2881
Ido Yariva6208652011-03-01 15:14:41 +02002882 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002883 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002884 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002885
2886 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2887 if (ret < 0)
2888 goto out_sleep;
2889
2890out_sleep:
2891 wl1271_ps_elp_sleep(wl);
2892
Arik Nemtsov409622e2011-02-23 00:22:29 +02002893out_free_sta:
2894 if (ret < 0)
2895 wl1271_free_sta(wl, hlid);
2896
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002897out:
2898 mutex_unlock(&wl->mutex);
2899 return ret;
2900}
2901
2902static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2903 struct ieee80211_vif *vif,
2904 struct ieee80211_sta *sta)
2905{
2906 struct wl1271 *wl = hw->priv;
2907 struct wl1271_station *wl_sta;
2908 int ret = 0, id;
2909
2910 mutex_lock(&wl->mutex);
2911
2912 if (unlikely(wl->state == WL1271_STATE_OFF))
2913 goto out;
2914
2915 if (wl->bss_type != BSS_TYPE_AP_BSS)
2916 goto out;
2917
2918 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2919
2920 wl_sta = (struct wl1271_station *)sta->drv_priv;
2921 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2922 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2923 goto out;
2924
Ido Yariva6208652011-03-01 15:14:41 +02002925 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002926 if (ret < 0)
2927 goto out;
2928
2929 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2930 if (ret < 0)
2931 goto out_sleep;
2932
Arik Nemtsov409622e2011-02-23 00:22:29 +02002933 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002934
2935out_sleep:
2936 wl1271_ps_elp_sleep(wl);
2937
2938out:
2939 mutex_unlock(&wl->mutex);
2940 return ret;
2941}
2942
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002943int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002944 enum ieee80211_ampdu_mlme_action action,
2945 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2946 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002947{
2948 struct wl1271 *wl = hw->priv;
2949 int ret;
2950
2951 mutex_lock(&wl->mutex);
2952
2953 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2954 ret = -EAGAIN;
2955 goto out;
2956 }
2957
Ido Yariva6208652011-03-01 15:14:41 +02002958 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002959 if (ret < 0)
2960 goto out;
2961
2962 switch (action) {
2963 case IEEE80211_AMPDU_RX_START:
2964 if (wl->ba_support) {
2965 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2966 true);
2967 if (!ret)
2968 wl->ba_rx_bitmap |= BIT(tid);
2969 } else {
2970 ret = -ENOTSUPP;
2971 }
2972 break;
2973
2974 case IEEE80211_AMPDU_RX_STOP:
2975 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2976 if (!ret)
2977 wl->ba_rx_bitmap &= ~BIT(tid);
2978 break;
2979
2980 /*
2981 * The BA initiator session management in FW independently.
2982 * Falling break here on purpose for all TX APDU commands.
2983 */
2984 case IEEE80211_AMPDU_TX_START:
2985 case IEEE80211_AMPDU_TX_STOP:
2986 case IEEE80211_AMPDU_TX_OPERATIONAL:
2987 ret = -EINVAL;
2988 break;
2989
2990 default:
2991 wl1271_error("Incorrect ampdu action id=%x\n", action);
2992 ret = -EINVAL;
2993 }
2994
2995 wl1271_ps_elp_sleep(wl);
2996
2997out:
2998 mutex_unlock(&wl->mutex);
2999
3000 return ret;
3001}
3002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003/* can't be const, mac80211 writes to this */
3004static struct ieee80211_rate wl1271_rates[] = {
3005 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003006 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3007 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003008 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003009 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3010 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3012 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003013 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3014 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3016 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003017 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3018 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3020 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003021 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3022 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003024 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3025 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003026 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003027 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3028 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003030 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3031 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003033 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3034 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003036 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3037 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003039 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3040 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003042 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3043 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044};
3045
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003046/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003048 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003049 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003050 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3051 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3052 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003053 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003054 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3055 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3056 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003057 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003058 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3059 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3060 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003061 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062};
3063
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003064/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003065static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003066 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003067 7, /* CONF_HW_RXTX_RATE_MCS7 */
3068 6, /* CONF_HW_RXTX_RATE_MCS6 */
3069 5, /* CONF_HW_RXTX_RATE_MCS5 */
3070 4, /* CONF_HW_RXTX_RATE_MCS4 */
3071 3, /* CONF_HW_RXTX_RATE_MCS3 */
3072 2, /* CONF_HW_RXTX_RATE_MCS2 */
3073 1, /* CONF_HW_RXTX_RATE_MCS1 */
3074 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003075
3076 11, /* CONF_HW_RXTX_RATE_54 */
3077 10, /* CONF_HW_RXTX_RATE_48 */
3078 9, /* CONF_HW_RXTX_RATE_36 */
3079 8, /* CONF_HW_RXTX_RATE_24 */
3080
3081 /* TI-specific rate */
3082 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3083
3084 7, /* CONF_HW_RXTX_RATE_18 */
3085 6, /* CONF_HW_RXTX_RATE_12 */
3086 3, /* CONF_HW_RXTX_RATE_11 */
3087 5, /* CONF_HW_RXTX_RATE_9 */
3088 4, /* CONF_HW_RXTX_RATE_6 */
3089 2, /* CONF_HW_RXTX_RATE_5_5 */
3090 1, /* CONF_HW_RXTX_RATE_2 */
3091 0 /* CONF_HW_RXTX_RATE_1 */
3092};
3093
Shahar Levie8b03a22010-10-13 16:09:39 +02003094/* 11n STA capabilities */
3095#define HW_RX_HIGHEST_RATE 72
3096
Shahar Levi00d20102010-11-08 11:20:10 +00003097#ifdef CONFIG_WL12XX_HT
3098#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003099 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3100 .ht_supported = true, \
3101 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3102 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3103 .mcs = { \
3104 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3105 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3106 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3107 }, \
3108}
Shahar Levi18357852010-10-13 16:09:41 +02003109#else
Shahar Levi00d20102010-11-08 11:20:10 +00003110#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003111 .ht_supported = false, \
3112}
3113#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003114
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003115/* can't be const, mac80211 writes to this */
3116static struct ieee80211_supported_band wl1271_band_2ghz = {
3117 .channels = wl1271_channels,
3118 .n_channels = ARRAY_SIZE(wl1271_channels),
3119 .bitrates = wl1271_rates,
3120 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003121 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003122};
3123
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003124/* 5 GHz data rates for WL1273 */
3125static struct ieee80211_rate wl1271_rates_5ghz[] = {
3126 { .bitrate = 60,
3127 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3128 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3129 { .bitrate = 90,
3130 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3131 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3132 { .bitrate = 120,
3133 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3134 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3135 { .bitrate = 180,
3136 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3137 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3138 { .bitrate = 240,
3139 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3141 { .bitrate = 360,
3142 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3143 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3144 { .bitrate = 480,
3145 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3146 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3147 { .bitrate = 540,
3148 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3149 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3150};
3151
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003152/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003153static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003154 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003155 { .hw_value = 8, .center_freq = 5040},
3156 { .hw_value = 9, .center_freq = 5045},
3157 { .hw_value = 11, .center_freq = 5055},
3158 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003159 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003160 { .hw_value = 34, .center_freq = 5170},
3161 { .hw_value = 36, .center_freq = 5180},
3162 { .hw_value = 38, .center_freq = 5190},
3163 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003164 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003165 { .hw_value = 44, .center_freq = 5220},
3166 { .hw_value = 46, .center_freq = 5230},
3167 { .hw_value = 48, .center_freq = 5240},
3168 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003169 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003170 { .hw_value = 60, .center_freq = 5300},
3171 { .hw_value = 64, .center_freq = 5320},
3172 { .hw_value = 100, .center_freq = 5500},
3173 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003174 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003175 { .hw_value = 112, .center_freq = 5560},
3176 { .hw_value = 116, .center_freq = 5580},
3177 { .hw_value = 120, .center_freq = 5600},
3178 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003179 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003180 { .hw_value = 132, .center_freq = 5660},
3181 { .hw_value = 136, .center_freq = 5680},
3182 { .hw_value = 140, .center_freq = 5700},
3183 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003184 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003185 { .hw_value = 157, .center_freq = 5785},
3186 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003187 { .hw_value = 165, .center_freq = 5825},
3188};
3189
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003190/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003191static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003192 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003193 7, /* CONF_HW_RXTX_RATE_MCS7 */
3194 6, /* CONF_HW_RXTX_RATE_MCS6 */
3195 5, /* CONF_HW_RXTX_RATE_MCS5 */
3196 4, /* CONF_HW_RXTX_RATE_MCS4 */
3197 3, /* CONF_HW_RXTX_RATE_MCS3 */
3198 2, /* CONF_HW_RXTX_RATE_MCS2 */
3199 1, /* CONF_HW_RXTX_RATE_MCS1 */
3200 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003201
3202 7, /* CONF_HW_RXTX_RATE_54 */
3203 6, /* CONF_HW_RXTX_RATE_48 */
3204 5, /* CONF_HW_RXTX_RATE_36 */
3205 4, /* CONF_HW_RXTX_RATE_24 */
3206
3207 /* TI-specific rate */
3208 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3209
3210 3, /* CONF_HW_RXTX_RATE_18 */
3211 2, /* CONF_HW_RXTX_RATE_12 */
3212 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3213 1, /* CONF_HW_RXTX_RATE_9 */
3214 0, /* CONF_HW_RXTX_RATE_6 */
3215 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3216 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3217 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3218};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003219
3220static struct ieee80211_supported_band wl1271_band_5ghz = {
3221 .channels = wl1271_channels_5ghz,
3222 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3223 .bitrates = wl1271_rates_5ghz,
3224 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003225 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003226};
3227
Tobias Klausera0ea9492010-05-20 10:38:11 +02003228static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003229 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3230 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3231};
3232
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003233static const struct ieee80211_ops wl1271_ops = {
3234 .start = wl1271_op_start,
3235 .stop = wl1271_op_stop,
3236 .add_interface = wl1271_op_add_interface,
3237 .remove_interface = wl1271_op_remove_interface,
3238 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003239 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003240 .configure_filter = wl1271_op_configure_filter,
3241 .tx = wl1271_op_tx,
3242 .set_key = wl1271_op_set_key,
3243 .hw_scan = wl1271_op_hw_scan,
3244 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003245 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003246 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003247 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003248 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003249 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003250 .sta_add = wl1271_op_sta_add,
3251 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003252 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003253 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003254};
3255
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003256
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003257u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003258{
3259 u8 idx;
3260
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003261 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003262
3263 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3264 wl1271_error("Illegal RX rate from HW: %d", rate);
3265 return 0;
3266 }
3267
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003268 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003269 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3270 wl1271_error("Unsupported RX rate from HW: %d", rate);
3271 return 0;
3272 }
3273
3274 return idx;
3275}
3276
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003277static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3278 struct device_attribute *attr,
3279 char *buf)
3280{
3281 struct wl1271 *wl = dev_get_drvdata(dev);
3282 ssize_t len;
3283
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003284 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003285
3286 mutex_lock(&wl->mutex);
3287 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3288 wl->sg_enabled);
3289 mutex_unlock(&wl->mutex);
3290
3291 return len;
3292
3293}
3294
3295static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3296 struct device_attribute *attr,
3297 const char *buf, size_t count)
3298{
3299 struct wl1271 *wl = dev_get_drvdata(dev);
3300 unsigned long res;
3301 int ret;
3302
3303 ret = strict_strtoul(buf, 10, &res);
3304
3305 if (ret < 0) {
3306 wl1271_warning("incorrect value written to bt_coex_mode");
3307 return count;
3308 }
3309
3310 mutex_lock(&wl->mutex);
3311
3312 res = !!res;
3313
3314 if (res == wl->sg_enabled)
3315 goto out;
3316
3317 wl->sg_enabled = res;
3318
3319 if (wl->state == WL1271_STATE_OFF)
3320 goto out;
3321
Ido Yariva6208652011-03-01 15:14:41 +02003322 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003323 if (ret < 0)
3324 goto out;
3325
3326 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3327 wl1271_ps_elp_sleep(wl);
3328
3329 out:
3330 mutex_unlock(&wl->mutex);
3331 return count;
3332}
3333
3334static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3335 wl1271_sysfs_show_bt_coex_state,
3336 wl1271_sysfs_store_bt_coex_state);
3337
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003338static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3339 struct device_attribute *attr,
3340 char *buf)
3341{
3342 struct wl1271 *wl = dev_get_drvdata(dev);
3343 ssize_t len;
3344
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003345 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003346
3347 mutex_lock(&wl->mutex);
3348 if (wl->hw_pg_ver >= 0)
3349 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3350 else
3351 len = snprintf(buf, len, "n/a\n");
3352 mutex_unlock(&wl->mutex);
3353
3354 return len;
3355}
3356
3357static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3358 wl1271_sysfs_show_hw_pg_ver, NULL);
3359
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003360int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003361{
3362 int ret;
3363
3364 if (wl->mac80211_registered)
3365 return 0;
3366
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003367 ret = wl1271_fetch_nvs(wl);
3368 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003369 /* NOTE: The wl->nvs->nvs element must be first, in
3370 * order to simplify the casting, we assume it is at
3371 * the beginning of the wl->nvs structure.
3372 */
3373 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003374
3375 wl->mac_addr[0] = nvs_ptr[11];
3376 wl->mac_addr[1] = nvs_ptr[10];
3377 wl->mac_addr[2] = nvs_ptr[6];
3378 wl->mac_addr[3] = nvs_ptr[5];
3379 wl->mac_addr[4] = nvs_ptr[4];
3380 wl->mac_addr[5] = nvs_ptr[3];
3381 }
3382
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003383 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3384
3385 ret = ieee80211_register_hw(wl->hw);
3386 if (ret < 0) {
3387 wl1271_error("unable to register mac80211 hw: %d", ret);
3388 return ret;
3389 }
3390
3391 wl->mac80211_registered = true;
3392
Eliad Pellerd60080a2010-11-24 12:53:16 +02003393 wl1271_debugfs_init(wl);
3394
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003395 register_netdevice_notifier(&wl1271_dev_notifier);
3396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003397 wl1271_notice("loaded");
3398
3399 return 0;
3400}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003401EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003402
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003403void wl1271_unregister_hw(struct wl1271 *wl)
3404{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003405 if (wl->state == WL1271_STATE_PLT)
3406 __wl1271_plt_stop(wl);
3407
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003408 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003409 ieee80211_unregister_hw(wl->hw);
3410 wl->mac80211_registered = false;
3411
3412}
3413EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3414
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003415int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003416{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003417 static const u32 cipher_suites[] = {
3418 WLAN_CIPHER_SUITE_WEP40,
3419 WLAN_CIPHER_SUITE_WEP104,
3420 WLAN_CIPHER_SUITE_TKIP,
3421 WLAN_CIPHER_SUITE_CCMP,
3422 WL1271_CIPHER_SUITE_GEM,
3423 };
3424
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003425 /* The tx descriptor buffer and the TKIP space. */
3426 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3427 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428
3429 /* unit us */
3430 /* FIXME: find a proper value */
3431 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003432 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003433
3434 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003435 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003436 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003437 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003438 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003439 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003440 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003441 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3442 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003443
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003444 wl->hw->wiphy->cipher_suites = cipher_suites;
3445 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3446
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003447 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003448 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003450 /*
3451 * Maximum length of elements in scanning probe request templates
3452 * should be the maximum length possible for a template, without
3453 * the IEEE80211 header of the template
3454 */
3455 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3456 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003457
3458 /*
3459 * We keep local copies of the band structs because we need to
3460 * modify them on a per-device basis.
3461 */
3462 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3463 sizeof(wl1271_band_2ghz));
3464 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3465 sizeof(wl1271_band_5ghz));
3466
3467 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3468 &wl->bands[IEEE80211_BAND_2GHZ];
3469 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3470 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003471
Kalle Valo12bd8942010-03-18 12:26:33 +02003472 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003473 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003474
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003475 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3476
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003477 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003478
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003479 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3480
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003481 wl->hw->max_rx_aggregation_subframes = 8;
3482
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003483 return 0;
3484}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003485EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003486
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003487#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003488
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003489struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003490{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003491 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003492 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003494 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003495 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003496
3497 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3498 if (!hw) {
3499 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003500 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003501 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003502 }
3503
Julia Lawall929ebd32010-05-15 23:16:39 +02003504 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003505 if (!plat_dev) {
3506 wl1271_error("could not allocate platform_device");
3507 ret = -ENOMEM;
3508 goto err_plat_alloc;
3509 }
3510
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003511 wl = hw->priv;
3512 memset(wl, 0, sizeof(*wl));
3513
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003514 INIT_LIST_HEAD(&wl->list);
3515
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003516 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003517 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003518
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003519 for (i = 0; i < NUM_TX_QUEUES; i++)
3520 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003521
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003522 for (i = 0; i < NUM_TX_QUEUES; i++)
3523 for (j = 0; j < AP_MAX_LINKS; j++)
3524 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3525
Ido Yariva6208652011-03-01 15:14:41 +02003526 skb_queue_head_init(&wl->deferred_rx_queue);
3527 skb_queue_head_init(&wl->deferred_tx_queue);
3528
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003529 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003530 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003531 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003532 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3533 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3534 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003535 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003536 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003539 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3540 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003541 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003542 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003543 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003544 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003545 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003546 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003547 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003548 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003549 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003550 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003551 wl->bss_type = MAX_BSS_TYPE;
3552 wl->set_bss_type = MAX_BSS_TYPE;
3553 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003554 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003555 wl->ap_ps_map = 0;
3556 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003557 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003558 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003559
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003560 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003561 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003562 wl->tx_frames[i] = NULL;
3563
3564 spin_lock_init(&wl->wl_lock);
3565
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003566 wl->state = WL1271_STATE_OFF;
3567 mutex_init(&wl->mutex);
3568
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003569 /* Apply default driver configuration. */
3570 wl1271_conf_init(wl);
3571
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003572 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3573 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3574 if (!wl->aggr_buf) {
3575 ret = -ENOMEM;
3576 goto err_hw;
3577 }
3578
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003579 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003580 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003581 if (ret) {
3582 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003583 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003584 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003585 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003586
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003587 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003588 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003589 if (ret < 0) {
3590 wl1271_error("failed to create sysfs file bt_coex_state");
3591 goto err_platform;
3592 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003593
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003594 /* Create sysfs file to get HW PG version */
3595 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3596 if (ret < 0) {
3597 wl1271_error("failed to create sysfs file hw_pg_ver");
3598 goto err_bt_coex_state;
3599 }
3600
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003601 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003602
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003603err_bt_coex_state:
3604 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3605
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003606err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003607 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003608
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003609err_aggr:
3610 free_pages((unsigned long)wl->aggr_buf, order);
3611
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003612err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003613 wl1271_debugfs_exit(wl);
3614 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003615
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003616err_plat_alloc:
3617 ieee80211_free_hw(hw);
3618
3619err_hw_alloc:
3620
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003621 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003622}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003623EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003624
3625int wl1271_free_hw(struct wl1271 *wl)
3626{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003627 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003628 free_pages((unsigned long)wl->aggr_buf,
3629 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003630 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003631
3632 wl1271_debugfs_exit(wl);
3633
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003634 vfree(wl->fw);
3635 wl->fw = NULL;
3636 kfree(wl->nvs);
3637 wl->nvs = NULL;
3638
3639 kfree(wl->fw_status);
3640 kfree(wl->tx_res_if);
3641
3642 ieee80211_free_hw(wl->hw);
3643
3644 return 0;
3645}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003646EXPORT_SYMBOL_GPL(wl1271_free_hw);
3647
Guy Eilam491bbd62011-01-12 10:33:29 +01003648u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003649EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003650module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003651MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3652
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003653MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003654MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003655MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");