blob: 9a7ca6524d20f77509899abb14b10a4744287ba7 [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:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200835 if (wl->chip.id == CHIP_ID_1283_PG20)
836 fw_name = WL128X_AP_FW_NAME;
837 else
838 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200839 break;
840 case BSS_TYPE_IBSS:
841 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200842 if (wl->chip.id == CHIP_ID_1283_PG20)
843 fw_name = WL128X_FW_NAME;
844 else
845 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200846 break;
847 default:
848 wl1271_error("no compatible firmware for bss_type %d",
849 wl->bss_type);
850 return -EINVAL;
851 }
852
853 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
854
855 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856
857 if (ret < 0) {
858 wl1271_error("could not get firmware: %d", ret);
859 return ret;
860 }
861
862 if (fw->size % 4) {
863 wl1271_error("firmware size is not multiple of 32 bits: %zu",
864 fw->size);
865 ret = -EILSEQ;
866 goto out;
867 }
868
Arik Nemtsov166d5042010-10-16 21:44:57 +0200869 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300870 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300871 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872
873 if (!wl->fw) {
874 wl1271_error("could not allocate memory for the firmware");
875 ret = -ENOMEM;
876 goto out;
877 }
878
879 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200880 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881 ret = 0;
882
883out:
884 release_firmware(fw);
885
886 return ret;
887}
888
889static int wl1271_fetch_nvs(struct wl1271 *wl)
890{
891 const struct firmware *fw;
892 int ret;
893
Shahar Levi5aa42342011-03-06 16:32:07 +0200894 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895
896 if (ret < 0) {
897 wl1271_error("could not get nvs file: %d", ret);
898 return ret;
899 }
900
Shahar Levibc765bf2011-03-06 16:32:10 +0200901 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 if (!wl->nvs) {
904 wl1271_error("could not allocate memory for the nvs file");
905 ret = -ENOMEM;
906 goto out;
907 }
908
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200909 wl->nvs_len = fw->size;
910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911out:
912 release_firmware(fw);
913
914 return ret;
915}
916
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200917static void wl1271_recovery_work(struct work_struct *work)
918{
919 struct wl1271 *wl =
920 container_of(work, struct wl1271, recovery_work);
921
922 mutex_lock(&wl->mutex);
923
924 if (wl->state != WL1271_STATE_ON)
925 goto out;
926
927 wl1271_info("Hardware recovery in progress.");
928
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200929 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
930 ieee80211_connection_loss(wl->vif);
931
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200932 /* reboot the chipset */
933 __wl1271_op_remove_interface(wl);
934 ieee80211_restart_hw(wl->hw);
935
936out:
937 mutex_unlock(&wl->mutex);
938}
939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940static void wl1271_fw_wakeup(struct wl1271 *wl)
941{
942 u32 elp_reg;
943
944 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300945 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946}
947
948static int wl1271_setup(struct wl1271 *wl)
949{
950 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
951 if (!wl->fw_status)
952 return -ENOMEM;
953
954 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
955 if (!wl->tx_res_if) {
956 kfree(wl->fw_status);
957 return -ENOMEM;
958 }
959
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 return 0;
961}
962
963static int wl1271_chip_wakeup(struct wl1271 *wl)
964{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300965 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 int ret = 0;
967
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200968 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200969 ret = wl1271_power_on(wl);
970 if (ret < 0)
971 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200973 wl1271_io_reset(wl);
974 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975
976 /* We don't need a real memory partition here, because we only want
977 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300978 memset(&partition, 0, sizeof(partition));
979 partition.reg.start = REGISTERS_BASE;
980 partition.reg.size = REGISTERS_DOWN_SIZE;
981 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982
983 /* ELP module wake up */
984 wl1271_fw_wakeup(wl);
985
986 /* whal_FwCtrl_BootSm() */
987
988 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200989 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990
991 /* 1. check if chip id is valid */
992
993 switch (wl->chip.id) {
994 case CHIP_ID_1271_PG10:
995 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
996 wl->chip.id);
997
998 ret = wl1271_setup(wl);
999 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001000 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 break;
1002 case CHIP_ID_1271_PG20:
1003 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1004 wl->chip.id);
1005
1006 ret = wl1271_setup(wl);
1007 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001008 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 break;
1010 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001011 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001013 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 }
1015
Arik Nemtsov166d5042010-10-16 21:44:57 +02001016 /* Make sure the firmware type matches the BSS type */
1017 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 ret = wl1271_fetch_firmware(wl);
1019 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001020 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 }
1022
1023 /* No NVS from netlink, try to get it from the filesystem */
1024 if (wl->nvs == NULL) {
1025 ret = wl1271_fetch_nvs(wl);
1026 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001027 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 }
1029
1030out:
1031 return ret;
1032}
1033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034int wl1271_plt_start(struct wl1271 *wl)
1035{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001036 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 int ret;
1038
1039 mutex_lock(&wl->mutex);
1040
1041 wl1271_notice("power up");
1042
1043 if (wl->state != WL1271_STATE_OFF) {
1044 wl1271_error("cannot go into PLT state because not "
1045 "in off state: %d", wl->state);
1046 ret = -EBUSY;
1047 goto out;
1048 }
1049
Arik Nemtsov166d5042010-10-16 21:44:57 +02001050 wl->bss_type = BSS_TYPE_STA_BSS;
1051
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001052 while (retries) {
1053 retries--;
1054 ret = wl1271_chip_wakeup(wl);
1055 if (ret < 0)
1056 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001058 ret = wl1271_boot(wl);
1059 if (ret < 0)
1060 goto power_off;
1061
1062 ret = wl1271_plt_init(wl);
1063 if (ret < 0)
1064 goto irq_disable;
1065
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001066 wl->state = WL1271_STATE_PLT;
1067 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001068 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 goto out;
1070
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001071irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001072 mutex_unlock(&wl->mutex);
1073 /* Unlocking the mutex in the middle of handling is
1074 inherently unsafe. In this case we deem it safe to do,
1075 because we need to let any possibly pending IRQ out of
1076 the system (and while we are WL1271_STATE_OFF the IRQ
1077 work function will not do anything.) Also, any other
1078 possible concurrent operations will fail due to the
1079 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001080 wl1271_disable_interrupts(wl);
1081 wl1271_flush_deferred_work(wl);
1082 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001083 mutex_lock(&wl->mutex);
1084power_off:
1085 wl1271_power_off(wl);
1086 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001088 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1089 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090out:
1091 mutex_unlock(&wl->mutex);
1092
1093 return ret;
1094}
1095
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001096int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097{
1098 int ret = 0;
1099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 wl1271_notice("power down");
1101
1102 if (wl->state != WL1271_STATE_PLT) {
1103 wl1271_error("cannot power down because not in PLT "
1104 "state: %d", wl->state);
1105 ret = -EBUSY;
1106 goto out;
1107 }
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 wl1271_power_off(wl);
1110
1111 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001112 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001114 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001115 wl1271_disable_interrupts(wl);
1116 wl1271_flush_deferred_work(wl);
1117 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001118 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001119 mutex_lock(&wl->mutex);
1120out:
1121 return ret;
1122}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001123
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001124int wl1271_plt_stop(struct wl1271 *wl)
1125{
1126 int ret;
1127
1128 mutex_lock(&wl->mutex);
1129 ret = __wl1271_plt_stop(wl);
1130 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001131 return ret;
1132}
1133
Johannes Berg7bb45682011-02-24 14:42:06 +01001134static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135{
1136 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001137 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001138 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001139 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140
Ido Yarivb07d4032011-03-01 15:14:43 +02001141 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1142
1143 if (wl->bss_type == BSS_TYPE_AP_BSS)
1144 hlid = wl1271_tx_get_hlid(skb);
1145
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001146 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001147
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001148 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001149
1150 /*
1151 * The workqueue is slow to process the tx_queue and we need stop
1152 * the queue here, otherwise the queue will get too long.
1153 */
1154 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1155 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1156 ieee80211_stop_queues(wl->hw);
1157 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1158 }
1159
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001160 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001161 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001162 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1163 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1164 } else {
1165 skb_queue_tail(&wl->tx_queue[q], skb);
1166 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001167
1168 /*
1169 * The chip specific setup must run before the first TX packet -
1170 * before that, the tx_work will not be initialized!
1171 */
1172
Ido Yarivb07d4032011-03-01 15:14:43 +02001173 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1174 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001175 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001176
1177 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178}
1179
Shahar Leviae47c452011-03-06 16:32:14 +02001180#define TX_DUMMY_PACKET_SIZE 1400
1181int wl1271_tx_dummy_packet(struct wl1271 *wl)
1182{
1183 struct sk_buff *skb = NULL;
1184 struct ieee80211_hdr_3addr *hdr;
1185 int ret = 0;
1186
1187 skb = dev_alloc_skb(
1188 sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
1189 TX_DUMMY_PACKET_SIZE);
1190 if (!skb) {
1191 wl1271_warning("failed to allocate buffer for dummy packet");
1192 ret = -ENOMEM;
1193 goto out;
1194 }
1195
1196 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1197
1198 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1199 memset(hdr, 0, sizeof(*hdr));
1200 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1201 IEEE80211_FCTL_TODS |
1202 IEEE80211_STYPE_NULLFUNC);
1203
1204 memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
1205 memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
1206 memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
1207
1208 skb_put(skb, TX_DUMMY_PACKET_SIZE);
1209
1210 memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
1211
1212 skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
1213 /* CONF_TX_AC_VO */
1214 skb->queue_mapping = 0;
1215
1216 wl1271_op_tx(wl->hw, skb);
1217
1218out:
1219 return ret;
1220}
1221
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001222static struct notifier_block wl1271_dev_notifier = {
1223 .notifier_call = wl1271_dev_notify,
1224};
1225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226static int wl1271_op_start(struct ieee80211_hw *hw)
1227{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001228 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1229
1230 /*
1231 * We have to delay the booting of the hardware because
1232 * we need to know the local MAC address before downloading and
1233 * initializing the firmware. The MAC address cannot be changed
1234 * after boot, and without the proper MAC address, the firmware
1235 * will not function properly.
1236 *
1237 * The MAC address is first known when the corresponding interface
1238 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001239 *
1240 * In addition, we currently have different firmwares for AP and managed
1241 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001242 */
1243
1244 return 0;
1245}
1246
1247static void wl1271_op_stop(struct ieee80211_hw *hw)
1248{
1249 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1250}
1251
1252static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1253 struct ieee80211_vif *vif)
1254{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001256 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001257 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001258 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001259 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001261 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1262 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
1264 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001265 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001266 wl1271_debug(DEBUG_MAC80211,
1267 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001268 ret = -EBUSY;
1269 goto out;
1270 }
1271
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001272 switch (vif->type) {
1273 case NL80211_IFTYPE_STATION:
1274 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001275 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001276 break;
1277 case NL80211_IFTYPE_ADHOC:
1278 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001279 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001280 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001281 case NL80211_IFTYPE_AP:
1282 wl->bss_type = BSS_TYPE_AP_BSS;
1283 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001284 default:
1285 ret = -EOPNOTSUPP;
1286 goto out;
1287 }
1288
1289 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290
1291 if (wl->state != WL1271_STATE_OFF) {
1292 wl1271_error("cannot start because not in off state: %d",
1293 wl->state);
1294 ret = -EBUSY;
1295 goto out;
1296 }
1297
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001298 while (retries) {
1299 retries--;
1300 ret = wl1271_chip_wakeup(wl);
1301 if (ret < 0)
1302 goto power_off;
1303
1304 ret = wl1271_boot(wl);
1305 if (ret < 0)
1306 goto power_off;
1307
1308 ret = wl1271_hw_init(wl);
1309 if (ret < 0)
1310 goto irq_disable;
1311
Eliad Peller71125ab2010-10-28 21:46:43 +02001312 booted = true;
1313 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001315irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001316 mutex_unlock(&wl->mutex);
1317 /* Unlocking the mutex in the middle of handling is
1318 inherently unsafe. In this case we deem it safe to do,
1319 because we need to let any possibly pending IRQ out of
1320 the system (and while we are WL1271_STATE_OFF the IRQ
1321 work function will not do anything.) Also, any other
1322 possible concurrent operations will fail due to the
1323 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001324 wl1271_disable_interrupts(wl);
1325 wl1271_flush_deferred_work(wl);
1326 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001327 mutex_lock(&wl->mutex);
1328power_off:
1329 wl1271_power_off(wl);
1330 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331
Eliad Peller71125ab2010-10-28 21:46:43 +02001332 if (!booted) {
1333 wl1271_error("firmware boot failed despite %d retries",
1334 WL1271_BOOT_RETRIES);
1335 goto out;
1336 }
1337
1338 wl->vif = vif;
1339 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001340 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001341
1342 /* update hw/fw version info in wiphy struct */
1343 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001344 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001345 sizeof(wiphy->fw_version));
1346
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001347 /*
1348 * Now we know if 11a is supported (info from the NVS), so disable
1349 * 11a channels if not supported
1350 */
1351 if (!wl->enable_11a)
1352 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1353
1354 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1355 wl->enable_11a ? "" : "not ");
1356
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001357out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358 mutex_unlock(&wl->mutex);
1359
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001360 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001361 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 return ret;
1364}
1365
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001366static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 int i;
1369
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001370 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001372 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001374 list_del(&wl->list);
1375
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376 WARN_ON(wl->state != WL1271_STATE_ON);
1377
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001378 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001379 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001380 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001381
Luciano Coelho08688d62010-07-08 17:50:07 +03001382 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001383 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1384 kfree(wl->scan.scanned_ch);
1385 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001386 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001387 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388 }
1389
1390 wl->state = WL1271_STATE_OFF;
1391
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392 mutex_unlock(&wl->mutex);
1393
Ido Yariva6208652011-03-01 15:14:41 +02001394 wl1271_disable_interrupts(wl);
1395 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001396 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001397 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001398 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001399 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001400 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401
1402 mutex_lock(&wl->mutex);
1403
1404 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001405 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406 wl1271_power_off(wl);
1407
1408 memset(wl->bssid, 0, ETH_ALEN);
1409 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1410 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001412 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001413 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414
1415 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001416 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1418 wl->tx_blocks_available = 0;
1419 wl->tx_results_count = 0;
1420 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001421 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001422 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 wl->time_offset = 0;
1424 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001425 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001426 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001427 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001428 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001429 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001430 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001431 wl->ap_fw_ps_map = 0;
1432 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001433 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001435 for (i = 0; i < NUM_TX_QUEUES; i++)
1436 wl->tx_blocks_freed[i] = 0;
1437
1438 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001439
1440 kfree(wl->fw_status);
1441 wl->fw_status = NULL;
1442 kfree(wl->tx_res_if);
1443 wl->tx_res_if = NULL;
1444 kfree(wl->target_mem_map);
1445 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001446}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001447
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001448static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1449 struct ieee80211_vif *vif)
1450{
1451 struct wl1271 *wl = hw->priv;
1452
1453 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001454 /*
1455 * wl->vif can be null here if someone shuts down the interface
1456 * just when hardware recovery has been started.
1457 */
1458 if (wl->vif) {
1459 WARN_ON(wl->vif != vif);
1460 __wl1271_op_remove_interface(wl);
1461 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001462
Juuso Oikarinen67353292010-11-18 15:19:02 +02001463 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001464 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465}
1466
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001467static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1468{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001469 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001470
1471 /* combine requested filters with current filter config */
1472 filters = wl->filters | filters;
1473
1474 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1475
1476 if (filters & FIF_PROMISC_IN_BSS) {
1477 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1478 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1479 wl->rx_config |= CFG_BSSID_FILTER_EN;
1480 }
1481 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1482 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1483 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1484 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1485 }
1486 if (filters & FIF_OTHER_BSS) {
1487 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1488 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1489 }
1490 if (filters & FIF_CONTROL) {
1491 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1492 wl->rx_filter |= CFG_RX_CTL_EN;
1493 }
1494 if (filters & FIF_FCSFAIL) {
1495 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1496 wl->rx_filter |= CFG_RX_FCS_ERROR;
1497 }
1498}
1499
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001500static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001501{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001502 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001503 /* we need to use a dummy BSSID for now */
1504 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1505 0xad, 0xbe, 0xef };
1506
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001507 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1508
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001509 /* pass through frames from all BSS */
1510 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1511
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001512 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001513 if (ret < 0)
1514 goto out;
1515
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001516 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001517
1518out:
1519 return ret;
1520}
1521
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001522static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001523{
1524 int ret;
1525
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001526 /*
1527 * One of the side effects of the JOIN command is that is clears
1528 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1529 * to a WPA/WPA2 access point will therefore kill the data-path.
1530 * Currently there is no supported scenario for JOIN during
1531 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1532 * must be handled somehow.
1533 *
1534 */
1535 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1536 wl1271_info("JOIN while associated.");
1537
1538 if (set_assoc)
1539 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1540
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001541 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1542 if (ret < 0)
1543 goto out;
1544
1545 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1546
1547 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1548 goto out;
1549
1550 /*
1551 * The join command disable the keep-alive mode, shut down its process,
1552 * and also clear the template config, so we need to reset it all after
1553 * the join. The acx_aid starts the keep-alive process, and the order
1554 * of the commands below is relevant.
1555 */
1556 ret = wl1271_acx_keep_alive_mode(wl, true);
1557 if (ret < 0)
1558 goto out;
1559
1560 ret = wl1271_acx_aid(wl, wl->aid);
1561 if (ret < 0)
1562 goto out;
1563
1564 ret = wl1271_cmd_build_klv_null_data(wl);
1565 if (ret < 0)
1566 goto out;
1567
1568 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1569 ACX_KEEP_ALIVE_TPL_VALID);
1570 if (ret < 0)
1571 goto out;
1572
1573out:
1574 return ret;
1575}
1576
1577static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001578{
1579 int ret;
1580
1581 /* to stop listening to a channel, we disconnect */
1582 ret = wl1271_cmd_disconnect(wl);
1583 if (ret < 0)
1584 goto out;
1585
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001586 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001587 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001588
1589 /* stop filterting packets based on bssid */
1590 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001591
1592out:
1593 return ret;
1594}
1595
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001596static void wl1271_set_band_rate(struct wl1271 *wl)
1597{
1598 if (wl->band == IEEE80211_BAND_2GHZ)
1599 wl->basic_rate_set = wl->conf.tx.basic_rate;
1600 else
1601 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1602}
1603
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001604static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001605{
1606 int ret;
1607
1608 if (idle) {
1609 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1610 ret = wl1271_unjoin(wl);
1611 if (ret < 0)
1612 goto out;
1613 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001614 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001615 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001616 if (ret < 0)
1617 goto out;
1618 ret = wl1271_acx_keep_alive_config(
1619 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1620 ACX_KEEP_ALIVE_TPL_INVALID);
1621 if (ret < 0)
1622 goto out;
1623 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1624 } else {
1625 /* increment the session counter */
1626 wl->session_counter++;
1627 if (wl->session_counter >= SESSION_COUNTER_MAX)
1628 wl->session_counter = 0;
1629 ret = wl1271_dummy_join(wl);
1630 if (ret < 0)
1631 goto out;
1632 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1633 }
1634
1635out:
1636 return ret;
1637}
1638
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001639static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1640{
1641 struct wl1271 *wl = hw->priv;
1642 struct ieee80211_conf *conf = &hw->conf;
1643 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001644 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645
1646 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1647
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001648 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1649 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 channel,
1651 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001652 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001653 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1654 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001656 /*
1657 * mac80211 will go to idle nearly immediately after transmitting some
1658 * frames, such as the deauth. To make sure those frames reach the air,
1659 * wait here until the TX queue is fully flushed.
1660 */
1661 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1662 (conf->flags & IEEE80211_CONF_IDLE))
1663 wl1271_tx_flush(wl);
1664
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665 mutex_lock(&wl->mutex);
1666
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001667 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1668 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001669 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001670 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001671
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001672 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1673
Ido Yariva6208652011-03-01 15:14:41 +02001674 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001675 if (ret < 0)
1676 goto out;
1677
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001678 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001679 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1680 ((wl->band != conf->channel->band) ||
1681 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001682 wl->band = conf->channel->band;
1683 wl->channel = channel;
1684
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001685 if (!is_ap) {
1686 /*
1687 * FIXME: the mac80211 should really provide a fixed
1688 * rate to use here. for now, just use the smallest
1689 * possible rate for the band as a fixed rate for
1690 * association frames and other control messages.
1691 */
1692 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1693 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001694
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001695 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1696 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001697 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001698 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001699 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001700
1701 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1702 ret = wl1271_join(wl, false);
1703 if (ret < 0)
1704 wl1271_warning("cmd join on channel "
1705 "failed %d", ret);
1706 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001707 }
1708 }
1709
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001710 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1711 ret = wl1271_sta_handle_idle(wl,
1712 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001713 if (ret < 0)
1714 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715 }
1716
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001717 /*
1718 * if mac80211 changes the PSM mode, make sure the mode is not
1719 * incorrectly changed after the pspoll failure active window.
1720 */
1721 if (changed & IEEE80211_CONF_CHANGE_PS)
1722 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1723
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001724 if (conf->flags & IEEE80211_CONF_PS &&
1725 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1726 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727
1728 /*
1729 * We enter PSM only if we're already associated.
1730 * If we're not, we'll enter it when joining an SSID,
1731 * through the bss_info_changed() hook.
1732 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001733 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001734 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001735 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001736 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001737 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001738 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001739 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001740 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001741
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001742 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001743
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001744 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001745 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001746 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747 }
1748
1749 if (conf->power_level != wl->power_level) {
1750 ret = wl1271_acx_tx_power(wl, conf->power_level);
1751 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001752 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001753
1754 wl->power_level = conf->power_level;
1755 }
1756
1757out_sleep:
1758 wl1271_ps_elp_sleep(wl);
1759
1760out:
1761 mutex_unlock(&wl->mutex);
1762
1763 return ret;
1764}
1765
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001766struct wl1271_filter_params {
1767 bool enabled;
1768 int mc_list_length;
1769 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1770};
1771
Jiri Pirko22bedad2010-04-01 21:22:57 +00001772static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1773 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001774{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001775 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001776 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001777 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001778
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001779 if (unlikely(wl->state == WL1271_STATE_OFF))
1780 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001781
Juuso Oikarinen74441132009-10-13 12:47:53 +03001782 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001783 if (!fp) {
1784 wl1271_error("Out of memory setting filters.");
1785 return 0;
1786 }
1787
1788 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001789 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001790 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1791 fp->enabled = false;
1792 } else {
1793 fp->enabled = true;
1794 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001795 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001796 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001797 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001798 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001799 }
1800
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001801 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001802}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001804#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1805 FIF_ALLMULTI | \
1806 FIF_FCSFAIL | \
1807 FIF_BCN_PRBRESP_PROMISC | \
1808 FIF_CONTROL | \
1809 FIF_OTHER_BSS)
1810
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1812 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001813 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001815 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001817 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818
Arik Nemtsov7d057862010-10-16 19:25:35 +02001819 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1820 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001822 mutex_lock(&wl->mutex);
1823
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001824 *total &= WL1271_SUPPORTED_FILTERS;
1825 changed &= WL1271_SUPPORTED_FILTERS;
1826
1827 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001828 goto out;
1829
Ido Yariva6208652011-03-01 15:14:41 +02001830 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001831 if (ret < 0)
1832 goto out;
1833
Arik Nemtsov7d057862010-10-16 19:25:35 +02001834 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1835 if (*total & FIF_ALLMULTI)
1836 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1837 else if (fp)
1838 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1839 fp->mc_list,
1840 fp->mc_list_length);
1841 if (ret < 0)
1842 goto out_sleep;
1843 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001845 /* determine, whether supported filter values have changed */
1846 if (changed == 0)
1847 goto out_sleep;
1848
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001849 /* configure filters */
1850 wl->filters = *total;
1851 wl1271_configure_filters(wl, 0);
1852
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001853 /* apply configured filters */
1854 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1855 if (ret < 0)
1856 goto out_sleep;
1857
1858out_sleep:
1859 wl1271_ps_elp_sleep(wl);
1860
1861out:
1862 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001863 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001864}
1865
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001866static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1867 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1868 u16 tx_seq_16)
1869{
1870 struct wl1271_ap_key *ap_key;
1871 int i;
1872
1873 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1874
1875 if (key_size > MAX_KEY_SIZE)
1876 return -EINVAL;
1877
1878 /*
1879 * Find next free entry in ap_keys. Also check we are not replacing
1880 * an existing key.
1881 */
1882 for (i = 0; i < MAX_NUM_KEYS; i++) {
1883 if (wl->recorded_ap_keys[i] == NULL)
1884 break;
1885
1886 if (wl->recorded_ap_keys[i]->id == id) {
1887 wl1271_warning("trying to record key replacement");
1888 return -EINVAL;
1889 }
1890 }
1891
1892 if (i == MAX_NUM_KEYS)
1893 return -EBUSY;
1894
1895 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1896 if (!ap_key)
1897 return -ENOMEM;
1898
1899 ap_key->id = id;
1900 ap_key->key_type = key_type;
1901 ap_key->key_size = key_size;
1902 memcpy(ap_key->key, key, key_size);
1903 ap_key->hlid = hlid;
1904 ap_key->tx_seq_32 = tx_seq_32;
1905 ap_key->tx_seq_16 = tx_seq_16;
1906
1907 wl->recorded_ap_keys[i] = ap_key;
1908 return 0;
1909}
1910
1911static void wl1271_free_ap_keys(struct wl1271 *wl)
1912{
1913 int i;
1914
1915 for (i = 0; i < MAX_NUM_KEYS; i++) {
1916 kfree(wl->recorded_ap_keys[i]);
1917 wl->recorded_ap_keys[i] = NULL;
1918 }
1919}
1920
1921static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1922{
1923 int i, ret = 0;
1924 struct wl1271_ap_key *key;
1925 bool wep_key_added = false;
1926
1927 for (i = 0; i < MAX_NUM_KEYS; i++) {
1928 if (wl->recorded_ap_keys[i] == NULL)
1929 break;
1930
1931 key = wl->recorded_ap_keys[i];
1932 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1933 key->id, key->key_type,
1934 key->key_size, key->key,
1935 key->hlid, key->tx_seq_32,
1936 key->tx_seq_16);
1937 if (ret < 0)
1938 goto out;
1939
1940 if (key->key_type == KEY_WEP)
1941 wep_key_added = true;
1942 }
1943
1944 if (wep_key_added) {
1945 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1946 if (ret < 0)
1947 goto out;
1948 }
1949
1950out:
1951 wl1271_free_ap_keys(wl);
1952 return ret;
1953}
1954
1955static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1956 u8 key_size, const u8 *key, u32 tx_seq_32,
1957 u16 tx_seq_16, struct ieee80211_sta *sta)
1958{
1959 int ret;
1960 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1961
1962 if (is_ap) {
1963 struct wl1271_station *wl_sta;
1964 u8 hlid;
1965
1966 if (sta) {
1967 wl_sta = (struct wl1271_station *)sta->drv_priv;
1968 hlid = wl_sta->hlid;
1969 } else {
1970 hlid = WL1271_AP_BROADCAST_HLID;
1971 }
1972
1973 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1974 /*
1975 * We do not support removing keys after AP shutdown.
1976 * Pretend we do to make mac80211 happy.
1977 */
1978 if (action != KEY_ADD_OR_REPLACE)
1979 return 0;
1980
1981 ret = wl1271_record_ap_key(wl, id,
1982 key_type, key_size,
1983 key, hlid, tx_seq_32,
1984 tx_seq_16);
1985 } else {
1986 ret = wl1271_cmd_set_ap_key(wl, action,
1987 id, key_type, key_size,
1988 key, hlid, tx_seq_32,
1989 tx_seq_16);
1990 }
1991
1992 if (ret < 0)
1993 return ret;
1994 } else {
1995 const u8 *addr;
1996 static const u8 bcast_addr[ETH_ALEN] = {
1997 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1998 };
1999
2000 addr = sta ? sta->addr : bcast_addr;
2001
2002 if (is_zero_ether_addr(addr)) {
2003 /* We dont support TX only encryption */
2004 return -EOPNOTSUPP;
2005 }
2006
2007 /* The wl1271 does not allow to remove unicast keys - they
2008 will be cleared automatically on next CMD_JOIN. Ignore the
2009 request silently, as we dont want the mac80211 to emit
2010 an error message. */
2011 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2012 return 0;
2013
2014 ret = wl1271_cmd_set_sta_key(wl, action,
2015 id, key_type, key_size,
2016 key, addr, tx_seq_32,
2017 tx_seq_16);
2018 if (ret < 0)
2019 return ret;
2020
2021 /* the default WEP key needs to be configured at least once */
2022 if (key_type == KEY_WEP) {
2023 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2024 wl->default_key);
2025 if (ret < 0)
2026 return ret;
2027 }
2028 }
2029
2030 return 0;
2031}
2032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2034 struct ieee80211_vif *vif,
2035 struct ieee80211_sta *sta,
2036 struct ieee80211_key_conf *key_conf)
2037{
2038 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002040 u32 tx_seq_32 = 0;
2041 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042 u8 key_type;
2043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2045
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002046 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002048 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 key_conf->keylen, key_conf->flags);
2050 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2051
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 mutex_lock(&wl->mutex);
2053
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002054 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2055 ret = -EAGAIN;
2056 goto out_unlock;
2057 }
2058
Ido Yariva6208652011-03-01 15:14:41 +02002059 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 if (ret < 0)
2061 goto out_unlock;
2062
Johannes Berg97359d12010-08-10 09:46:38 +02002063 switch (key_conf->cipher) {
2064 case WLAN_CIPHER_SUITE_WEP40:
2065 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002066 key_type = KEY_WEP;
2067
2068 key_conf->hw_key_idx = key_conf->keyidx;
2069 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002070 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071 key_type = KEY_TKIP;
2072
2073 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002074 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2075 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002077 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002078 key_type = KEY_AES;
2079
2080 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002081 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2082 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002083 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002084 case WL1271_CIPHER_SUITE_GEM:
2085 key_type = KEY_GEM;
2086 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2087 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2088 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002089 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002090 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002091
2092 ret = -EOPNOTSUPP;
2093 goto out_sleep;
2094 }
2095
2096 switch (cmd) {
2097 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002098 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2099 key_conf->keyidx, key_type,
2100 key_conf->keylen, key_conf->key,
2101 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102 if (ret < 0) {
2103 wl1271_error("Could not add or replace key");
2104 goto out_sleep;
2105 }
2106 break;
2107
2108 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002109 ret = wl1271_set_key(wl, KEY_REMOVE,
2110 key_conf->keyidx, key_type,
2111 key_conf->keylen, key_conf->key,
2112 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113 if (ret < 0) {
2114 wl1271_error("Could not remove key");
2115 goto out_sleep;
2116 }
2117 break;
2118
2119 default:
2120 wl1271_error("Unsupported key cmd 0x%x", cmd);
2121 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122 break;
2123 }
2124
2125out_sleep:
2126 wl1271_ps_elp_sleep(wl);
2127
2128out_unlock:
2129 mutex_unlock(&wl->mutex);
2130
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131 return ret;
2132}
2133
2134static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002135 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002136 struct cfg80211_scan_request *req)
2137{
2138 struct wl1271 *wl = hw->priv;
2139 int ret;
2140 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002141 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142
2143 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2144
2145 if (req->n_ssids) {
2146 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002147 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148 }
2149
2150 mutex_lock(&wl->mutex);
2151
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002152 if (wl->state == WL1271_STATE_OFF) {
2153 /*
2154 * We cannot return -EBUSY here because cfg80211 will expect
2155 * a call to ieee80211_scan_completed if we do - in this case
2156 * there won't be any call.
2157 */
2158 ret = -EAGAIN;
2159 goto out;
2160 }
2161
Ido Yariva6208652011-03-01 15:14:41 +02002162 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 if (ret < 0)
2164 goto out;
2165
Luciano Coelho5924f892010-08-04 03:46:22 +03002166 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167
2168 wl1271_ps_elp_sleep(wl);
2169
2170out:
2171 mutex_unlock(&wl->mutex);
2172
2173 return ret;
2174}
2175
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002176static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2177{
2178 struct wl1271 *wl = hw->priv;
2179 int ret = 0;
2180
2181 mutex_lock(&wl->mutex);
2182
2183 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2184 ret = -EAGAIN;
2185 goto out;
2186 }
2187
Ido Yariva6208652011-03-01 15:14:41 +02002188 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002189 if (ret < 0)
2190 goto out;
2191
2192 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2193 if (ret < 0)
2194 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2195
2196 wl1271_ps_elp_sleep(wl);
2197
2198out:
2199 mutex_unlock(&wl->mutex);
2200
2201 return ret;
2202}
2203
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2205{
2206 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002207 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208
2209 mutex_lock(&wl->mutex);
2210
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002211 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2212 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002213 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002214 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002215
Ido Yariva6208652011-03-01 15:14:41 +02002216 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 if (ret < 0)
2218 goto out;
2219
2220 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2221 if (ret < 0)
2222 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2223
2224 wl1271_ps_elp_sleep(wl);
2225
2226out:
2227 mutex_unlock(&wl->mutex);
2228
2229 return ret;
2230}
2231
Arik Nemtsove78a2872010-10-16 19:07:21 +02002232static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002233 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002234{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002235 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002236
2237 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002238 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002239 if (ptr[0] == WLAN_EID_SSID) {
2240 wl->ssid_len = ptr[1];
2241 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002242 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002243 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002244 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002245 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002246
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002247 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002248 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002249}
2250
Arik Nemtsove78a2872010-10-16 19:07:21 +02002251static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2252 struct ieee80211_bss_conf *bss_conf,
2253 u32 changed)
2254{
2255 int ret = 0;
2256
2257 if (changed & BSS_CHANGED_ERP_SLOT) {
2258 if (bss_conf->use_short_slot)
2259 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2260 else
2261 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2262 if (ret < 0) {
2263 wl1271_warning("Set slot time failed %d", ret);
2264 goto out;
2265 }
2266 }
2267
2268 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2269 if (bss_conf->use_short_preamble)
2270 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2271 else
2272 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2273 }
2274
2275 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2276 if (bss_conf->use_cts_prot)
2277 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2278 else
2279 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2280 if (ret < 0) {
2281 wl1271_warning("Set ctsprotect failed %d", ret);
2282 goto out;
2283 }
2284 }
2285
2286out:
2287 return ret;
2288}
2289
2290static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2291 struct ieee80211_vif *vif,
2292 struct ieee80211_bss_conf *bss_conf,
2293 u32 changed)
2294{
2295 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2296 int ret = 0;
2297
2298 if ((changed & BSS_CHANGED_BEACON_INT)) {
2299 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2300 bss_conf->beacon_int);
2301
2302 wl->beacon_int = bss_conf->beacon_int;
2303 }
2304
2305 if ((changed & BSS_CHANGED_BEACON)) {
2306 struct ieee80211_hdr *hdr;
2307 int ieoffset = offsetof(struct ieee80211_mgmt,
2308 u.beacon.variable);
2309 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2310 u16 tmpl_id;
2311
2312 if (!beacon)
2313 goto out;
2314
2315 wl1271_debug(DEBUG_MASTER, "beacon updated");
2316
2317 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2318 if (ret < 0) {
2319 dev_kfree_skb(beacon);
2320 goto out;
2321 }
2322 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2323 CMD_TEMPL_BEACON;
2324 ret = wl1271_cmd_template_set(wl, tmpl_id,
2325 beacon->data,
2326 beacon->len, 0,
2327 wl1271_tx_min_rate_get(wl));
2328 if (ret < 0) {
2329 dev_kfree_skb(beacon);
2330 goto out;
2331 }
2332
2333 hdr = (struct ieee80211_hdr *) beacon->data;
2334 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2335 IEEE80211_STYPE_PROBE_RESP);
2336
2337 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2338 CMD_TEMPL_PROBE_RESPONSE;
2339 ret = wl1271_cmd_template_set(wl,
2340 tmpl_id,
2341 beacon->data,
2342 beacon->len, 0,
2343 wl1271_tx_min_rate_get(wl));
2344 dev_kfree_skb(beacon);
2345 if (ret < 0)
2346 goto out;
2347 }
2348
2349out:
2350 return ret;
2351}
2352
2353/* AP mode changes */
2354static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355 struct ieee80211_vif *vif,
2356 struct ieee80211_bss_conf *bss_conf,
2357 u32 changed)
2358{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002359 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360
Arik Nemtsove78a2872010-10-16 19:07:21 +02002361 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2362 u32 rates = bss_conf->basic_rates;
2363 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364
Arik Nemtsove78a2872010-10-16 19:07:21 +02002365 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2366 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2367 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2368 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369
Arik Nemtsove78a2872010-10-16 19:07:21 +02002370 /* update the AP management rate policy with the new rates */
2371 mgmt_rc.enabled_rates = wl->basic_rate_set;
2372 mgmt_rc.long_retry_limit = 10;
2373 mgmt_rc.short_retry_limit = 10;
2374 mgmt_rc.aflags = 0;
2375 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2376 ACX_TX_AP_MODE_MGMT_RATE);
2377 if (ret < 0) {
2378 wl1271_error("AP mgmt policy change failed %d", ret);
2379 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002380 }
2381 }
2382
Arik Nemtsove78a2872010-10-16 19:07:21 +02002383 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2384 if (ret < 0)
2385 goto out;
2386
2387 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2388 if (bss_conf->enable_beacon) {
2389 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2390 ret = wl1271_cmd_start_bss(wl);
2391 if (ret < 0)
2392 goto out;
2393
2394 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2395 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002396
2397 ret = wl1271_ap_init_hwenc(wl);
2398 if (ret < 0)
2399 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002400 }
2401 } else {
2402 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2403 ret = wl1271_cmd_stop_bss(wl);
2404 if (ret < 0)
2405 goto out;
2406
2407 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2408 wl1271_debug(DEBUG_AP, "stopped AP");
2409 }
2410 }
2411 }
2412
2413 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2414 if (ret < 0)
2415 goto out;
2416out:
2417 return;
2418}
2419
2420/* STA/IBSS mode changes */
2421static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2422 struct ieee80211_vif *vif,
2423 struct ieee80211_bss_conf *bss_conf,
2424 u32 changed)
2425{
2426 bool do_join = false, set_assoc = false;
2427 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002428 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002429 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002430 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002431 bool sta_exists = false;
2432 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002433
2434 if (is_ibss) {
2435 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2436 changed);
2437 if (ret < 0)
2438 goto out;
2439 }
2440
2441 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2442 do_join = true;
2443
2444 /* Need to update the SSID (for filtering etc) */
2445 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2446 do_join = true;
2447
2448 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002449 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2450 bss_conf->enable_beacon ? "enabled" : "disabled");
2451
2452 if (bss_conf->enable_beacon)
2453 wl->set_bss_type = BSS_TYPE_IBSS;
2454 else
2455 wl->set_bss_type = BSS_TYPE_STA_BSS;
2456 do_join = true;
2457 }
2458
Arik Nemtsove78a2872010-10-16 19:07:21 +02002459 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002460 bool enable = false;
2461 if (bss_conf->cqm_rssi_thold)
2462 enable = true;
2463 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2464 bss_conf->cqm_rssi_thold,
2465 bss_conf->cqm_rssi_hyst);
2466 if (ret < 0)
2467 goto out;
2468 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2469 }
2470
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002471 if ((changed & BSS_CHANGED_BSSID) &&
2472 /*
2473 * Now we know the correct bssid, so we send a new join command
2474 * and enable the BSSID filter
2475 */
2476 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002477 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002478
Eliad Pellerfa287b82010-12-26 09:27:50 +01002479 if (!is_zero_ether_addr(wl->bssid)) {
2480 ret = wl1271_cmd_build_null_data(wl);
2481 if (ret < 0)
2482 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002483
Eliad Pellerfa287b82010-12-26 09:27:50 +01002484 ret = wl1271_build_qos_null_data(wl);
2485 if (ret < 0)
2486 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002487
Eliad Pellerfa287b82010-12-26 09:27:50 +01002488 /* filter out all packets not from this BSSID */
2489 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002490
Eliad Pellerfa287b82010-12-26 09:27:50 +01002491 /* Need to update the BSSID (for filtering etc) */
2492 do_join = true;
2493 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002494 }
2495
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002496 rcu_read_lock();
2497 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2498 if (sta) {
2499 /* save the supp_rates of the ap */
2500 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2501 if (sta->ht_cap.ht_supported)
2502 sta_rate_set |=
2503 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002504 sta_ht_cap = sta->ht_cap;
2505 sta_exists = true;
2506 }
2507 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002508
Arik Nemtsova1008852011-02-12 23:24:20 +02002509 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002510 /* handle new association with HT and HT information change */
2511 if ((changed & BSS_CHANGED_HT) &&
2512 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002513 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002514 true);
2515 if (ret < 0) {
2516 wl1271_warning("Set ht cap true failed %d",
2517 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002518 goto out;
2519 }
2520 ret = wl1271_acx_set_ht_information(wl,
2521 bss_conf->ht_operation_mode);
2522 if (ret < 0) {
2523 wl1271_warning("Set ht information failed %d",
2524 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002525 goto out;
2526 }
2527 }
2528 /* handle new association without HT and disassociation */
2529 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002530 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002531 false);
2532 if (ret < 0) {
2533 wl1271_warning("Set ht cap false failed %d",
2534 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002535 goto out;
2536 }
2537 }
2538 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002539
Arik Nemtsove78a2872010-10-16 19:07:21 +02002540 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002542 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002543 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002545 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002546
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002547 wl->ps_poll_failures = 0;
2548
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002549 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002550 * use basic rates from AP, and determine lowest rate
2551 * to use with control frames.
2552 */
2553 rates = bss_conf->basic_rates;
2554 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2555 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002556 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002557 if (sta_rate_set)
2558 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2559 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002560 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002561 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002562 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002563
2564 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002565 * with wl1271, we don't need to update the
2566 * beacon_int and dtim_period, because the firmware
2567 * updates it by itself when the first beacon is
2568 * received after a join.
2569 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002570 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2571 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002572 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002573
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002574 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002575 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002576 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002577 dev_kfree_skb(wl->probereq);
2578 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2579 ieoffset = offsetof(struct ieee80211_mgmt,
2580 u.probe_req.variable);
2581 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002582
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002583 /* enable the connection monitoring feature */
2584 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002585 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002586 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587
2588 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002589 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2590 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002591 enum wl1271_cmd_ps_mode mode;
2592
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002593 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002594 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002595 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002596 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002597 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002598 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002600 } else {
2601 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002602 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002603 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002604 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002605
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002606 /* free probe-request template */
2607 dev_kfree_skb(wl->probereq);
2608 wl->probereq = NULL;
2609
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002610 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002611 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002612
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002613 /* revert back to minimum rates for the current band */
2614 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002615 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002616 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002617 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002618 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002619
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002620 /* disable connection monitor features */
2621 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002622
2623 /* Disable the keep-alive feature */
2624 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002625 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002626 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002627
2628 /* restore the bssid filter and go to dummy bssid */
2629 wl1271_unjoin(wl);
2630 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002631 }
2632 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002633
Arik Nemtsove78a2872010-10-16 19:07:21 +02002634 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2635 if (ret < 0)
2636 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002638 if (changed & BSS_CHANGED_ARP_FILTER) {
2639 __be32 addr = bss_conf->arp_addr_list[0];
2640 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2641
Eliad Pellerc5312772010-12-09 11:31:27 +02002642 if (bss_conf->arp_addr_cnt == 1 &&
2643 bss_conf->arp_filter_enabled) {
2644 /*
2645 * The template should have been configured only upon
2646 * association. however, it seems that the correct ip
2647 * isn't being set (when sending), so we have to
2648 * reconfigure the template upon every ip change.
2649 */
2650 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2651 if (ret < 0) {
2652 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002653 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002654 }
2655
2656 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002657 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002658 addr);
2659 } else
2660 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002661
2662 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002663 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002664 }
2665
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002666 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002667 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002668 if (ret < 0) {
2669 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002670 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002671 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002672 }
2673
Arik Nemtsove78a2872010-10-16 19:07:21 +02002674out:
2675 return;
2676}
2677
2678static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2679 struct ieee80211_vif *vif,
2680 struct ieee80211_bss_conf *bss_conf,
2681 u32 changed)
2682{
2683 struct wl1271 *wl = hw->priv;
2684 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2685 int ret;
2686
2687 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2688 (int)changed);
2689
2690 mutex_lock(&wl->mutex);
2691
2692 if (unlikely(wl->state == WL1271_STATE_OFF))
2693 goto out;
2694
Ido Yariva6208652011-03-01 15:14:41 +02002695 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002696 if (ret < 0)
2697 goto out;
2698
2699 if (is_ap)
2700 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2701 else
2702 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2703
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704 wl1271_ps_elp_sleep(wl);
2705
2706out:
2707 mutex_unlock(&wl->mutex);
2708}
2709
Kalle Valoc6999d82010-02-18 13:25:41 +02002710static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2711 const struct ieee80211_tx_queue_params *params)
2712{
2713 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002714 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002715 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002716
2717 mutex_lock(&wl->mutex);
2718
2719 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2720
Kalle Valo4695dc92010-03-18 12:26:38 +02002721 if (params->uapsd)
2722 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2723 else
2724 ps_scheme = CONF_PS_SCHEME_LEGACY;
2725
Arik Nemtsov488fc542010-10-16 20:33:45 +02002726 if (wl->state == WL1271_STATE_OFF) {
2727 /*
2728 * If the state is off, the parameters will be recorded and
2729 * configured on init. This happens in AP-mode.
2730 */
2731 struct conf_tx_ac_category *conf_ac =
2732 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2733 struct conf_tx_tid *conf_tid =
2734 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2735
2736 conf_ac->ac = wl1271_tx_get_queue(queue);
2737 conf_ac->cw_min = (u8)params->cw_min;
2738 conf_ac->cw_max = params->cw_max;
2739 conf_ac->aifsn = params->aifs;
2740 conf_ac->tx_op_limit = params->txop << 5;
2741
2742 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2743 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2744 conf_tid->tsid = wl1271_tx_get_queue(queue);
2745 conf_tid->ps_scheme = ps_scheme;
2746 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2747 conf_tid->apsd_conf[0] = 0;
2748 conf_tid->apsd_conf[1] = 0;
2749 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002750 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002751 if (ret < 0)
2752 goto out;
2753
2754 /*
2755 * the txop is confed in units of 32us by the mac80211,
2756 * we need us
2757 */
2758 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2759 params->cw_min, params->cw_max,
2760 params->aifs, params->txop << 5);
2761 if (ret < 0)
2762 goto out_sleep;
2763
2764 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2765 CONF_CHANNEL_TYPE_EDCF,
2766 wl1271_tx_get_queue(queue),
2767 ps_scheme, CONF_ACK_POLICY_LEGACY,
2768 0, 0);
2769 if (ret < 0)
2770 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002771
2772out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002773 wl1271_ps_elp_sleep(wl);
2774 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002775
2776out:
2777 mutex_unlock(&wl->mutex);
2778
2779 return ret;
2780}
2781
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002782static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2783{
2784
2785 struct wl1271 *wl = hw->priv;
2786 u64 mactime = ULLONG_MAX;
2787 int ret;
2788
2789 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2790
2791 mutex_lock(&wl->mutex);
2792
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002793 if (unlikely(wl->state == WL1271_STATE_OFF))
2794 goto out;
2795
Ido Yariva6208652011-03-01 15:14:41 +02002796 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002797 if (ret < 0)
2798 goto out;
2799
2800 ret = wl1271_acx_tsf_info(wl, &mactime);
2801 if (ret < 0)
2802 goto out_sleep;
2803
2804out_sleep:
2805 wl1271_ps_elp_sleep(wl);
2806
2807out:
2808 mutex_unlock(&wl->mutex);
2809 return mactime;
2810}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811
John W. Linvilleece550d2010-07-28 16:41:06 -04002812static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2813 struct survey_info *survey)
2814{
2815 struct wl1271 *wl = hw->priv;
2816 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002817
John W. Linvilleece550d2010-07-28 16:41:06 -04002818 if (idx != 0)
2819 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002820
John W. Linvilleece550d2010-07-28 16:41:06 -04002821 survey->channel = conf->channel;
2822 survey->filled = SURVEY_INFO_NOISE_DBM;
2823 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002824
John W. Linvilleece550d2010-07-28 16:41:06 -04002825 return 0;
2826}
2827
Arik Nemtsov409622e2011-02-23 00:22:29 +02002828static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002829 struct ieee80211_sta *sta,
2830 u8 *hlid)
2831{
2832 struct wl1271_station *wl_sta;
2833 int id;
2834
2835 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2836 if (id >= AP_MAX_STATIONS) {
2837 wl1271_warning("could not allocate HLID - too much stations");
2838 return -EBUSY;
2839 }
2840
2841 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002842 __set_bit(id, wl->ap_hlid_map);
2843 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2844 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002845 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002846 return 0;
2847}
2848
Arik Nemtsov409622e2011-02-23 00:22:29 +02002849static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002850{
2851 int id = hlid - WL1271_AP_STA_HLID_START;
2852
Arik Nemtsov409622e2011-02-23 00:22:29 +02002853 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2854 return;
2855
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002856 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002857 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002858 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002859 __clear_bit(hlid, &wl->ap_ps_map);
2860 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002861}
2862
2863static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2864 struct ieee80211_vif *vif,
2865 struct ieee80211_sta *sta)
2866{
2867 struct wl1271 *wl = hw->priv;
2868 int ret = 0;
2869 u8 hlid;
2870
2871 mutex_lock(&wl->mutex);
2872
2873 if (unlikely(wl->state == WL1271_STATE_OFF))
2874 goto out;
2875
2876 if (wl->bss_type != BSS_TYPE_AP_BSS)
2877 goto out;
2878
2879 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2880
Arik Nemtsov409622e2011-02-23 00:22:29 +02002881 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002882 if (ret < 0)
2883 goto out;
2884
Ido Yariva6208652011-03-01 15:14:41 +02002885 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002886 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002887 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002888
2889 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2890 if (ret < 0)
2891 goto out_sleep;
2892
2893out_sleep:
2894 wl1271_ps_elp_sleep(wl);
2895
Arik Nemtsov409622e2011-02-23 00:22:29 +02002896out_free_sta:
2897 if (ret < 0)
2898 wl1271_free_sta(wl, hlid);
2899
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002900out:
2901 mutex_unlock(&wl->mutex);
2902 return ret;
2903}
2904
2905static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2906 struct ieee80211_vif *vif,
2907 struct ieee80211_sta *sta)
2908{
2909 struct wl1271 *wl = hw->priv;
2910 struct wl1271_station *wl_sta;
2911 int ret = 0, id;
2912
2913 mutex_lock(&wl->mutex);
2914
2915 if (unlikely(wl->state == WL1271_STATE_OFF))
2916 goto out;
2917
2918 if (wl->bss_type != BSS_TYPE_AP_BSS)
2919 goto out;
2920
2921 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2922
2923 wl_sta = (struct wl1271_station *)sta->drv_priv;
2924 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2925 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2926 goto out;
2927
Ido Yariva6208652011-03-01 15:14:41 +02002928 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002929 if (ret < 0)
2930 goto out;
2931
2932 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2933 if (ret < 0)
2934 goto out_sleep;
2935
Arik Nemtsov409622e2011-02-23 00:22:29 +02002936 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002937
2938out_sleep:
2939 wl1271_ps_elp_sleep(wl);
2940
2941out:
2942 mutex_unlock(&wl->mutex);
2943 return ret;
2944}
2945
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002946int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002947 enum ieee80211_ampdu_mlme_action action,
2948 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2949 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002950{
2951 struct wl1271 *wl = hw->priv;
2952 int ret;
2953
2954 mutex_lock(&wl->mutex);
2955
2956 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2957 ret = -EAGAIN;
2958 goto out;
2959 }
2960
Ido Yariva6208652011-03-01 15:14:41 +02002961 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002962 if (ret < 0)
2963 goto out;
2964
2965 switch (action) {
2966 case IEEE80211_AMPDU_RX_START:
2967 if (wl->ba_support) {
2968 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2969 true);
2970 if (!ret)
2971 wl->ba_rx_bitmap |= BIT(tid);
2972 } else {
2973 ret = -ENOTSUPP;
2974 }
2975 break;
2976
2977 case IEEE80211_AMPDU_RX_STOP:
2978 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2979 if (!ret)
2980 wl->ba_rx_bitmap &= ~BIT(tid);
2981 break;
2982
2983 /*
2984 * The BA initiator session management in FW independently.
2985 * Falling break here on purpose for all TX APDU commands.
2986 */
2987 case IEEE80211_AMPDU_TX_START:
2988 case IEEE80211_AMPDU_TX_STOP:
2989 case IEEE80211_AMPDU_TX_OPERATIONAL:
2990 ret = -EINVAL;
2991 break;
2992
2993 default:
2994 wl1271_error("Incorrect ampdu action id=%x\n", action);
2995 ret = -EINVAL;
2996 }
2997
2998 wl1271_ps_elp_sleep(wl);
2999
3000out:
3001 mutex_unlock(&wl->mutex);
3002
3003 return ret;
3004}
3005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006/* can't be const, mac80211 writes to this */
3007static struct ieee80211_rate wl1271_rates[] = {
3008 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003009 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3010 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003011 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003012 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3013 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003014 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3015 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003016 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3017 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3019 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003020 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3021 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3023 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003024 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3025 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003026 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003027 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3028 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003030 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3031 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003033 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3034 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003036 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3037 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003039 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3040 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003042 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3043 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003045 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3046 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047};
3048
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003049/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003051 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003052 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003053 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3054 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3055 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003056 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003057 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3058 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3059 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003060 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003061 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3062 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3063 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003064 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003065};
3066
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003067/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003068static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003069 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003070 7, /* CONF_HW_RXTX_RATE_MCS7 */
3071 6, /* CONF_HW_RXTX_RATE_MCS6 */
3072 5, /* CONF_HW_RXTX_RATE_MCS5 */
3073 4, /* CONF_HW_RXTX_RATE_MCS4 */
3074 3, /* CONF_HW_RXTX_RATE_MCS3 */
3075 2, /* CONF_HW_RXTX_RATE_MCS2 */
3076 1, /* CONF_HW_RXTX_RATE_MCS1 */
3077 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003078
3079 11, /* CONF_HW_RXTX_RATE_54 */
3080 10, /* CONF_HW_RXTX_RATE_48 */
3081 9, /* CONF_HW_RXTX_RATE_36 */
3082 8, /* CONF_HW_RXTX_RATE_24 */
3083
3084 /* TI-specific rate */
3085 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3086
3087 7, /* CONF_HW_RXTX_RATE_18 */
3088 6, /* CONF_HW_RXTX_RATE_12 */
3089 3, /* CONF_HW_RXTX_RATE_11 */
3090 5, /* CONF_HW_RXTX_RATE_9 */
3091 4, /* CONF_HW_RXTX_RATE_6 */
3092 2, /* CONF_HW_RXTX_RATE_5_5 */
3093 1, /* CONF_HW_RXTX_RATE_2 */
3094 0 /* CONF_HW_RXTX_RATE_1 */
3095};
3096
Shahar Levie8b03a22010-10-13 16:09:39 +02003097/* 11n STA capabilities */
3098#define HW_RX_HIGHEST_RATE 72
3099
Shahar Levi00d20102010-11-08 11:20:10 +00003100#ifdef CONFIG_WL12XX_HT
3101#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003102 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3103 .ht_supported = true, \
3104 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3105 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3106 .mcs = { \
3107 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3108 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3109 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3110 }, \
3111}
Shahar Levi18357852010-10-13 16:09:41 +02003112#else
Shahar Levi00d20102010-11-08 11:20:10 +00003113#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003114 .ht_supported = false, \
3115}
3116#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003117
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003118/* can't be const, mac80211 writes to this */
3119static struct ieee80211_supported_band wl1271_band_2ghz = {
3120 .channels = wl1271_channels,
3121 .n_channels = ARRAY_SIZE(wl1271_channels),
3122 .bitrates = wl1271_rates,
3123 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003124 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003125};
3126
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003127/* 5 GHz data rates for WL1273 */
3128static struct ieee80211_rate wl1271_rates_5ghz[] = {
3129 { .bitrate = 60,
3130 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3131 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3132 { .bitrate = 90,
3133 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3134 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3135 { .bitrate = 120,
3136 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3137 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3138 { .bitrate = 180,
3139 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3141 { .bitrate = 240,
3142 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3143 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3144 { .bitrate = 360,
3145 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3146 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3147 { .bitrate = 480,
3148 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3149 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3150 { .bitrate = 540,
3151 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3152 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3153};
3154
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003155/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003156static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003157 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003158 { .hw_value = 8, .center_freq = 5040},
3159 { .hw_value = 9, .center_freq = 5045},
3160 { .hw_value = 11, .center_freq = 5055},
3161 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003162 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003163 { .hw_value = 34, .center_freq = 5170},
3164 { .hw_value = 36, .center_freq = 5180},
3165 { .hw_value = 38, .center_freq = 5190},
3166 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003167 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003168 { .hw_value = 44, .center_freq = 5220},
3169 { .hw_value = 46, .center_freq = 5230},
3170 { .hw_value = 48, .center_freq = 5240},
3171 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003172 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003173 { .hw_value = 60, .center_freq = 5300},
3174 { .hw_value = 64, .center_freq = 5320},
3175 { .hw_value = 100, .center_freq = 5500},
3176 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003177 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003178 { .hw_value = 112, .center_freq = 5560},
3179 { .hw_value = 116, .center_freq = 5580},
3180 { .hw_value = 120, .center_freq = 5600},
3181 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003182 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003183 { .hw_value = 132, .center_freq = 5660},
3184 { .hw_value = 136, .center_freq = 5680},
3185 { .hw_value = 140, .center_freq = 5700},
3186 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003187 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003188 { .hw_value = 157, .center_freq = 5785},
3189 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003190 { .hw_value = 165, .center_freq = 5825},
3191};
3192
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003193/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003194static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003195 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003196 7, /* CONF_HW_RXTX_RATE_MCS7 */
3197 6, /* CONF_HW_RXTX_RATE_MCS6 */
3198 5, /* CONF_HW_RXTX_RATE_MCS5 */
3199 4, /* CONF_HW_RXTX_RATE_MCS4 */
3200 3, /* CONF_HW_RXTX_RATE_MCS3 */
3201 2, /* CONF_HW_RXTX_RATE_MCS2 */
3202 1, /* CONF_HW_RXTX_RATE_MCS1 */
3203 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003204
3205 7, /* CONF_HW_RXTX_RATE_54 */
3206 6, /* CONF_HW_RXTX_RATE_48 */
3207 5, /* CONF_HW_RXTX_RATE_36 */
3208 4, /* CONF_HW_RXTX_RATE_24 */
3209
3210 /* TI-specific rate */
3211 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3212
3213 3, /* CONF_HW_RXTX_RATE_18 */
3214 2, /* CONF_HW_RXTX_RATE_12 */
3215 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3216 1, /* CONF_HW_RXTX_RATE_9 */
3217 0, /* CONF_HW_RXTX_RATE_6 */
3218 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3219 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3220 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3221};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003222
3223static struct ieee80211_supported_band wl1271_band_5ghz = {
3224 .channels = wl1271_channels_5ghz,
3225 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3226 .bitrates = wl1271_rates_5ghz,
3227 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003228 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003229};
3230
Tobias Klausera0ea9492010-05-20 10:38:11 +02003231static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003232 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3233 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3234};
3235
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236static const struct ieee80211_ops wl1271_ops = {
3237 .start = wl1271_op_start,
3238 .stop = wl1271_op_stop,
3239 .add_interface = wl1271_op_add_interface,
3240 .remove_interface = wl1271_op_remove_interface,
3241 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003242 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243 .configure_filter = wl1271_op_configure_filter,
3244 .tx = wl1271_op_tx,
3245 .set_key = wl1271_op_set_key,
3246 .hw_scan = wl1271_op_hw_scan,
3247 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003248 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003249 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003250 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003251 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003252 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003253 .sta_add = wl1271_op_sta_add,
3254 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003255 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003256 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003257};
3258
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003259
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003260u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003261{
3262 u8 idx;
3263
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003264 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003265
3266 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3267 wl1271_error("Illegal RX rate from HW: %d", rate);
3268 return 0;
3269 }
3270
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003271 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003272 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3273 wl1271_error("Unsupported RX rate from HW: %d", rate);
3274 return 0;
3275 }
3276
3277 return idx;
3278}
3279
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003280static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3281 struct device_attribute *attr,
3282 char *buf)
3283{
3284 struct wl1271 *wl = dev_get_drvdata(dev);
3285 ssize_t len;
3286
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003287 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003288
3289 mutex_lock(&wl->mutex);
3290 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3291 wl->sg_enabled);
3292 mutex_unlock(&wl->mutex);
3293
3294 return len;
3295
3296}
3297
3298static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3299 struct device_attribute *attr,
3300 const char *buf, size_t count)
3301{
3302 struct wl1271 *wl = dev_get_drvdata(dev);
3303 unsigned long res;
3304 int ret;
3305
3306 ret = strict_strtoul(buf, 10, &res);
3307
3308 if (ret < 0) {
3309 wl1271_warning("incorrect value written to bt_coex_mode");
3310 return count;
3311 }
3312
3313 mutex_lock(&wl->mutex);
3314
3315 res = !!res;
3316
3317 if (res == wl->sg_enabled)
3318 goto out;
3319
3320 wl->sg_enabled = res;
3321
3322 if (wl->state == WL1271_STATE_OFF)
3323 goto out;
3324
Ido Yariva6208652011-03-01 15:14:41 +02003325 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003326 if (ret < 0)
3327 goto out;
3328
3329 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3330 wl1271_ps_elp_sleep(wl);
3331
3332 out:
3333 mutex_unlock(&wl->mutex);
3334 return count;
3335}
3336
3337static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3338 wl1271_sysfs_show_bt_coex_state,
3339 wl1271_sysfs_store_bt_coex_state);
3340
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003341static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3342 struct device_attribute *attr,
3343 char *buf)
3344{
3345 struct wl1271 *wl = dev_get_drvdata(dev);
3346 ssize_t len;
3347
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003348 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003349
3350 mutex_lock(&wl->mutex);
3351 if (wl->hw_pg_ver >= 0)
3352 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3353 else
3354 len = snprintf(buf, len, "n/a\n");
3355 mutex_unlock(&wl->mutex);
3356
3357 return len;
3358}
3359
3360static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3361 wl1271_sysfs_show_hw_pg_ver, NULL);
3362
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003363int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003364{
3365 int ret;
3366
3367 if (wl->mac80211_registered)
3368 return 0;
3369
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003370 ret = wl1271_fetch_nvs(wl);
3371 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003372 /* NOTE: The wl->nvs->nvs element must be first, in
3373 * order to simplify the casting, we assume it is at
3374 * the beginning of the wl->nvs structure.
3375 */
3376 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003377
3378 wl->mac_addr[0] = nvs_ptr[11];
3379 wl->mac_addr[1] = nvs_ptr[10];
3380 wl->mac_addr[2] = nvs_ptr[6];
3381 wl->mac_addr[3] = nvs_ptr[5];
3382 wl->mac_addr[4] = nvs_ptr[4];
3383 wl->mac_addr[5] = nvs_ptr[3];
3384 }
3385
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003386 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3387
3388 ret = ieee80211_register_hw(wl->hw);
3389 if (ret < 0) {
3390 wl1271_error("unable to register mac80211 hw: %d", ret);
3391 return ret;
3392 }
3393
3394 wl->mac80211_registered = true;
3395
Eliad Pellerd60080a2010-11-24 12:53:16 +02003396 wl1271_debugfs_init(wl);
3397
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003398 register_netdevice_notifier(&wl1271_dev_notifier);
3399
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003400 wl1271_notice("loaded");
3401
3402 return 0;
3403}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003404EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003405
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003406void wl1271_unregister_hw(struct wl1271 *wl)
3407{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003408 if (wl->state == WL1271_STATE_PLT)
3409 __wl1271_plt_stop(wl);
3410
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003411 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003412 ieee80211_unregister_hw(wl->hw);
3413 wl->mac80211_registered = false;
3414
3415}
3416EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3417
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003418int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003420 static const u32 cipher_suites[] = {
3421 WLAN_CIPHER_SUITE_WEP40,
3422 WLAN_CIPHER_SUITE_WEP104,
3423 WLAN_CIPHER_SUITE_TKIP,
3424 WLAN_CIPHER_SUITE_CCMP,
3425 WL1271_CIPHER_SUITE_GEM,
3426 };
3427
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003428 /* The tx descriptor buffer and the TKIP space. */
3429 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3430 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003431
3432 /* unit us */
3433 /* FIXME: find a proper value */
3434 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003435 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003436
3437 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003438 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003439 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003440 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003441 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003442 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003443 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003444 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3445 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003447 wl->hw->wiphy->cipher_suites = cipher_suites;
3448 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3449
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003450 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003451 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003452 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003453 /*
3454 * Maximum length of elements in scanning probe request templates
3455 * should be the maximum length possible for a template, without
3456 * the IEEE80211 header of the template
3457 */
3458 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3459 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003460
3461 /*
3462 * We keep local copies of the band structs because we need to
3463 * modify them on a per-device basis.
3464 */
3465 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3466 sizeof(wl1271_band_2ghz));
3467 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3468 sizeof(wl1271_band_5ghz));
3469
3470 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3471 &wl->bands[IEEE80211_BAND_2GHZ];
3472 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3473 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003474
Kalle Valo12bd8942010-03-18 12:26:33 +02003475 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003476 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003477
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003478 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3479
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003480 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003481
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003482 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3483
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003484 wl->hw->max_rx_aggregation_subframes = 8;
3485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003486 return 0;
3487}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003488EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003489
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003490#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003491
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003492struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003493{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003494 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003495 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003496 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003497 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003498 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499
3500 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3501 if (!hw) {
3502 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003503 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003504 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505 }
3506
Julia Lawall929ebd32010-05-15 23:16:39 +02003507 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003508 if (!plat_dev) {
3509 wl1271_error("could not allocate platform_device");
3510 ret = -ENOMEM;
3511 goto err_plat_alloc;
3512 }
3513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514 wl = hw->priv;
3515 memset(wl, 0, sizeof(*wl));
3516
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003517 INIT_LIST_HEAD(&wl->list);
3518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003519 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003520 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003521
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003522 for (i = 0; i < NUM_TX_QUEUES; i++)
3523 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003524
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003525 for (i = 0; i < NUM_TX_QUEUES; i++)
3526 for (j = 0; j < AP_MAX_LINKS; j++)
3527 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3528
Ido Yariva6208652011-03-01 15:14:41 +02003529 skb_queue_head_init(&wl->deferred_rx_queue);
3530 skb_queue_head_init(&wl->deferred_tx_queue);
3531
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003532 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003533 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003534 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003535 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3536 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3537 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003539 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003541 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003542 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3543 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003544 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003545 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003546 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003547 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003548 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003549 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003550 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003551 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003552 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003553 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003554 wl->bss_type = MAX_BSS_TYPE;
3555 wl->set_bss_type = MAX_BSS_TYPE;
3556 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003557 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003558 wl->ap_ps_map = 0;
3559 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003560 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003561 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003562
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003563 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003564 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003565 wl->tx_frames[i] = NULL;
3566
3567 spin_lock_init(&wl->wl_lock);
3568
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003569 wl->state = WL1271_STATE_OFF;
3570 mutex_init(&wl->mutex);
3571
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003572 /* Apply default driver configuration. */
3573 wl1271_conf_init(wl);
3574
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003575 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3576 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3577 if (!wl->aggr_buf) {
3578 ret = -ENOMEM;
3579 goto err_hw;
3580 }
3581
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003582 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003583 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003584 if (ret) {
3585 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003586 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003587 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003588 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003589
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003590 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003591 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003592 if (ret < 0) {
3593 wl1271_error("failed to create sysfs file bt_coex_state");
3594 goto err_platform;
3595 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003596
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003597 /* Create sysfs file to get HW PG version */
3598 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3599 if (ret < 0) {
3600 wl1271_error("failed to create sysfs file hw_pg_ver");
3601 goto err_bt_coex_state;
3602 }
3603
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003604 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003605
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003606err_bt_coex_state:
3607 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3608
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003609err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003610 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003611
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003612err_aggr:
3613 free_pages((unsigned long)wl->aggr_buf, order);
3614
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003615err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003616 wl1271_debugfs_exit(wl);
3617 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003618
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003619err_plat_alloc:
3620 ieee80211_free_hw(hw);
3621
3622err_hw_alloc:
3623
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003624 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003625}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003626EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003627
3628int wl1271_free_hw(struct wl1271 *wl)
3629{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003630 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003631 free_pages((unsigned long)wl->aggr_buf,
3632 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003633 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003634
3635 wl1271_debugfs_exit(wl);
3636
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003637 vfree(wl->fw);
3638 wl->fw = NULL;
3639 kfree(wl->nvs);
3640 wl->nvs = NULL;
3641
3642 kfree(wl->fw_status);
3643 kfree(wl->tx_res_if);
3644
3645 ieee80211_free_hw(wl->hw);
3646
3647 return 0;
3648}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003649EXPORT_SYMBOL_GPL(wl1271_free_hw);
3650
Guy Eilam491bbd62011-01-12 10:33:29 +01003651u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003652EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003653module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003654MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3655
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003656MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003657MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003658MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");