blob: 0b9d41f14b28825137c60362d4524ce665c2bf54 [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;
Shahar Levi0830cee2011-03-06 16:32:20 +02001010 case CHIP_ID_1283_PG20:
1011 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1012 wl->chip.id);
1013
1014 ret = wl1271_setup(wl);
1015 if (ret < 0)
1016 goto out;
1017 break;
1018 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001020 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001022 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 }
1024
Arik Nemtsov166d5042010-10-16 21:44:57 +02001025 /* Make sure the firmware type matches the BSS type */
1026 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027 ret = wl1271_fetch_firmware(wl);
1028 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001029 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 }
1031
1032 /* No NVS from netlink, try to get it from the filesystem */
1033 if (wl->nvs == NULL) {
1034 ret = wl1271_fetch_nvs(wl);
1035 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001036 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 }
1038
1039out:
1040 return ret;
1041}
1042
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043int wl1271_plt_start(struct wl1271 *wl)
1044{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001045 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret;
1047
1048 mutex_lock(&wl->mutex);
1049
1050 wl1271_notice("power up");
1051
1052 if (wl->state != WL1271_STATE_OFF) {
1053 wl1271_error("cannot go into PLT state because not "
1054 "in off state: %d", wl->state);
1055 ret = -EBUSY;
1056 goto out;
1057 }
1058
Arik Nemtsov166d5042010-10-16 21:44:57 +02001059 wl->bss_type = BSS_TYPE_STA_BSS;
1060
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001061 while (retries) {
1062 retries--;
1063 ret = wl1271_chip_wakeup(wl);
1064 if (ret < 0)
1065 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001067 ret = wl1271_boot(wl);
1068 if (ret < 0)
1069 goto power_off;
1070
1071 ret = wl1271_plt_init(wl);
1072 if (ret < 0)
1073 goto irq_disable;
1074
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001075 wl->state = WL1271_STATE_PLT;
1076 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001077 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 goto out;
1079
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001080irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001081 mutex_unlock(&wl->mutex);
1082 /* Unlocking the mutex in the middle of handling is
1083 inherently unsafe. In this case we deem it safe to do,
1084 because we need to let any possibly pending IRQ out of
1085 the system (and while we are WL1271_STATE_OFF the IRQ
1086 work function will not do anything.) Also, any other
1087 possible concurrent operations will fail due to the
1088 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001089 wl1271_disable_interrupts(wl);
1090 wl1271_flush_deferred_work(wl);
1091 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001092 mutex_lock(&wl->mutex);
1093power_off:
1094 wl1271_power_off(wl);
1095 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001097 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1098 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099out:
1100 mutex_unlock(&wl->mutex);
1101
1102 return ret;
1103}
1104
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001105int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106{
1107 int ret = 0;
1108
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 wl1271_notice("power down");
1110
1111 if (wl->state != WL1271_STATE_PLT) {
1112 wl1271_error("cannot power down because not in PLT "
1113 "state: %d", wl->state);
1114 ret = -EBUSY;
1115 goto out;
1116 }
1117
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001118 wl1271_power_off(wl);
1119
1120 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001121 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001122
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001124 wl1271_disable_interrupts(wl);
1125 wl1271_flush_deferred_work(wl);
1126 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001127 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001128 mutex_lock(&wl->mutex);
1129out:
1130 return ret;
1131}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001132
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001133int wl1271_plt_stop(struct wl1271 *wl)
1134{
1135 int ret;
1136
1137 mutex_lock(&wl->mutex);
1138 ret = __wl1271_plt_stop(wl);
1139 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140 return ret;
1141}
1142
Johannes Berg7bb45682011-02-24 14:42:06 +01001143static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001144{
1145 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001146 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001147 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001148 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001149
Ido Yarivb07d4032011-03-01 15:14:43 +02001150 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1151
1152 if (wl->bss_type == BSS_TYPE_AP_BSS)
1153 hlid = wl1271_tx_get_hlid(skb);
1154
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001155 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001156
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001157 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001158
1159 /*
1160 * The workqueue is slow to process the tx_queue and we need stop
1161 * the queue here, otherwise the queue will get too long.
1162 */
1163 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1164 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1165 ieee80211_stop_queues(wl->hw);
1166 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1167 }
1168
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001169 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001170 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001171 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1172 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1173 } else {
1174 skb_queue_tail(&wl->tx_queue[q], skb);
1175 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176
1177 /*
1178 * The chip specific setup must run before the first TX packet -
1179 * before that, the tx_work will not be initialized!
1180 */
1181
Ido Yarivb07d4032011-03-01 15:14:43 +02001182 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1183 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001184 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001185
1186 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001187}
1188
Shahar Leviae47c452011-03-06 16:32:14 +02001189#define TX_DUMMY_PACKET_SIZE 1400
1190int wl1271_tx_dummy_packet(struct wl1271 *wl)
1191{
1192 struct sk_buff *skb = NULL;
1193 struct ieee80211_hdr_3addr *hdr;
1194 int ret = 0;
1195
1196 skb = dev_alloc_skb(
1197 sizeof(struct wl1271_tx_hw_descr) + sizeof(*hdr) +
1198 TX_DUMMY_PACKET_SIZE);
1199 if (!skb) {
1200 wl1271_warning("failed to allocate buffer for dummy packet");
1201 ret = -ENOMEM;
1202 goto out;
1203 }
1204
1205 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1206
1207 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1208 memset(hdr, 0, sizeof(*hdr));
1209 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1210 IEEE80211_FCTL_TODS |
1211 IEEE80211_STYPE_NULLFUNC);
1212
1213 memcpy(hdr->addr1, wl->bssid, ETH_ALEN);
1214 memcpy(hdr->addr2, wl->mac_addr, ETH_ALEN);
1215 memcpy(hdr->addr3, wl->bssid, ETH_ALEN);
1216
1217 skb_put(skb, TX_DUMMY_PACKET_SIZE);
1218
1219 memset(skb->data, 0, TX_DUMMY_PACKET_SIZE);
1220
1221 skb->pkt_type = TX_PKT_TYPE_DUMMY_REQ;
1222 /* CONF_TX_AC_VO */
1223 skb->queue_mapping = 0;
1224
1225 wl1271_op_tx(wl->hw, skb);
1226
1227out:
1228 return ret;
1229}
1230
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001231static struct notifier_block wl1271_dev_notifier = {
1232 .notifier_call = wl1271_dev_notify,
1233};
1234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235static int wl1271_op_start(struct ieee80211_hw *hw)
1236{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001237 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1238
1239 /*
1240 * We have to delay the booting of the hardware because
1241 * we need to know the local MAC address before downloading and
1242 * initializing the firmware. The MAC address cannot be changed
1243 * after boot, and without the proper MAC address, the firmware
1244 * will not function properly.
1245 *
1246 * The MAC address is first known when the corresponding interface
1247 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001248 *
1249 * In addition, we currently have different firmwares for AP and managed
1250 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001251 */
1252
1253 return 0;
1254}
1255
1256static void wl1271_op_stop(struct ieee80211_hw *hw)
1257{
1258 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1259}
1260
1261static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1262 struct ieee80211_vif *vif)
1263{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001265 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001266 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001268 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001270 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1271 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272
1273 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001274 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001275 wl1271_debug(DEBUG_MAC80211,
1276 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001277 ret = -EBUSY;
1278 goto out;
1279 }
1280
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001281 switch (vif->type) {
1282 case NL80211_IFTYPE_STATION:
1283 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001284 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001285 break;
1286 case NL80211_IFTYPE_ADHOC:
1287 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001288 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001289 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001290 case NL80211_IFTYPE_AP:
1291 wl->bss_type = BSS_TYPE_AP_BSS;
1292 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001293 default:
1294 ret = -EOPNOTSUPP;
1295 goto out;
1296 }
1297
1298 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299
1300 if (wl->state != WL1271_STATE_OFF) {
1301 wl1271_error("cannot start because not in off state: %d",
1302 wl->state);
1303 ret = -EBUSY;
1304 goto out;
1305 }
1306
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001307 while (retries) {
1308 retries--;
1309 ret = wl1271_chip_wakeup(wl);
1310 if (ret < 0)
1311 goto power_off;
1312
1313 ret = wl1271_boot(wl);
1314 if (ret < 0)
1315 goto power_off;
1316
1317 ret = wl1271_hw_init(wl);
1318 if (ret < 0)
1319 goto irq_disable;
1320
Eliad Peller71125ab2010-10-28 21:46:43 +02001321 booted = true;
1322 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001324irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 mutex_unlock(&wl->mutex);
1326 /* Unlocking the mutex in the middle of handling is
1327 inherently unsafe. In this case we deem it safe to do,
1328 because we need to let any possibly pending IRQ out of
1329 the system (and while we are WL1271_STATE_OFF the IRQ
1330 work function will not do anything.) Also, any other
1331 possible concurrent operations will fail due to the
1332 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001333 wl1271_disable_interrupts(wl);
1334 wl1271_flush_deferred_work(wl);
1335 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001336 mutex_lock(&wl->mutex);
1337power_off:
1338 wl1271_power_off(wl);
1339 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340
Eliad Peller71125ab2010-10-28 21:46:43 +02001341 if (!booted) {
1342 wl1271_error("firmware boot failed despite %d retries",
1343 WL1271_BOOT_RETRIES);
1344 goto out;
1345 }
1346
1347 wl->vif = vif;
1348 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001349 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001350
1351 /* update hw/fw version info in wiphy struct */
1352 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001353 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001354 sizeof(wiphy->fw_version));
1355
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001356 /*
1357 * Now we know if 11a is supported (info from the NVS), so disable
1358 * 11a channels if not supported
1359 */
1360 if (!wl->enable_11a)
1361 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1362
1363 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1364 wl->enable_11a ? "" : "not ");
1365
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001366out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 mutex_unlock(&wl->mutex);
1368
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001369 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001370 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001371
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 return ret;
1373}
1374
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001375static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 int i;
1378
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001379 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001381 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001383 list_del(&wl->list);
1384
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385 WARN_ON(wl->state != WL1271_STATE_ON);
1386
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001387 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001388 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001389 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001390
Luciano Coelho08688d62010-07-08 17:50:07 +03001391 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001392 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1393 kfree(wl->scan.scanned_ch);
1394 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001395 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001396 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397 }
1398
1399 wl->state = WL1271_STATE_OFF;
1400
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401 mutex_unlock(&wl->mutex);
1402
Ido Yariva6208652011-03-01 15:14:41 +02001403 wl1271_disable_interrupts(wl);
1404 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001405 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001406 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001408 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001409 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410
1411 mutex_lock(&wl->mutex);
1412
1413 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001414 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415 wl1271_power_off(wl);
1416
1417 memset(wl->bssid, 0, ETH_ALEN);
1418 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1419 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001421 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001422 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423
1424 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001425 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1427 wl->tx_blocks_available = 0;
1428 wl->tx_results_count = 0;
1429 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001430 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001431 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 wl->time_offset = 0;
1433 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001434 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001435 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001436 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001437 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001438 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001439 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001440 wl->ap_fw_ps_map = 0;
1441 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001442 wl->block_size = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 for (i = 0; i < NUM_TX_QUEUES; i++)
1445 wl->tx_blocks_freed[i] = 0;
1446
1447 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001448
1449 kfree(wl->fw_status);
1450 wl->fw_status = NULL;
1451 kfree(wl->tx_res_if);
1452 wl->tx_res_if = NULL;
1453 kfree(wl->target_mem_map);
1454 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001455}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001456
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001457static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1458 struct ieee80211_vif *vif)
1459{
1460 struct wl1271 *wl = hw->priv;
1461
1462 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001463 /*
1464 * wl->vif can be null here if someone shuts down the interface
1465 * just when hardware recovery has been started.
1466 */
1467 if (wl->vif) {
1468 WARN_ON(wl->vif != vif);
1469 __wl1271_op_remove_interface(wl);
1470 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001471
Juuso Oikarinen67353292010-11-18 15:19:02 +02001472 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001473 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474}
1475
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001476static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1477{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001478 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001479
1480 /* combine requested filters with current filter config */
1481 filters = wl->filters | filters;
1482
1483 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1484
1485 if (filters & FIF_PROMISC_IN_BSS) {
1486 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1487 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1488 wl->rx_config |= CFG_BSSID_FILTER_EN;
1489 }
1490 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1491 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1492 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1493 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1494 }
1495 if (filters & FIF_OTHER_BSS) {
1496 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1497 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1498 }
1499 if (filters & FIF_CONTROL) {
1500 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1501 wl->rx_filter |= CFG_RX_CTL_EN;
1502 }
1503 if (filters & FIF_FCSFAIL) {
1504 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1505 wl->rx_filter |= CFG_RX_FCS_ERROR;
1506 }
1507}
1508
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001509static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001510{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001511 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001512 /* we need to use a dummy BSSID for now */
1513 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1514 0xad, 0xbe, 0xef };
1515
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001516 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1517
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001518 /* pass through frames from all BSS */
1519 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1520
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001521 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001522 if (ret < 0)
1523 goto out;
1524
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001525 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001526
1527out:
1528 return ret;
1529}
1530
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001531static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001532{
1533 int ret;
1534
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001535 /*
1536 * One of the side effects of the JOIN command is that is clears
1537 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1538 * to a WPA/WPA2 access point will therefore kill the data-path.
1539 * Currently there is no supported scenario for JOIN during
1540 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1541 * must be handled somehow.
1542 *
1543 */
1544 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1545 wl1271_info("JOIN while associated.");
1546
1547 if (set_assoc)
1548 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1549
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001550 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1551 if (ret < 0)
1552 goto out;
1553
1554 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1555
1556 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1557 goto out;
1558
1559 /*
1560 * The join command disable the keep-alive mode, shut down its process,
1561 * and also clear the template config, so we need to reset it all after
1562 * the join. The acx_aid starts the keep-alive process, and the order
1563 * of the commands below is relevant.
1564 */
1565 ret = wl1271_acx_keep_alive_mode(wl, true);
1566 if (ret < 0)
1567 goto out;
1568
1569 ret = wl1271_acx_aid(wl, wl->aid);
1570 if (ret < 0)
1571 goto out;
1572
1573 ret = wl1271_cmd_build_klv_null_data(wl);
1574 if (ret < 0)
1575 goto out;
1576
1577 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1578 ACX_KEEP_ALIVE_TPL_VALID);
1579 if (ret < 0)
1580 goto out;
1581
1582out:
1583 return ret;
1584}
1585
1586static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001587{
1588 int ret;
1589
1590 /* to stop listening to a channel, we disconnect */
1591 ret = wl1271_cmd_disconnect(wl);
1592 if (ret < 0)
1593 goto out;
1594
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001595 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001596 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001597
1598 /* stop filterting packets based on bssid */
1599 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001600
1601out:
1602 return ret;
1603}
1604
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001605static void wl1271_set_band_rate(struct wl1271 *wl)
1606{
1607 if (wl->band == IEEE80211_BAND_2GHZ)
1608 wl->basic_rate_set = wl->conf.tx.basic_rate;
1609 else
1610 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1611}
1612
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001613static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001614{
1615 int ret;
1616
1617 if (idle) {
1618 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1619 ret = wl1271_unjoin(wl);
1620 if (ret < 0)
1621 goto out;
1622 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001623 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001624 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001625 if (ret < 0)
1626 goto out;
1627 ret = wl1271_acx_keep_alive_config(
1628 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1629 ACX_KEEP_ALIVE_TPL_INVALID);
1630 if (ret < 0)
1631 goto out;
1632 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1633 } else {
1634 /* increment the session counter */
1635 wl->session_counter++;
1636 if (wl->session_counter >= SESSION_COUNTER_MAX)
1637 wl->session_counter = 0;
1638 ret = wl1271_dummy_join(wl);
1639 if (ret < 0)
1640 goto out;
1641 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1642 }
1643
1644out:
1645 return ret;
1646}
1647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1649{
1650 struct wl1271 *wl = hw->priv;
1651 struct ieee80211_conf *conf = &hw->conf;
1652 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001653 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654
1655 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1656
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001657 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1658 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659 channel,
1660 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001661 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001662 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1663 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001665 /*
1666 * mac80211 will go to idle nearly immediately after transmitting some
1667 * frames, such as the deauth. To make sure those frames reach the air,
1668 * wait here until the TX queue is fully flushed.
1669 */
1670 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1671 (conf->flags & IEEE80211_CONF_IDLE))
1672 wl1271_tx_flush(wl);
1673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001674 mutex_lock(&wl->mutex);
1675
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001676 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1677 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001678 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001679 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001680
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001681 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1682
Ido Yariva6208652011-03-01 15:14:41 +02001683 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001684 if (ret < 0)
1685 goto out;
1686
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001687 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001688 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1689 ((wl->band != conf->channel->band) ||
1690 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001691 wl->band = conf->channel->band;
1692 wl->channel = channel;
1693
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001694 if (!is_ap) {
1695 /*
1696 * FIXME: the mac80211 should really provide a fixed
1697 * rate to use here. for now, just use the smallest
1698 * possible rate for the band as a fixed rate for
1699 * association frames and other control messages.
1700 */
1701 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1702 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001703
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001704 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1705 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001706 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001707 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001708 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001709
1710 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1711 ret = wl1271_join(wl, false);
1712 if (ret < 0)
1713 wl1271_warning("cmd join on channel "
1714 "failed %d", ret);
1715 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001716 }
1717 }
1718
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001719 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1720 ret = wl1271_sta_handle_idle(wl,
1721 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001722 if (ret < 0)
1723 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724 }
1725
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001726 /*
1727 * if mac80211 changes the PSM mode, make sure the mode is not
1728 * incorrectly changed after the pspoll failure active window.
1729 */
1730 if (changed & IEEE80211_CONF_CHANGE_PS)
1731 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1732
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001733 if (conf->flags & IEEE80211_CONF_PS &&
1734 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1735 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736
1737 /*
1738 * We enter PSM only if we're already associated.
1739 * If we're not, we'll enter it when joining an SSID,
1740 * through the bss_info_changed() hook.
1741 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001742 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001743 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001744 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001745 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001746 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001748 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001749 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001751 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001753 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001754 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001755 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756 }
1757
1758 if (conf->power_level != wl->power_level) {
1759 ret = wl1271_acx_tx_power(wl, conf->power_level);
1760 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001761 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762
1763 wl->power_level = conf->power_level;
1764 }
1765
1766out_sleep:
1767 wl1271_ps_elp_sleep(wl);
1768
1769out:
1770 mutex_unlock(&wl->mutex);
1771
1772 return ret;
1773}
1774
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001775struct wl1271_filter_params {
1776 bool enabled;
1777 int mc_list_length;
1778 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1779};
1780
Jiri Pirko22bedad32010-04-01 21:22:57 +00001781static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1782 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001783{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001784 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001785 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001786 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001787
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001788 if (unlikely(wl->state == WL1271_STATE_OFF))
1789 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001790
Juuso Oikarinen74441132009-10-13 12:47:53 +03001791 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001792 if (!fp) {
1793 wl1271_error("Out of memory setting filters.");
1794 return 0;
1795 }
1796
1797 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001798 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001799 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1800 fp->enabled = false;
1801 } else {
1802 fp->enabled = true;
1803 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001804 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001805 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001806 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001807 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001808 }
1809
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001810 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001811}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001813#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1814 FIF_ALLMULTI | \
1815 FIF_FCSFAIL | \
1816 FIF_BCN_PRBRESP_PROMISC | \
1817 FIF_CONTROL | \
1818 FIF_OTHER_BSS)
1819
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1821 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001822 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001824 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001826 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827
Arik Nemtsov7d057862010-10-16 19:25:35 +02001828 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1829 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001831 mutex_lock(&wl->mutex);
1832
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001833 *total &= WL1271_SUPPORTED_FILTERS;
1834 changed &= WL1271_SUPPORTED_FILTERS;
1835
1836 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001837 goto out;
1838
Ido Yariva6208652011-03-01 15:14:41 +02001839 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001840 if (ret < 0)
1841 goto out;
1842
Arik Nemtsov7d057862010-10-16 19:25:35 +02001843 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1844 if (*total & FIF_ALLMULTI)
1845 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1846 else if (fp)
1847 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1848 fp->mc_list,
1849 fp->mc_list_length);
1850 if (ret < 0)
1851 goto out_sleep;
1852 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001854 /* determine, whether supported filter values have changed */
1855 if (changed == 0)
1856 goto out_sleep;
1857
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001858 /* configure filters */
1859 wl->filters = *total;
1860 wl1271_configure_filters(wl, 0);
1861
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001862 /* apply configured filters */
1863 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1864 if (ret < 0)
1865 goto out_sleep;
1866
1867out_sleep:
1868 wl1271_ps_elp_sleep(wl);
1869
1870out:
1871 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001872 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001873}
1874
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001875static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1876 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1877 u16 tx_seq_16)
1878{
1879 struct wl1271_ap_key *ap_key;
1880 int i;
1881
1882 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1883
1884 if (key_size > MAX_KEY_SIZE)
1885 return -EINVAL;
1886
1887 /*
1888 * Find next free entry in ap_keys. Also check we are not replacing
1889 * an existing key.
1890 */
1891 for (i = 0; i < MAX_NUM_KEYS; i++) {
1892 if (wl->recorded_ap_keys[i] == NULL)
1893 break;
1894
1895 if (wl->recorded_ap_keys[i]->id == id) {
1896 wl1271_warning("trying to record key replacement");
1897 return -EINVAL;
1898 }
1899 }
1900
1901 if (i == MAX_NUM_KEYS)
1902 return -EBUSY;
1903
1904 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1905 if (!ap_key)
1906 return -ENOMEM;
1907
1908 ap_key->id = id;
1909 ap_key->key_type = key_type;
1910 ap_key->key_size = key_size;
1911 memcpy(ap_key->key, key, key_size);
1912 ap_key->hlid = hlid;
1913 ap_key->tx_seq_32 = tx_seq_32;
1914 ap_key->tx_seq_16 = tx_seq_16;
1915
1916 wl->recorded_ap_keys[i] = ap_key;
1917 return 0;
1918}
1919
1920static void wl1271_free_ap_keys(struct wl1271 *wl)
1921{
1922 int i;
1923
1924 for (i = 0; i < MAX_NUM_KEYS; i++) {
1925 kfree(wl->recorded_ap_keys[i]);
1926 wl->recorded_ap_keys[i] = NULL;
1927 }
1928}
1929
1930static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1931{
1932 int i, ret = 0;
1933 struct wl1271_ap_key *key;
1934 bool wep_key_added = false;
1935
1936 for (i = 0; i < MAX_NUM_KEYS; i++) {
1937 if (wl->recorded_ap_keys[i] == NULL)
1938 break;
1939
1940 key = wl->recorded_ap_keys[i];
1941 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1942 key->id, key->key_type,
1943 key->key_size, key->key,
1944 key->hlid, key->tx_seq_32,
1945 key->tx_seq_16);
1946 if (ret < 0)
1947 goto out;
1948
1949 if (key->key_type == KEY_WEP)
1950 wep_key_added = true;
1951 }
1952
1953 if (wep_key_added) {
1954 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1955 if (ret < 0)
1956 goto out;
1957 }
1958
1959out:
1960 wl1271_free_ap_keys(wl);
1961 return ret;
1962}
1963
1964static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1965 u8 key_size, const u8 *key, u32 tx_seq_32,
1966 u16 tx_seq_16, struct ieee80211_sta *sta)
1967{
1968 int ret;
1969 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1970
1971 if (is_ap) {
1972 struct wl1271_station *wl_sta;
1973 u8 hlid;
1974
1975 if (sta) {
1976 wl_sta = (struct wl1271_station *)sta->drv_priv;
1977 hlid = wl_sta->hlid;
1978 } else {
1979 hlid = WL1271_AP_BROADCAST_HLID;
1980 }
1981
1982 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1983 /*
1984 * We do not support removing keys after AP shutdown.
1985 * Pretend we do to make mac80211 happy.
1986 */
1987 if (action != KEY_ADD_OR_REPLACE)
1988 return 0;
1989
1990 ret = wl1271_record_ap_key(wl, id,
1991 key_type, key_size,
1992 key, hlid, tx_seq_32,
1993 tx_seq_16);
1994 } else {
1995 ret = wl1271_cmd_set_ap_key(wl, action,
1996 id, key_type, key_size,
1997 key, hlid, tx_seq_32,
1998 tx_seq_16);
1999 }
2000
2001 if (ret < 0)
2002 return ret;
2003 } else {
2004 const u8 *addr;
2005 static const u8 bcast_addr[ETH_ALEN] = {
2006 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2007 };
2008
2009 addr = sta ? sta->addr : bcast_addr;
2010
2011 if (is_zero_ether_addr(addr)) {
2012 /* We dont support TX only encryption */
2013 return -EOPNOTSUPP;
2014 }
2015
2016 /* The wl1271 does not allow to remove unicast keys - they
2017 will be cleared automatically on next CMD_JOIN. Ignore the
2018 request silently, as we dont want the mac80211 to emit
2019 an error message. */
2020 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2021 return 0;
2022
2023 ret = wl1271_cmd_set_sta_key(wl, action,
2024 id, key_type, key_size,
2025 key, addr, tx_seq_32,
2026 tx_seq_16);
2027 if (ret < 0)
2028 return ret;
2029
2030 /* the default WEP key needs to be configured at least once */
2031 if (key_type == KEY_WEP) {
2032 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2033 wl->default_key);
2034 if (ret < 0)
2035 return ret;
2036 }
2037 }
2038
2039 return 0;
2040}
2041
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2043 struct ieee80211_vif *vif,
2044 struct ieee80211_sta *sta,
2045 struct ieee80211_key_conf *key_conf)
2046{
2047 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002049 u32 tx_seq_32 = 0;
2050 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 u8 key_type;
2052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2054
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002055 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002057 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 key_conf->keylen, key_conf->flags);
2059 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2060
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 mutex_lock(&wl->mutex);
2062
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002063 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2064 ret = -EAGAIN;
2065 goto out_unlock;
2066 }
2067
Ido Yariva6208652011-03-01 15:14:41 +02002068 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069 if (ret < 0)
2070 goto out_unlock;
2071
Johannes Berg97359d12010-08-10 09:46:38 +02002072 switch (key_conf->cipher) {
2073 case WLAN_CIPHER_SUITE_WEP40:
2074 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075 key_type = KEY_WEP;
2076
2077 key_conf->hw_key_idx = key_conf->keyidx;
2078 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002079 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080 key_type = KEY_TKIP;
2081
2082 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002083 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2084 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002086 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 key_type = KEY_AES;
2088
2089 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002090 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2091 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002092 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002093 case WL1271_CIPHER_SUITE_GEM:
2094 key_type = KEY_GEM;
2095 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2096 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2097 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002098 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002099 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100
2101 ret = -EOPNOTSUPP;
2102 goto out_sleep;
2103 }
2104
2105 switch (cmd) {
2106 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002107 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2108 key_conf->keyidx, key_type,
2109 key_conf->keylen, key_conf->key,
2110 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111 if (ret < 0) {
2112 wl1271_error("Could not add or replace key");
2113 goto out_sleep;
2114 }
2115 break;
2116
2117 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002118 ret = wl1271_set_key(wl, KEY_REMOVE,
2119 key_conf->keyidx, key_type,
2120 key_conf->keylen, key_conf->key,
2121 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122 if (ret < 0) {
2123 wl1271_error("Could not remove key");
2124 goto out_sleep;
2125 }
2126 break;
2127
2128 default:
2129 wl1271_error("Unsupported key cmd 0x%x", cmd);
2130 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131 break;
2132 }
2133
2134out_sleep:
2135 wl1271_ps_elp_sleep(wl);
2136
2137out_unlock:
2138 mutex_unlock(&wl->mutex);
2139
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140 return ret;
2141}
2142
2143static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002144 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 struct cfg80211_scan_request *req)
2146{
2147 struct wl1271 *wl = hw->priv;
2148 int ret;
2149 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002150 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151
2152 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2153
2154 if (req->n_ssids) {
2155 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002156 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157 }
2158
2159 mutex_lock(&wl->mutex);
2160
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002161 if (wl->state == WL1271_STATE_OFF) {
2162 /*
2163 * We cannot return -EBUSY here because cfg80211 will expect
2164 * a call to ieee80211_scan_completed if we do - in this case
2165 * there won't be any call.
2166 */
2167 ret = -EAGAIN;
2168 goto out;
2169 }
2170
Ido Yariva6208652011-03-01 15:14:41 +02002171 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 if (ret < 0)
2173 goto out;
2174
Luciano Coelho5924f892010-08-04 03:46:22 +03002175 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176
2177 wl1271_ps_elp_sleep(wl);
2178
2179out:
2180 mutex_unlock(&wl->mutex);
2181
2182 return ret;
2183}
2184
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002185static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2186{
2187 struct wl1271 *wl = hw->priv;
2188 int ret = 0;
2189
2190 mutex_lock(&wl->mutex);
2191
2192 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2193 ret = -EAGAIN;
2194 goto out;
2195 }
2196
Ido Yariva6208652011-03-01 15:14:41 +02002197 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002198 if (ret < 0)
2199 goto out;
2200
2201 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2202 if (ret < 0)
2203 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2204
2205 wl1271_ps_elp_sleep(wl);
2206
2207out:
2208 mutex_unlock(&wl->mutex);
2209
2210 return ret;
2211}
2212
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002213static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2214{
2215 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002216 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217
2218 mutex_lock(&wl->mutex);
2219
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002220 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2221 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002222 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002223 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002224
Ido Yariva6208652011-03-01 15:14:41 +02002225 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226 if (ret < 0)
2227 goto out;
2228
2229 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2230 if (ret < 0)
2231 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2232
2233 wl1271_ps_elp_sleep(wl);
2234
2235out:
2236 mutex_unlock(&wl->mutex);
2237
2238 return ret;
2239}
2240
Arik Nemtsove78a2872010-10-16 19:07:21 +02002241static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002242 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002243{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002244 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002245
2246 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002247 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002248 if (ptr[0] == WLAN_EID_SSID) {
2249 wl->ssid_len = ptr[1];
2250 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002251 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002252 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002253 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002254 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002255
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002256 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002257 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002258}
2259
Arik Nemtsove78a2872010-10-16 19:07:21 +02002260static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2261 struct ieee80211_bss_conf *bss_conf,
2262 u32 changed)
2263{
2264 int ret = 0;
2265
2266 if (changed & BSS_CHANGED_ERP_SLOT) {
2267 if (bss_conf->use_short_slot)
2268 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2269 else
2270 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2271 if (ret < 0) {
2272 wl1271_warning("Set slot time failed %d", ret);
2273 goto out;
2274 }
2275 }
2276
2277 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2278 if (bss_conf->use_short_preamble)
2279 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2280 else
2281 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2282 }
2283
2284 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2285 if (bss_conf->use_cts_prot)
2286 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2287 else
2288 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2289 if (ret < 0) {
2290 wl1271_warning("Set ctsprotect failed %d", ret);
2291 goto out;
2292 }
2293 }
2294
2295out:
2296 return ret;
2297}
2298
2299static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2300 struct ieee80211_vif *vif,
2301 struct ieee80211_bss_conf *bss_conf,
2302 u32 changed)
2303{
2304 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2305 int ret = 0;
2306
2307 if ((changed & BSS_CHANGED_BEACON_INT)) {
2308 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2309 bss_conf->beacon_int);
2310
2311 wl->beacon_int = bss_conf->beacon_int;
2312 }
2313
2314 if ((changed & BSS_CHANGED_BEACON)) {
2315 struct ieee80211_hdr *hdr;
2316 int ieoffset = offsetof(struct ieee80211_mgmt,
2317 u.beacon.variable);
2318 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2319 u16 tmpl_id;
2320
2321 if (!beacon)
2322 goto out;
2323
2324 wl1271_debug(DEBUG_MASTER, "beacon updated");
2325
2326 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2327 if (ret < 0) {
2328 dev_kfree_skb(beacon);
2329 goto out;
2330 }
2331 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2332 CMD_TEMPL_BEACON;
2333 ret = wl1271_cmd_template_set(wl, tmpl_id,
2334 beacon->data,
2335 beacon->len, 0,
2336 wl1271_tx_min_rate_get(wl));
2337 if (ret < 0) {
2338 dev_kfree_skb(beacon);
2339 goto out;
2340 }
2341
2342 hdr = (struct ieee80211_hdr *) beacon->data;
2343 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2344 IEEE80211_STYPE_PROBE_RESP);
2345
2346 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2347 CMD_TEMPL_PROBE_RESPONSE;
2348 ret = wl1271_cmd_template_set(wl,
2349 tmpl_id,
2350 beacon->data,
2351 beacon->len, 0,
2352 wl1271_tx_min_rate_get(wl));
2353 dev_kfree_skb(beacon);
2354 if (ret < 0)
2355 goto out;
2356 }
2357
2358out:
2359 return ret;
2360}
2361
2362/* AP mode changes */
2363static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 struct ieee80211_vif *vif,
2365 struct ieee80211_bss_conf *bss_conf,
2366 u32 changed)
2367{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002368 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369
Arik Nemtsove78a2872010-10-16 19:07:21 +02002370 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2371 u32 rates = bss_conf->basic_rates;
2372 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373
Arik Nemtsove78a2872010-10-16 19:07:21 +02002374 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2375 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2376 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2377 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378
Arik Nemtsove78a2872010-10-16 19:07:21 +02002379 /* update the AP management rate policy with the new rates */
2380 mgmt_rc.enabled_rates = wl->basic_rate_set;
2381 mgmt_rc.long_retry_limit = 10;
2382 mgmt_rc.short_retry_limit = 10;
2383 mgmt_rc.aflags = 0;
2384 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2385 ACX_TX_AP_MODE_MGMT_RATE);
2386 if (ret < 0) {
2387 wl1271_error("AP mgmt policy change failed %d", ret);
2388 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002389 }
2390 }
2391
Arik Nemtsove78a2872010-10-16 19:07:21 +02002392 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2393 if (ret < 0)
2394 goto out;
2395
2396 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2397 if (bss_conf->enable_beacon) {
2398 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2399 ret = wl1271_cmd_start_bss(wl);
2400 if (ret < 0)
2401 goto out;
2402
2403 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2404 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002405
2406 ret = wl1271_ap_init_hwenc(wl);
2407 if (ret < 0)
2408 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002409 }
2410 } else {
2411 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2412 ret = wl1271_cmd_stop_bss(wl);
2413 if (ret < 0)
2414 goto out;
2415
2416 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2417 wl1271_debug(DEBUG_AP, "stopped AP");
2418 }
2419 }
2420 }
2421
2422 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2423 if (ret < 0)
2424 goto out;
2425out:
2426 return;
2427}
2428
2429/* STA/IBSS mode changes */
2430static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2431 struct ieee80211_vif *vif,
2432 struct ieee80211_bss_conf *bss_conf,
2433 u32 changed)
2434{
2435 bool do_join = false, set_assoc = false;
2436 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002437 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002438 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002439 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002440 bool sta_exists = false;
2441 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002442
2443 if (is_ibss) {
2444 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2445 changed);
2446 if (ret < 0)
2447 goto out;
2448 }
2449
2450 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2451 do_join = true;
2452
2453 /* Need to update the SSID (for filtering etc) */
2454 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2455 do_join = true;
2456
2457 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002458 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2459 bss_conf->enable_beacon ? "enabled" : "disabled");
2460
2461 if (bss_conf->enable_beacon)
2462 wl->set_bss_type = BSS_TYPE_IBSS;
2463 else
2464 wl->set_bss_type = BSS_TYPE_STA_BSS;
2465 do_join = true;
2466 }
2467
Arik Nemtsove78a2872010-10-16 19:07:21 +02002468 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002469 bool enable = false;
2470 if (bss_conf->cqm_rssi_thold)
2471 enable = true;
2472 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2473 bss_conf->cqm_rssi_thold,
2474 bss_conf->cqm_rssi_hyst);
2475 if (ret < 0)
2476 goto out;
2477 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2478 }
2479
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002480 if ((changed & BSS_CHANGED_BSSID) &&
2481 /*
2482 * Now we know the correct bssid, so we send a new join command
2483 * and enable the BSSID filter
2484 */
2485 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002486 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002487
Eliad Pellerfa287b82010-12-26 09:27:50 +01002488 if (!is_zero_ether_addr(wl->bssid)) {
2489 ret = wl1271_cmd_build_null_data(wl);
2490 if (ret < 0)
2491 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002492
Eliad Pellerfa287b82010-12-26 09:27:50 +01002493 ret = wl1271_build_qos_null_data(wl);
2494 if (ret < 0)
2495 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002496
Eliad Pellerfa287b82010-12-26 09:27:50 +01002497 /* filter out all packets not from this BSSID */
2498 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002499
Eliad Pellerfa287b82010-12-26 09:27:50 +01002500 /* Need to update the BSSID (for filtering etc) */
2501 do_join = true;
2502 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002503 }
2504
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002505 rcu_read_lock();
2506 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2507 if (sta) {
2508 /* save the supp_rates of the ap */
2509 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2510 if (sta->ht_cap.ht_supported)
2511 sta_rate_set |=
2512 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002513 sta_ht_cap = sta->ht_cap;
2514 sta_exists = true;
2515 }
2516 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002517
Arik Nemtsova1008852011-02-12 23:24:20 +02002518 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002519 /* handle new association with HT and HT information change */
2520 if ((changed & BSS_CHANGED_HT) &&
2521 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002522 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002523 true);
2524 if (ret < 0) {
2525 wl1271_warning("Set ht cap true failed %d",
2526 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002527 goto out;
2528 }
2529 ret = wl1271_acx_set_ht_information(wl,
2530 bss_conf->ht_operation_mode);
2531 if (ret < 0) {
2532 wl1271_warning("Set ht information failed %d",
2533 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002534 goto out;
2535 }
2536 }
2537 /* handle new association without HT and disassociation */
2538 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002539 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002540 false);
2541 if (ret < 0) {
2542 wl1271_warning("Set ht cap false failed %d",
2543 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002544 goto out;
2545 }
2546 }
2547 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002548
Arik Nemtsove78a2872010-10-16 19:07:21 +02002549 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002551 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002552 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002554 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002555
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002556 wl->ps_poll_failures = 0;
2557
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002558 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002559 * use basic rates from AP, and determine lowest rate
2560 * to use with control frames.
2561 */
2562 rates = bss_conf->basic_rates;
2563 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2564 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002565 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002566 if (sta_rate_set)
2567 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2568 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002569 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002570 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002571 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002572
2573 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002574 * with wl1271, we don't need to update the
2575 * beacon_int and dtim_period, because the firmware
2576 * updates it by itself when the first beacon is
2577 * received after a join.
2578 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2580 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002581 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002582
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002583 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002584 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002585 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002586 dev_kfree_skb(wl->probereq);
2587 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2588 ieoffset = offsetof(struct ieee80211_mgmt,
2589 u.probe_req.variable);
2590 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002591
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002592 /* enable the connection monitoring feature */
2593 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002595 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002596
2597 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002598 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2599 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002600 enum wl1271_cmd_ps_mode mode;
2601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002603 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002604 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002605 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002606 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002607 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002608 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002609 } else {
2610 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002611 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002612 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002613 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002614
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002615 /* free probe-request template */
2616 dev_kfree_skb(wl->probereq);
2617 wl->probereq = NULL;
2618
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002619 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002620 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002621
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002622 /* revert back to minimum rates for the current band */
2623 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002624 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002625 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002626 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002627 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002628
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002629 /* disable connection monitor features */
2630 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002631
2632 /* Disable the keep-alive feature */
2633 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002634 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002635 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002636
2637 /* restore the bssid filter and go to dummy bssid */
2638 wl1271_unjoin(wl);
2639 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640 }
2641 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002642
Arik Nemtsove78a2872010-10-16 19:07:21 +02002643 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2644 if (ret < 0)
2645 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002646
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002647 if (changed & BSS_CHANGED_ARP_FILTER) {
2648 __be32 addr = bss_conf->arp_addr_list[0];
2649 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2650
Eliad Pellerc5312772010-12-09 11:31:27 +02002651 if (bss_conf->arp_addr_cnt == 1 &&
2652 bss_conf->arp_filter_enabled) {
2653 /*
2654 * The template should have been configured only upon
2655 * association. however, it seems that the correct ip
2656 * isn't being set (when sending), so we have to
2657 * reconfigure the template upon every ip change.
2658 */
2659 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2660 if (ret < 0) {
2661 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002662 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002663 }
2664
2665 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002666 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002667 addr);
2668 } else
2669 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002670
2671 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002672 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002673 }
2674
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002675 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002676 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002677 if (ret < 0) {
2678 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002679 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002680 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002681 }
2682
Arik Nemtsove78a2872010-10-16 19:07:21 +02002683out:
2684 return;
2685}
2686
2687static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2688 struct ieee80211_vif *vif,
2689 struct ieee80211_bss_conf *bss_conf,
2690 u32 changed)
2691{
2692 struct wl1271 *wl = hw->priv;
2693 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2694 int ret;
2695
2696 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2697 (int)changed);
2698
2699 mutex_lock(&wl->mutex);
2700
2701 if (unlikely(wl->state == WL1271_STATE_OFF))
2702 goto out;
2703
Ido Yariva6208652011-03-01 15:14:41 +02002704 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002705 if (ret < 0)
2706 goto out;
2707
2708 if (is_ap)
2709 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2710 else
2711 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2712
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 wl1271_ps_elp_sleep(wl);
2714
2715out:
2716 mutex_unlock(&wl->mutex);
2717}
2718
Kalle Valoc6999d82010-02-18 13:25:41 +02002719static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2720 const struct ieee80211_tx_queue_params *params)
2721{
2722 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002723 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002724 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002725
2726 mutex_lock(&wl->mutex);
2727
2728 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2729
Kalle Valo4695dc92010-03-18 12:26:38 +02002730 if (params->uapsd)
2731 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2732 else
2733 ps_scheme = CONF_PS_SCHEME_LEGACY;
2734
Arik Nemtsov488fc542010-10-16 20:33:45 +02002735 if (wl->state == WL1271_STATE_OFF) {
2736 /*
2737 * If the state is off, the parameters will be recorded and
2738 * configured on init. This happens in AP-mode.
2739 */
2740 struct conf_tx_ac_category *conf_ac =
2741 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2742 struct conf_tx_tid *conf_tid =
2743 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2744
2745 conf_ac->ac = wl1271_tx_get_queue(queue);
2746 conf_ac->cw_min = (u8)params->cw_min;
2747 conf_ac->cw_max = params->cw_max;
2748 conf_ac->aifsn = params->aifs;
2749 conf_ac->tx_op_limit = params->txop << 5;
2750
2751 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2752 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2753 conf_tid->tsid = wl1271_tx_get_queue(queue);
2754 conf_tid->ps_scheme = ps_scheme;
2755 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2756 conf_tid->apsd_conf[0] = 0;
2757 conf_tid->apsd_conf[1] = 0;
2758 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002759 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002760 if (ret < 0)
2761 goto out;
2762
2763 /*
2764 * the txop is confed in units of 32us by the mac80211,
2765 * we need us
2766 */
2767 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2768 params->cw_min, params->cw_max,
2769 params->aifs, params->txop << 5);
2770 if (ret < 0)
2771 goto out_sleep;
2772
2773 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2774 CONF_CHANNEL_TYPE_EDCF,
2775 wl1271_tx_get_queue(queue),
2776 ps_scheme, CONF_ACK_POLICY_LEGACY,
2777 0, 0);
2778 if (ret < 0)
2779 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002780
2781out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002782 wl1271_ps_elp_sleep(wl);
2783 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002784
2785out:
2786 mutex_unlock(&wl->mutex);
2787
2788 return ret;
2789}
2790
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002791static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2792{
2793
2794 struct wl1271 *wl = hw->priv;
2795 u64 mactime = ULLONG_MAX;
2796 int ret;
2797
2798 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2799
2800 mutex_lock(&wl->mutex);
2801
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002802 if (unlikely(wl->state == WL1271_STATE_OFF))
2803 goto out;
2804
Ido Yariva6208652011-03-01 15:14:41 +02002805 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002806 if (ret < 0)
2807 goto out;
2808
2809 ret = wl1271_acx_tsf_info(wl, &mactime);
2810 if (ret < 0)
2811 goto out_sleep;
2812
2813out_sleep:
2814 wl1271_ps_elp_sleep(wl);
2815
2816out:
2817 mutex_unlock(&wl->mutex);
2818 return mactime;
2819}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002820
John W. Linvilleece550d2010-07-28 16:41:06 -04002821static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2822 struct survey_info *survey)
2823{
2824 struct wl1271 *wl = hw->priv;
2825 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002826
John W. Linvilleece550d2010-07-28 16:41:06 -04002827 if (idx != 0)
2828 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002829
John W. Linvilleece550d2010-07-28 16:41:06 -04002830 survey->channel = conf->channel;
2831 survey->filled = SURVEY_INFO_NOISE_DBM;
2832 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002833
John W. Linvilleece550d2010-07-28 16:41:06 -04002834 return 0;
2835}
2836
Arik Nemtsov409622e2011-02-23 00:22:29 +02002837static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002838 struct ieee80211_sta *sta,
2839 u8 *hlid)
2840{
2841 struct wl1271_station *wl_sta;
2842 int id;
2843
2844 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2845 if (id >= AP_MAX_STATIONS) {
2846 wl1271_warning("could not allocate HLID - too much stations");
2847 return -EBUSY;
2848 }
2849
2850 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002851 __set_bit(id, wl->ap_hlid_map);
2852 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2853 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002854 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002855 return 0;
2856}
2857
Arik Nemtsov409622e2011-02-23 00:22:29 +02002858static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002859{
2860 int id = hlid - WL1271_AP_STA_HLID_START;
2861
Arik Nemtsov409622e2011-02-23 00:22:29 +02002862 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2863 return;
2864
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002865 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002866 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002867 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002868 __clear_bit(hlid, &wl->ap_ps_map);
2869 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002870}
2871
2872static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2873 struct ieee80211_vif *vif,
2874 struct ieee80211_sta *sta)
2875{
2876 struct wl1271 *wl = hw->priv;
2877 int ret = 0;
2878 u8 hlid;
2879
2880 mutex_lock(&wl->mutex);
2881
2882 if (unlikely(wl->state == WL1271_STATE_OFF))
2883 goto out;
2884
2885 if (wl->bss_type != BSS_TYPE_AP_BSS)
2886 goto out;
2887
2888 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2889
Arik Nemtsov409622e2011-02-23 00:22:29 +02002890 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002891 if (ret < 0)
2892 goto out;
2893
Ido Yariva6208652011-03-01 15:14:41 +02002894 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002895 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002896 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002897
2898 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2899 if (ret < 0)
2900 goto out_sleep;
2901
2902out_sleep:
2903 wl1271_ps_elp_sleep(wl);
2904
Arik Nemtsov409622e2011-02-23 00:22:29 +02002905out_free_sta:
2906 if (ret < 0)
2907 wl1271_free_sta(wl, hlid);
2908
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002909out:
2910 mutex_unlock(&wl->mutex);
2911 return ret;
2912}
2913
2914static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2915 struct ieee80211_vif *vif,
2916 struct ieee80211_sta *sta)
2917{
2918 struct wl1271 *wl = hw->priv;
2919 struct wl1271_station *wl_sta;
2920 int ret = 0, id;
2921
2922 mutex_lock(&wl->mutex);
2923
2924 if (unlikely(wl->state == WL1271_STATE_OFF))
2925 goto out;
2926
2927 if (wl->bss_type != BSS_TYPE_AP_BSS)
2928 goto out;
2929
2930 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2931
2932 wl_sta = (struct wl1271_station *)sta->drv_priv;
2933 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2934 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2935 goto out;
2936
Ido Yariva6208652011-03-01 15:14:41 +02002937 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002938 if (ret < 0)
2939 goto out;
2940
2941 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2942 if (ret < 0)
2943 goto out_sleep;
2944
Arik Nemtsov409622e2011-02-23 00:22:29 +02002945 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002946
2947out_sleep:
2948 wl1271_ps_elp_sleep(wl);
2949
2950out:
2951 mutex_unlock(&wl->mutex);
2952 return ret;
2953}
2954
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002955int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002956 enum ieee80211_ampdu_mlme_action action,
2957 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2958 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002959{
2960 struct wl1271 *wl = hw->priv;
2961 int ret;
2962
2963 mutex_lock(&wl->mutex);
2964
2965 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2966 ret = -EAGAIN;
2967 goto out;
2968 }
2969
Ido Yariva6208652011-03-01 15:14:41 +02002970 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002971 if (ret < 0)
2972 goto out;
2973
2974 switch (action) {
2975 case IEEE80211_AMPDU_RX_START:
2976 if (wl->ba_support) {
2977 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2978 true);
2979 if (!ret)
2980 wl->ba_rx_bitmap |= BIT(tid);
2981 } else {
2982 ret = -ENOTSUPP;
2983 }
2984 break;
2985
2986 case IEEE80211_AMPDU_RX_STOP:
2987 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2988 if (!ret)
2989 wl->ba_rx_bitmap &= ~BIT(tid);
2990 break;
2991
2992 /*
2993 * The BA initiator session management in FW independently.
2994 * Falling break here on purpose for all TX APDU commands.
2995 */
2996 case IEEE80211_AMPDU_TX_START:
2997 case IEEE80211_AMPDU_TX_STOP:
2998 case IEEE80211_AMPDU_TX_OPERATIONAL:
2999 ret = -EINVAL;
3000 break;
3001
3002 default:
3003 wl1271_error("Incorrect ampdu action id=%x\n", action);
3004 ret = -EINVAL;
3005 }
3006
3007 wl1271_ps_elp_sleep(wl);
3008
3009out:
3010 mutex_unlock(&wl->mutex);
3011
3012 return ret;
3013}
3014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015/* can't be const, mac80211 writes to this */
3016static struct ieee80211_rate wl1271_rates[] = {
3017 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003018 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3019 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003020 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003021 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3022 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3024 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003025 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3026 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3028 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003029 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3030 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003031 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3032 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003033 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3034 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003035 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003036 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3037 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003039 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3040 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003042 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3043 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003045 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3046 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003048 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3049 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003050 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003051 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3052 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003053 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003054 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3055 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056};
3057
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003058/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003060 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003061 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003062 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3063 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3064 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003065 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003066 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3067 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3068 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003069 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003070 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3071 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3072 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003073 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074};
3075
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003076/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003077static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003078 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003079 7, /* CONF_HW_RXTX_RATE_MCS7 */
3080 6, /* CONF_HW_RXTX_RATE_MCS6 */
3081 5, /* CONF_HW_RXTX_RATE_MCS5 */
3082 4, /* CONF_HW_RXTX_RATE_MCS4 */
3083 3, /* CONF_HW_RXTX_RATE_MCS3 */
3084 2, /* CONF_HW_RXTX_RATE_MCS2 */
3085 1, /* CONF_HW_RXTX_RATE_MCS1 */
3086 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003087
3088 11, /* CONF_HW_RXTX_RATE_54 */
3089 10, /* CONF_HW_RXTX_RATE_48 */
3090 9, /* CONF_HW_RXTX_RATE_36 */
3091 8, /* CONF_HW_RXTX_RATE_24 */
3092
3093 /* TI-specific rate */
3094 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3095
3096 7, /* CONF_HW_RXTX_RATE_18 */
3097 6, /* CONF_HW_RXTX_RATE_12 */
3098 3, /* CONF_HW_RXTX_RATE_11 */
3099 5, /* CONF_HW_RXTX_RATE_9 */
3100 4, /* CONF_HW_RXTX_RATE_6 */
3101 2, /* CONF_HW_RXTX_RATE_5_5 */
3102 1, /* CONF_HW_RXTX_RATE_2 */
3103 0 /* CONF_HW_RXTX_RATE_1 */
3104};
3105
Shahar Levie8b03a22010-10-13 16:09:39 +02003106/* 11n STA capabilities */
3107#define HW_RX_HIGHEST_RATE 72
3108
Shahar Levi00d20102010-11-08 11:20:10 +00003109#ifdef CONFIG_WL12XX_HT
3110#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003111 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3112 .ht_supported = true, \
3113 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3114 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3115 .mcs = { \
3116 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3117 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3118 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3119 }, \
3120}
Shahar Levi18357852010-10-13 16:09:41 +02003121#else
Shahar Levi00d20102010-11-08 11:20:10 +00003122#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003123 .ht_supported = false, \
3124}
3125#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003127/* can't be const, mac80211 writes to this */
3128static struct ieee80211_supported_band wl1271_band_2ghz = {
3129 .channels = wl1271_channels,
3130 .n_channels = ARRAY_SIZE(wl1271_channels),
3131 .bitrates = wl1271_rates,
3132 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003133 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003134};
3135
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003136/* 5 GHz data rates for WL1273 */
3137static struct ieee80211_rate wl1271_rates_5ghz[] = {
3138 { .bitrate = 60,
3139 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3140 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3141 { .bitrate = 90,
3142 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3143 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3144 { .bitrate = 120,
3145 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3146 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3147 { .bitrate = 180,
3148 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3149 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3150 { .bitrate = 240,
3151 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3152 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3153 { .bitrate = 360,
3154 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3155 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3156 { .bitrate = 480,
3157 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3158 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3159 { .bitrate = 540,
3160 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3161 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3162};
3163
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003164/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003165static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003166 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003167 { .hw_value = 8, .center_freq = 5040},
3168 { .hw_value = 9, .center_freq = 5045},
3169 { .hw_value = 11, .center_freq = 5055},
3170 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003171 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003172 { .hw_value = 34, .center_freq = 5170},
3173 { .hw_value = 36, .center_freq = 5180},
3174 { .hw_value = 38, .center_freq = 5190},
3175 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003176 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003177 { .hw_value = 44, .center_freq = 5220},
3178 { .hw_value = 46, .center_freq = 5230},
3179 { .hw_value = 48, .center_freq = 5240},
3180 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003181 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003182 { .hw_value = 60, .center_freq = 5300},
3183 { .hw_value = 64, .center_freq = 5320},
3184 { .hw_value = 100, .center_freq = 5500},
3185 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003186 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003187 { .hw_value = 112, .center_freq = 5560},
3188 { .hw_value = 116, .center_freq = 5580},
3189 { .hw_value = 120, .center_freq = 5600},
3190 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003191 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003192 { .hw_value = 132, .center_freq = 5660},
3193 { .hw_value = 136, .center_freq = 5680},
3194 { .hw_value = 140, .center_freq = 5700},
3195 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003196 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003197 { .hw_value = 157, .center_freq = 5785},
3198 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003199 { .hw_value = 165, .center_freq = 5825},
3200};
3201
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003202/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003203static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003204 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003205 7, /* CONF_HW_RXTX_RATE_MCS7 */
3206 6, /* CONF_HW_RXTX_RATE_MCS6 */
3207 5, /* CONF_HW_RXTX_RATE_MCS5 */
3208 4, /* CONF_HW_RXTX_RATE_MCS4 */
3209 3, /* CONF_HW_RXTX_RATE_MCS3 */
3210 2, /* CONF_HW_RXTX_RATE_MCS2 */
3211 1, /* CONF_HW_RXTX_RATE_MCS1 */
3212 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003213
3214 7, /* CONF_HW_RXTX_RATE_54 */
3215 6, /* CONF_HW_RXTX_RATE_48 */
3216 5, /* CONF_HW_RXTX_RATE_36 */
3217 4, /* CONF_HW_RXTX_RATE_24 */
3218
3219 /* TI-specific rate */
3220 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3221
3222 3, /* CONF_HW_RXTX_RATE_18 */
3223 2, /* CONF_HW_RXTX_RATE_12 */
3224 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3225 1, /* CONF_HW_RXTX_RATE_9 */
3226 0, /* CONF_HW_RXTX_RATE_6 */
3227 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3228 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3229 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3230};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003231
3232static struct ieee80211_supported_band wl1271_band_5ghz = {
3233 .channels = wl1271_channels_5ghz,
3234 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3235 .bitrates = wl1271_rates_5ghz,
3236 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003237 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003238};
3239
Tobias Klausera0ea9492010-05-20 10:38:11 +02003240static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003241 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3242 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3243};
3244
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003245static const struct ieee80211_ops wl1271_ops = {
3246 .start = wl1271_op_start,
3247 .stop = wl1271_op_stop,
3248 .add_interface = wl1271_op_add_interface,
3249 .remove_interface = wl1271_op_remove_interface,
3250 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003251 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003252 .configure_filter = wl1271_op_configure_filter,
3253 .tx = wl1271_op_tx,
3254 .set_key = wl1271_op_set_key,
3255 .hw_scan = wl1271_op_hw_scan,
3256 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003257 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003258 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003259 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003260 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003261 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003262 .sta_add = wl1271_op_sta_add,
3263 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003264 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003265 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003266};
3267
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003268
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003269u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003270{
3271 u8 idx;
3272
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003273 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003274
3275 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3276 wl1271_error("Illegal RX rate from HW: %d", rate);
3277 return 0;
3278 }
3279
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003280 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003281 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3282 wl1271_error("Unsupported RX rate from HW: %d", rate);
3283 return 0;
3284 }
3285
3286 return idx;
3287}
3288
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003289static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3290 struct device_attribute *attr,
3291 char *buf)
3292{
3293 struct wl1271 *wl = dev_get_drvdata(dev);
3294 ssize_t len;
3295
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003296 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003297
3298 mutex_lock(&wl->mutex);
3299 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3300 wl->sg_enabled);
3301 mutex_unlock(&wl->mutex);
3302
3303 return len;
3304
3305}
3306
3307static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3308 struct device_attribute *attr,
3309 const char *buf, size_t count)
3310{
3311 struct wl1271 *wl = dev_get_drvdata(dev);
3312 unsigned long res;
3313 int ret;
3314
3315 ret = strict_strtoul(buf, 10, &res);
3316
3317 if (ret < 0) {
3318 wl1271_warning("incorrect value written to bt_coex_mode");
3319 return count;
3320 }
3321
3322 mutex_lock(&wl->mutex);
3323
3324 res = !!res;
3325
3326 if (res == wl->sg_enabled)
3327 goto out;
3328
3329 wl->sg_enabled = res;
3330
3331 if (wl->state == WL1271_STATE_OFF)
3332 goto out;
3333
Ido Yariva6208652011-03-01 15:14:41 +02003334 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003335 if (ret < 0)
3336 goto out;
3337
3338 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3339 wl1271_ps_elp_sleep(wl);
3340
3341 out:
3342 mutex_unlock(&wl->mutex);
3343 return count;
3344}
3345
3346static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3347 wl1271_sysfs_show_bt_coex_state,
3348 wl1271_sysfs_store_bt_coex_state);
3349
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003350static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3351 struct device_attribute *attr,
3352 char *buf)
3353{
3354 struct wl1271 *wl = dev_get_drvdata(dev);
3355 ssize_t len;
3356
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003357 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003358
3359 mutex_lock(&wl->mutex);
3360 if (wl->hw_pg_ver >= 0)
3361 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3362 else
3363 len = snprintf(buf, len, "n/a\n");
3364 mutex_unlock(&wl->mutex);
3365
3366 return len;
3367}
3368
3369static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3370 wl1271_sysfs_show_hw_pg_ver, NULL);
3371
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003372int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003373{
3374 int ret;
3375
3376 if (wl->mac80211_registered)
3377 return 0;
3378
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003379 ret = wl1271_fetch_nvs(wl);
3380 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003381 /* NOTE: The wl->nvs->nvs element must be first, in
3382 * order to simplify the casting, we assume it is at
3383 * the beginning of the wl->nvs structure.
3384 */
3385 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003386
3387 wl->mac_addr[0] = nvs_ptr[11];
3388 wl->mac_addr[1] = nvs_ptr[10];
3389 wl->mac_addr[2] = nvs_ptr[6];
3390 wl->mac_addr[3] = nvs_ptr[5];
3391 wl->mac_addr[4] = nvs_ptr[4];
3392 wl->mac_addr[5] = nvs_ptr[3];
3393 }
3394
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003395 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3396
3397 ret = ieee80211_register_hw(wl->hw);
3398 if (ret < 0) {
3399 wl1271_error("unable to register mac80211 hw: %d", ret);
3400 return ret;
3401 }
3402
3403 wl->mac80211_registered = true;
3404
Eliad Pellerd60080a2010-11-24 12:53:16 +02003405 wl1271_debugfs_init(wl);
3406
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003407 register_netdevice_notifier(&wl1271_dev_notifier);
3408
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003409 wl1271_notice("loaded");
3410
3411 return 0;
3412}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003413EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003414
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003415void wl1271_unregister_hw(struct wl1271 *wl)
3416{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003417 if (wl->state == WL1271_STATE_PLT)
3418 __wl1271_plt_stop(wl);
3419
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003420 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003421 ieee80211_unregister_hw(wl->hw);
3422 wl->mac80211_registered = false;
3423
3424}
3425EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3426
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003427int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003429 static const u32 cipher_suites[] = {
3430 WLAN_CIPHER_SUITE_WEP40,
3431 WLAN_CIPHER_SUITE_WEP104,
3432 WLAN_CIPHER_SUITE_TKIP,
3433 WLAN_CIPHER_SUITE_CCMP,
3434 WL1271_CIPHER_SUITE_GEM,
3435 };
3436
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003437 /* The tx descriptor buffer and the TKIP space. */
3438 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3439 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440
3441 /* unit us */
3442 /* FIXME: find a proper value */
3443 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003444 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003445
3446 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003447 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003448 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003449 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003450 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003451 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003452 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003453 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3454 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003455
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003456 wl->hw->wiphy->cipher_suites = cipher_suites;
3457 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3458
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003459 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003460 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003462 /*
3463 * Maximum length of elements in scanning probe request templates
3464 * should be the maximum length possible for a template, without
3465 * the IEEE80211 header of the template
3466 */
3467 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3468 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003469
3470 /*
3471 * We keep local copies of the band structs because we need to
3472 * modify them on a per-device basis.
3473 */
3474 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3475 sizeof(wl1271_band_2ghz));
3476 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3477 sizeof(wl1271_band_5ghz));
3478
3479 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3480 &wl->bands[IEEE80211_BAND_2GHZ];
3481 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3482 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003483
Kalle Valo12bd8942010-03-18 12:26:33 +02003484 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003485 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003486
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003487 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3488
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003489 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003490
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003491 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3492
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003493 wl->hw->max_rx_aggregation_subframes = 8;
3494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495 return 0;
3496}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003497EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003498
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003499#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003500
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003501struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003502{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003503 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003504 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003505 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003506 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003507 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003508
3509 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3510 if (!hw) {
3511 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003512 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003513 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514 }
3515
Julia Lawall929ebd32010-05-15 23:16:39 +02003516 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003517 if (!plat_dev) {
3518 wl1271_error("could not allocate platform_device");
3519 ret = -ENOMEM;
3520 goto err_plat_alloc;
3521 }
3522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003523 wl = hw->priv;
3524 memset(wl, 0, sizeof(*wl));
3525
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003526 INIT_LIST_HEAD(&wl->list);
3527
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003529 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003531 for (i = 0; i < NUM_TX_QUEUES; i++)
3532 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003533
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003534 for (i = 0; i < NUM_TX_QUEUES; i++)
3535 for (j = 0; j < AP_MAX_LINKS; j++)
3536 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3537
Ido Yariva6208652011-03-01 15:14:41 +02003538 skb_queue_head_init(&wl->deferred_rx_queue);
3539 skb_queue_head_init(&wl->deferred_tx_queue);
3540
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003541 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003542 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003543 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003544 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3545 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3546 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003547 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003548 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003549 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003550 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003551 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3552 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003553 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003554 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003555 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003556 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003557 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003558 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003559 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003560 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003561 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003562 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003563 wl->bss_type = MAX_BSS_TYPE;
3564 wl->set_bss_type = MAX_BSS_TYPE;
3565 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003566 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003567 wl->ap_ps_map = 0;
3568 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003569 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003570 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003571
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003572 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003573 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003574 wl->tx_frames[i] = NULL;
3575
3576 spin_lock_init(&wl->wl_lock);
3577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578 wl->state = WL1271_STATE_OFF;
3579 mutex_init(&wl->mutex);
3580
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003581 /* Apply default driver configuration. */
3582 wl1271_conf_init(wl);
3583
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003584 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3585 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3586 if (!wl->aggr_buf) {
3587 ret = -ENOMEM;
3588 goto err_hw;
3589 }
3590
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003591 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003592 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003593 if (ret) {
3594 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003595 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003596 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003597 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003598
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003599 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003600 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003601 if (ret < 0) {
3602 wl1271_error("failed to create sysfs file bt_coex_state");
3603 goto err_platform;
3604 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003605
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003606 /* Create sysfs file to get HW PG version */
3607 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3608 if (ret < 0) {
3609 wl1271_error("failed to create sysfs file hw_pg_ver");
3610 goto err_bt_coex_state;
3611 }
3612
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003613 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003614
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003615err_bt_coex_state:
3616 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3617
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003618err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003619 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003620
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003621err_aggr:
3622 free_pages((unsigned long)wl->aggr_buf, order);
3623
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003624err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003625 wl1271_debugfs_exit(wl);
3626 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003627
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003628err_plat_alloc:
3629 ieee80211_free_hw(hw);
3630
3631err_hw_alloc:
3632
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003633 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003634}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003635EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003636
3637int wl1271_free_hw(struct wl1271 *wl)
3638{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003639 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003640 free_pages((unsigned long)wl->aggr_buf,
3641 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003642 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003643
3644 wl1271_debugfs_exit(wl);
3645
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003646 vfree(wl->fw);
3647 wl->fw = NULL;
3648 kfree(wl->nvs);
3649 wl->nvs = NULL;
3650
3651 kfree(wl->fw_status);
3652 kfree(wl->tx_res_if);
3653
3654 ieee80211_free_hw(wl->hw);
3655
3656 return 0;
3657}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003658EXPORT_SYMBOL_GPL(wl1271_free_hw);
3659
Guy Eilam491bbd62011-01-12 10:33:29 +01003660u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003661EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003662module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003663MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3664
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003665MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003666MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003667MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");