blob: e1fd005dd04833980d39fb5d8c0010153b31da7d [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200259 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_nullfunc_retries = 3,
261 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300262 .keep_alive_interval = 55000,
263 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200265 .itrim = {
266 .enable = false,
267 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200268 },
269 .pm_config = {
270 .host_clk_settling_time = 5000,
271 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300272 },
273 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 .trigger_pacing = 1,
275 .avg_weight_rssi_beacon = 20,
276 .avg_weight_rssi_data = 10,
277 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100278 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200279 },
280 .scan = {
281 .min_dwell_time_active = 7500,
282 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100283 .min_dwell_time_passive = 100000,
284 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200285 .num_probe_reqs = 2,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
300 },
Eliad Pellerc8bde242011-02-02 09:59:35 +0200301 .mem = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 70,
305 .tx_min_block_num = 40,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200306 .dynamic_memory = 0,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200307 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
310 }
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300311};
312
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200313static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200314static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200315
316
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200317static void wl1271_device_release(struct device *dev)
318{
319
320}
321
322static struct platform_device wl1271_device = {
323 .name = "wl1271",
324 .id = -1,
325
326 /* device model insists to have a release function */
327 .dev = {
328 .release = wl1271_device_release,
329 },
330};
331
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300332static LIST_HEAD(wl_list);
333
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300334static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
335 void *arg)
336{
337 struct net_device *dev = arg;
338 struct wireless_dev *wdev;
339 struct wiphy *wiphy;
340 struct ieee80211_hw *hw;
341 struct wl1271 *wl;
342 struct wl1271 *wl_temp;
343 int ret = 0;
344
345 /* Check that this notification is for us. */
346 if (what != NETDEV_CHANGE)
347 return NOTIFY_DONE;
348
349 wdev = dev->ieee80211_ptr;
350 if (wdev == NULL)
351 return NOTIFY_DONE;
352
353 wiphy = wdev->wiphy;
354 if (wiphy == NULL)
355 return NOTIFY_DONE;
356
357 hw = wiphy_priv(wiphy);
358 if (hw == NULL)
359 return NOTIFY_DONE;
360
361 wl_temp = hw->priv;
362 list_for_each_entry(wl, &wl_list, list) {
363 if (wl == wl_temp)
364 break;
365 }
366 if (wl != wl_temp)
367 return NOTIFY_DONE;
368
369 mutex_lock(&wl->mutex);
370
371 if (wl->state == WL1271_STATE_OFF)
372 goto out;
373
374 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
375 goto out;
376
Ido Yariva6208652011-03-01 15:14:41 +0200377 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300378 if (ret < 0)
379 goto out;
380
381 if ((dev->operstate == IF_OPER_UP) &&
382 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
383 wl1271_cmd_set_sta_state(wl);
384 wl1271_info("Association completed.");
385 }
386
387 wl1271_ps_elp_sleep(wl);
388
389out:
390 mutex_unlock(&wl->mutex);
391
392 return NOTIFY_OK;
393}
394
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100395static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200396 struct regulatory_request *request)
397{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100398 struct ieee80211_supported_band *band;
399 struct ieee80211_channel *ch;
400 int i;
401
402 band = wiphy->bands[IEEE80211_BAND_5GHZ];
403 for (i = 0; i < band->n_channels; i++) {
404 ch = &band->channels[i];
405 if (ch->flags & IEEE80211_CHAN_DISABLED)
406 continue;
407
408 if (ch->flags & IEEE80211_CHAN_RADAR)
409 ch->flags |= IEEE80211_CHAN_NO_IBSS |
410 IEEE80211_CHAN_PASSIVE_SCAN;
411
412 }
413
414 return 0;
415}
416
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417static void wl1271_conf_init(struct wl1271 *wl)
418{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300419
420 /*
421 * This function applies the default configuration to the driver. This
422 * function is invoked upon driver load (spi probe.)
423 *
424 * The configuration is stored in a run-time structure in order to
425 * facilitate for run-time adjustment of any of the parameters. Making
426 * changes to the configuration structure will apply the new values on
427 * the next interface up (wl1271_op_start.)
428 */
429
430 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300431 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300432}
433
434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435static int wl1271_plt_init(struct wl1271 *wl)
436{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200437 struct conf_tx_ac_category *conf_ac;
438 struct conf_tx_tid *conf_tid;
439 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440
Shahar Levi49d750ca2011-03-06 16:32:09 +0200441 if (wl->chip.id == CHIP_ID_1283_PG20)
442 ret = wl128x_cmd_general_parms(wl);
443 else
444 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200445 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200446 return ret;
447
Shahar Levi49d750ca2011-03-06 16:32:09 +0200448 if (wl->chip.id == CHIP_ID_1283_PG20)
449 ret = wl128x_cmd_radio_parms(wl);
450 else
451 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200452 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200453 return ret;
454
Shahar Levi49d750ca2011-03-06 16:32:09 +0200455 if (wl->chip.id != CHIP_ID_1283_PG20) {
456 ret = wl1271_cmd_ext_radio_parms(wl);
457 if (ret < 0)
458 return ret;
459 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200460 if (ret < 0)
461 return ret;
462
Shahar Levi48a61472011-03-06 16:32:08 +0200463 /* Chip-specific initializations */
464 ret = wl1271_chip_specific_init(wl);
465 if (ret < 0)
466 return ret;
467
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200468 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200469 if (ret < 0)
470 return ret;
471
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 ret = wl1271_acx_init_mem_config(wl);
473 if (ret < 0)
474 return ret;
475
Luciano Coelho12419cc2010-02-18 13:25:44 +0200476 /* PHY layer config */
477 ret = wl1271_init_phy_config(wl);
478 if (ret < 0)
479 goto out_free_memmap;
480
481 ret = wl1271_acx_dco_itrim_params(wl);
482 if (ret < 0)
483 goto out_free_memmap;
484
485 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200486 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200487 if (ret < 0)
488 goto out_free_memmap;
489
490 /* Bluetooth WLAN coexistence */
491 ret = wl1271_init_pta(wl);
492 if (ret < 0)
493 goto out_free_memmap;
494
495 /* Energy detection */
496 ret = wl1271_init_energy_detection(wl);
497 if (ret < 0)
498 goto out_free_memmap;
499
Gery Kahn1ec610e2011-02-01 03:03:08 -0600500 ret = wl1271_acx_sta_mem_cfg(wl);
501 if (ret < 0)
502 goto out_free_memmap;
503
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100505 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200506 if (ret < 0)
507 goto out_free_memmap;
508
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200509 /* Default TID/AC configuration */
510 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200511 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200512 conf_ac = &wl->conf.tx.ac_conf[i];
513 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
514 conf_ac->cw_max, conf_ac->aifsn,
515 conf_ac->tx_op_limit);
516 if (ret < 0)
517 goto out_free_memmap;
518
Luciano Coelho12419cc2010-02-18 13:25:44 +0200519 conf_tid = &wl->conf.tx.tid_conf[i];
520 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
521 conf_tid->channel_type,
522 conf_tid->tsid,
523 conf_tid->ps_scheme,
524 conf_tid->ack_policy,
525 conf_tid->apsd_conf[0],
526 conf_tid->apsd_conf[1]);
527 if (ret < 0)
528 goto out_free_memmap;
529 }
530
Luciano Coelho12419cc2010-02-18 13:25:44 +0200531 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200532 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300533 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200534 goto out_free_memmap;
535
536 /* Configure for CAM power saving (ie. always active) */
537 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
538 if (ret < 0)
539 goto out_free_memmap;
540
541 /* configure PM */
542 ret = wl1271_acx_pm_config(wl);
543 if (ret < 0)
544 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300545
546 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200547
548 out_free_memmap:
549 kfree(wl->target_mem_map);
550 wl->target_mem_map = NULL;
551
552 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300553}
554
Arik Nemtsovb622d992011-02-23 00:22:31 +0200555static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
556{
557 bool fw_ps;
558
559 /* only regulate station links */
560 if (hlid < WL1271_AP_STA_HLID_START)
561 return;
562
563 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
564
565 /*
566 * Wake up from high level PS if the STA is asleep with too little
567 * blocks in FW or if the STA is awake.
568 */
569 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
570 wl1271_ps_link_end(wl, hlid);
571
572 /* Start high-level PS if the STA is asleep with enough blocks in FW */
573 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
574 wl1271_ps_link_start(wl, hlid, true);
575}
576
577static void wl1271_irq_update_links_status(struct wl1271 *wl,
578 struct wl1271_fw_ap_status *status)
579{
580 u32 cur_fw_ps_map;
581 u8 hlid;
582
583 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
584 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
585 wl1271_debug(DEBUG_PSM,
586 "link ps prev 0x%x cur 0x%x changed 0x%x",
587 wl->ap_fw_ps_map, cur_fw_ps_map,
588 wl->ap_fw_ps_map ^ cur_fw_ps_map);
589
590 wl->ap_fw_ps_map = cur_fw_ps_map;
591 }
592
593 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
594 u8 cnt = status->tx_lnk_free_blks[hlid] -
595 wl->links[hlid].prev_freed_blks;
596
597 wl->links[hlid].prev_freed_blks =
598 status->tx_lnk_free_blks[hlid];
599 wl->links[hlid].allocated_blks -= cnt;
600
601 wl1271_irq_ps_regulate_link(wl, hlid,
602 wl->links[hlid].allocated_blks);
603 }
604}
605
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300606static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200607 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200609 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200610 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611 u32 total = 0;
612 int i;
613
Eliad Pellerc8bde242011-02-02 09:59:35 +0200614 if (wl->bss_type == BSS_TYPE_AP_BSS)
615 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
616 sizeof(struct wl1271_fw_ap_status), false);
617 else
618 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
619 sizeof(struct wl1271_fw_sta_status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300620
621 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
622 "drv_rx_counter = %d, tx_results_counter = %d)",
623 status->intr,
624 status->fw_rx_counter,
625 status->drv_rx_counter,
626 status->tx_results_counter);
627
628 /* update number of available TX blocks */
629 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300630 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
631 wl->tx_blocks_freed[i];
632
633 wl->tx_blocks_freed[i] =
634 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635 wl->tx_blocks_available += cnt;
636 total += cnt;
637 }
638
Ido Yariva5225502010-10-12 14:49:10 +0200639 /* if more blocks are available now, tx work can be scheduled */
640 if (total)
641 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300642
Arik Nemtsovb622d992011-02-23 00:22:31 +0200643 /* for AP update num of allocated TX blocks per link and ps status */
644 if (wl->bss_type == BSS_TYPE_AP_BSS)
645 wl1271_irq_update_links_status(wl, &full_status->ap);
Arik Nemtsov09039f42011-02-23 00:22:30 +0200646
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200648 getnstimeofday(&ts);
649 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
650 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651}
652
Ido Yariva6208652011-03-01 15:14:41 +0200653static void wl1271_flush_deferred_work(struct wl1271 *wl)
654{
655 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200656
Ido Yariva6208652011-03-01 15:14:41 +0200657 /* Pass all received frames to the network stack */
658 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
659 ieee80211_rx_ni(wl->hw, skb);
660
661 /* Return sent skbs to the network stack */
662 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
663 ieee80211_tx_status(wl->hw, skb);
664}
665
666static void wl1271_netstack_work(struct work_struct *work)
667{
668 struct wl1271 *wl =
669 container_of(work, struct wl1271, netstack_work);
670
671 do {
672 wl1271_flush_deferred_work(wl);
673 } while (skb_queue_len(&wl->deferred_rx_queue));
674}
675
676#define WL1271_IRQ_MAX_LOOPS 256
677
678irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300681 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200682 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200683 struct wl1271 *wl = (struct wl1271 *)cookie;
684 bool done = false;
685 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200686 unsigned long flags;
687
688 /* TX might be handled here, avoid redundant work */
689 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
690 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691
692 mutex_lock(&wl->mutex);
693
694 wl1271_debug(DEBUG_IRQ, "IRQ work");
695
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200696 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697 goto out;
698
Ido Yariva6208652011-03-01 15:14:41 +0200699 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 if (ret < 0)
701 goto out;
702
Ido Yariva6208652011-03-01 15:14:41 +0200703 while (!done && loopcount--) {
704 /*
705 * In order to avoid a race with the hardirq, clear the flag
706 * before acknowledging the chip. Since the mutex is held,
707 * wl1271_ps_elp_wakeup cannot be called concurrently.
708 */
709 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
710 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200711
712 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200713 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200714 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200715 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200716 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200717 continue;
718 }
719
Eliad Pellerccc83b02010-10-27 14:09:57 +0200720 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
721 wl1271_error("watchdog interrupt received! "
722 "starting recovery.");
723 ieee80211_queue_work(wl->hw, &wl->recovery_work);
724
725 /* restarting the chip. ignore any other interrupt. */
726 goto out;
727 }
728
Ido Yariva6208652011-03-01 15:14:41 +0200729 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200730 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
731
Ido Yariv8aad2462011-03-01 15:14:38 +0200732 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200733
Ido Yariva5225502010-10-12 14:49:10 +0200734 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200735 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200736 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200737 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200738 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200739 /*
740 * In order to avoid starvation of the TX path,
741 * call the work function directly.
742 */
743 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200744 } else {
745 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200746 }
747
Ido Yariv8aad2462011-03-01 15:14:38 +0200748 /* check for tx results */
749 if (wl->fw_status->common.tx_results_counter !=
750 (wl->tx_results_count & 0xff))
751 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200752
753 /* Make sure the deferred queues don't get too long */
754 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
755 skb_queue_len(&wl->deferred_rx_queue);
756 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
757 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200758 }
759
760 if (intr & WL1271_ACX_INTR_EVENT_A) {
761 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
762 wl1271_event_handle(wl, 0);
763 }
764
765 if (intr & WL1271_ACX_INTR_EVENT_B) {
766 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
767 wl1271_event_handle(wl, 1);
768 }
769
770 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
771 wl1271_debug(DEBUG_IRQ,
772 "WL1271_ACX_INTR_INIT_COMPLETE");
773
774 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
775 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776 }
777
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 wl1271_ps_elp_sleep(wl);
779
780out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200781 spin_lock_irqsave(&wl->wl_lock, flags);
782 /* In case TX was not handled here, queue TX work */
783 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
784 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
785 wl->tx_queue_count)
786 ieee80211_queue_work(wl->hw, &wl->tx_work);
787 spin_unlock_irqrestore(&wl->wl_lock, flags);
788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200790
791 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792}
Ido Yariva6208652011-03-01 15:14:41 +0200793EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300794
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795static int wl1271_fetch_firmware(struct wl1271 *wl)
796{
797 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200798 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300799 int ret;
800
Arik Nemtsov166d5042010-10-16 21:44:57 +0200801 switch (wl->bss_type) {
802 case BSS_TYPE_AP_BSS:
803 fw_name = WL1271_AP_FW_NAME;
804 break;
805 case BSS_TYPE_IBSS:
806 case BSS_TYPE_STA_BSS:
807 fw_name = WL1271_FW_NAME;
808 break;
809 default:
810 wl1271_error("no compatible firmware for bss_type %d",
811 wl->bss_type);
812 return -EINVAL;
813 }
814
815 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
816
817 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300818
819 if (ret < 0) {
820 wl1271_error("could not get firmware: %d", ret);
821 return ret;
822 }
823
824 if (fw->size % 4) {
825 wl1271_error("firmware size is not multiple of 32 bits: %zu",
826 fw->size);
827 ret = -EILSEQ;
828 goto out;
829 }
830
Arik Nemtsov166d5042010-10-16 21:44:57 +0200831 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300833 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
835 if (!wl->fw) {
836 wl1271_error("could not allocate memory for the firmware");
837 ret = -ENOMEM;
838 goto out;
839 }
840
841 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200842 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 ret = 0;
844
845out:
846 release_firmware(fw);
847
848 return ret;
849}
850
851static int wl1271_fetch_nvs(struct wl1271 *wl)
852{
853 const struct firmware *fw;
854 int ret;
855
Shahar Levi5aa42342011-03-06 16:32:07 +0200856 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300857
858 if (ret < 0) {
859 wl1271_error("could not get nvs file: %d", ret);
860 return ret;
861 }
862
Julia Lawall929ebd32010-05-15 23:16:39 +0200863 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864
865 if (!wl->nvs) {
866 wl1271_error("could not allocate memory for the nvs file");
867 ret = -ENOMEM;
868 goto out;
869 }
870
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200871 wl->nvs_len = fw->size;
872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873out:
874 release_firmware(fw);
875
876 return ret;
877}
878
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200879static void wl1271_recovery_work(struct work_struct *work)
880{
881 struct wl1271 *wl =
882 container_of(work, struct wl1271, recovery_work);
883
884 mutex_lock(&wl->mutex);
885
886 if (wl->state != WL1271_STATE_ON)
887 goto out;
888
889 wl1271_info("Hardware recovery in progress.");
890
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200891 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
892 ieee80211_connection_loss(wl->vif);
893
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200894 /* reboot the chipset */
895 __wl1271_op_remove_interface(wl);
896 ieee80211_restart_hw(wl->hw);
897
898out:
899 mutex_unlock(&wl->mutex);
900}
901
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902static void wl1271_fw_wakeup(struct wl1271 *wl)
903{
904 u32 elp_reg;
905
906 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300907 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908}
909
910static int wl1271_setup(struct wl1271 *wl)
911{
912 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
913 if (!wl->fw_status)
914 return -ENOMEM;
915
916 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
917 if (!wl->tx_res_if) {
918 kfree(wl->fw_status);
919 return -ENOMEM;
920 }
921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300922 return 0;
923}
924
925static int wl1271_chip_wakeup(struct wl1271 *wl)
926{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300927 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 int ret = 0;
929
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +0200930 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200931 ret = wl1271_power_on(wl);
932 if (ret < 0)
933 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200935 wl1271_io_reset(wl);
936 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
938 /* We don't need a real memory partition here, because we only want
939 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300940 memset(&partition, 0, sizeof(partition));
941 partition.reg.start = REGISTERS_BASE;
942 partition.reg.size = REGISTERS_DOWN_SIZE;
943 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944
945 /* ELP module wake up */
946 wl1271_fw_wakeup(wl);
947
948 /* whal_FwCtrl_BootSm() */
949
950 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200951 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952
953 /* 1. check if chip id is valid */
954
955 switch (wl->chip.id) {
956 case CHIP_ID_1271_PG10:
957 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
958 wl->chip.id);
959
960 ret = wl1271_setup(wl);
961 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200962 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 break;
964 case CHIP_ID_1271_PG20:
965 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
966 wl->chip.id);
967
968 ret = wl1271_setup(wl);
969 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200970 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 break;
972 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200973 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200975 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 }
977
Arik Nemtsov166d5042010-10-16 21:44:57 +0200978 /* Make sure the firmware type matches the BSS type */
979 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 ret = wl1271_fetch_firmware(wl);
981 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200982 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 }
984
985 /* No NVS from netlink, try to get it from the filesystem */
986 if (wl->nvs == NULL) {
987 ret = wl1271_fetch_nvs(wl);
988 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200989 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 }
991
992out:
993 return ret;
994}
995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996int wl1271_plt_start(struct wl1271 *wl)
997{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200998 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 int ret;
1000
1001 mutex_lock(&wl->mutex);
1002
1003 wl1271_notice("power up");
1004
1005 if (wl->state != WL1271_STATE_OFF) {
1006 wl1271_error("cannot go into PLT state because not "
1007 "in off state: %d", wl->state);
1008 ret = -EBUSY;
1009 goto out;
1010 }
1011
Arik Nemtsov166d5042010-10-16 21:44:57 +02001012 wl->bss_type = BSS_TYPE_STA_BSS;
1013
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001014 while (retries) {
1015 retries--;
1016 ret = wl1271_chip_wakeup(wl);
1017 if (ret < 0)
1018 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001020 ret = wl1271_boot(wl);
1021 if (ret < 0)
1022 goto power_off;
1023
1024 ret = wl1271_plt_init(wl);
1025 if (ret < 0)
1026 goto irq_disable;
1027
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001028 wl->state = WL1271_STATE_PLT;
1029 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001030 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 goto out;
1032
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001033irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001034 mutex_unlock(&wl->mutex);
1035 /* Unlocking the mutex in the middle of handling is
1036 inherently unsafe. In this case we deem it safe to do,
1037 because we need to let any possibly pending IRQ out of
1038 the system (and while we are WL1271_STATE_OFF the IRQ
1039 work function will not do anything.) Also, any other
1040 possible concurrent operations will fail due to the
1041 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001042 wl1271_disable_interrupts(wl);
1043 wl1271_flush_deferred_work(wl);
1044 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001045 mutex_lock(&wl->mutex);
1046power_off:
1047 wl1271_power_off(wl);
1048 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001050 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1051 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052out:
1053 mutex_unlock(&wl->mutex);
1054
1055 return ret;
1056}
1057
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001058int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059{
1060 int ret = 0;
1061
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 wl1271_notice("power down");
1063
1064 if (wl->state != WL1271_STATE_PLT) {
1065 wl1271_error("cannot power down because not in PLT "
1066 "state: %d", wl->state);
1067 ret = -EBUSY;
1068 goto out;
1069 }
1070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 wl1271_power_off(wl);
1072
1073 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001074 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001077 wl1271_disable_interrupts(wl);
1078 wl1271_flush_deferred_work(wl);
1079 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001080 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001081 mutex_lock(&wl->mutex);
1082out:
1083 return ret;
1084}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001085
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001086int wl1271_plt_stop(struct wl1271 *wl)
1087{
1088 int ret;
1089
1090 mutex_lock(&wl->mutex);
1091 ret = __wl1271_plt_stop(wl);
1092 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093 return ret;
1094}
1095
Johannes Berg7bb45682011-02-24 14:42:06 +01001096static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097{
1098 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001099 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001100 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001101 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102
Ido Yarivb07d4032011-03-01 15:14:43 +02001103 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1104
1105 if (wl->bss_type == BSS_TYPE_AP_BSS)
1106 hlid = wl1271_tx_get_hlid(skb);
1107
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001108 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001109
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001110 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001111
1112 /*
1113 * The workqueue is slow to process the tx_queue and we need stop
1114 * the queue here, otherwise the queue will get too long.
1115 */
1116 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1117 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1118 ieee80211_stop_queues(wl->hw);
1119 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1120 }
1121
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001122 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001123 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001124 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1125 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1126 } else {
1127 skb_queue_tail(&wl->tx_queue[q], skb);
1128 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129
1130 /*
1131 * The chip specific setup must run before the first TX packet -
1132 * before that, the tx_work will not be initialized!
1133 */
1134
Ido Yarivb07d4032011-03-01 15:14:43 +02001135 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1136 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001137 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001138
1139 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140}
1141
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001142static struct notifier_block wl1271_dev_notifier = {
1143 .notifier_call = wl1271_dev_notify,
1144};
1145
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146static int wl1271_op_start(struct ieee80211_hw *hw)
1147{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001148 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1149
1150 /*
1151 * We have to delay the booting of the hardware because
1152 * we need to know the local MAC address before downloading and
1153 * initializing the firmware. The MAC address cannot be changed
1154 * after boot, and without the proper MAC address, the firmware
1155 * will not function properly.
1156 *
1157 * The MAC address is first known when the corresponding interface
1158 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001159 *
1160 * In addition, we currently have different firmwares for AP and managed
1161 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001162 */
1163
1164 return 0;
1165}
1166
1167static void wl1271_op_stop(struct ieee80211_hw *hw)
1168{
1169 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1170}
1171
1172static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1173 struct ieee80211_vif *vif)
1174{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001176 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001177 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001179 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001180
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001181 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1182 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183
1184 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001185 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001186 wl1271_debug(DEBUG_MAC80211,
1187 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001188 ret = -EBUSY;
1189 goto out;
1190 }
1191
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001192 switch (vif->type) {
1193 case NL80211_IFTYPE_STATION:
1194 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001195 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001196 break;
1197 case NL80211_IFTYPE_ADHOC:
1198 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001199 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001200 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001201 case NL80211_IFTYPE_AP:
1202 wl->bss_type = BSS_TYPE_AP_BSS;
1203 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001204 default:
1205 ret = -EOPNOTSUPP;
1206 goto out;
1207 }
1208
1209 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210
1211 if (wl->state != WL1271_STATE_OFF) {
1212 wl1271_error("cannot start because not in off state: %d",
1213 wl->state);
1214 ret = -EBUSY;
1215 goto out;
1216 }
1217
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001218 while (retries) {
1219 retries--;
1220 ret = wl1271_chip_wakeup(wl);
1221 if (ret < 0)
1222 goto power_off;
1223
1224 ret = wl1271_boot(wl);
1225 if (ret < 0)
1226 goto power_off;
1227
1228 ret = wl1271_hw_init(wl);
1229 if (ret < 0)
1230 goto irq_disable;
1231
Eliad Peller71125ab2010-10-28 21:46:43 +02001232 booted = true;
1233 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001235irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001236 mutex_unlock(&wl->mutex);
1237 /* Unlocking the mutex in the middle of handling is
1238 inherently unsafe. In this case we deem it safe to do,
1239 because we need to let any possibly pending IRQ out of
1240 the system (and while we are WL1271_STATE_OFF the IRQ
1241 work function will not do anything.) Also, any other
1242 possible concurrent operations will fail due to the
1243 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001244 wl1271_disable_interrupts(wl);
1245 wl1271_flush_deferred_work(wl);
1246 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001247 mutex_lock(&wl->mutex);
1248power_off:
1249 wl1271_power_off(wl);
1250 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251
Eliad Peller71125ab2010-10-28 21:46:43 +02001252 if (!booted) {
1253 wl1271_error("firmware boot failed despite %d retries",
1254 WL1271_BOOT_RETRIES);
1255 goto out;
1256 }
1257
1258 wl->vif = vif;
1259 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001260 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001261
1262 /* update hw/fw version info in wiphy struct */
1263 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001264 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001265 sizeof(wiphy->fw_version));
1266
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001267 /*
1268 * Now we know if 11a is supported (info from the NVS), so disable
1269 * 11a channels if not supported
1270 */
1271 if (!wl->enable_11a)
1272 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1273
1274 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1275 wl->enable_11a ? "" : "not ");
1276
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001277out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278 mutex_unlock(&wl->mutex);
1279
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001280 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001281 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001282
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 return ret;
1284}
1285
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001286static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 int i;
1289
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001290 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001292 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001294 list_del(&wl->list);
1295
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 WARN_ON(wl->state != WL1271_STATE_ON);
1297
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001298 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001299 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001300 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001301
Luciano Coelho08688d62010-07-08 17:50:07 +03001302 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001303 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1304 kfree(wl->scan.scanned_ch);
1305 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001306 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001307 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001308 }
1309
1310 wl->state = WL1271_STATE_OFF;
1311
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 mutex_unlock(&wl->mutex);
1313
Ido Yariva6208652011-03-01 15:14:41 +02001314 wl1271_disable_interrupts(wl);
1315 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001316 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001317 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001319 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001320 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321
1322 mutex_lock(&wl->mutex);
1323
1324 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001325 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 wl1271_power_off(wl);
1327
1328 memset(wl->bssid, 0, ETH_ALEN);
1329 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1330 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001332 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001333 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334
1335 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001336 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1338 wl->tx_blocks_available = 0;
1339 wl->tx_results_count = 0;
1340 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001341 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001342 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 wl->time_offset = 0;
1344 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001345 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001346 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001347 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001348 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001349 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001350 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001351 wl->ap_fw_ps_map = 0;
1352 wl->ap_ps_map = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02001353 wl->block_size = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 for (i = 0; i < NUM_TX_QUEUES; i++)
1356 wl->tx_blocks_freed[i] = 0;
1357
1358 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001359
1360 kfree(wl->fw_status);
1361 wl->fw_status = NULL;
1362 kfree(wl->tx_res_if);
1363 wl->tx_res_if = NULL;
1364 kfree(wl->target_mem_map);
1365 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001366}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001367
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001368static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1369 struct ieee80211_vif *vif)
1370{
1371 struct wl1271 *wl = hw->priv;
1372
1373 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001374 /*
1375 * wl->vif can be null here if someone shuts down the interface
1376 * just when hardware recovery has been started.
1377 */
1378 if (wl->vif) {
1379 WARN_ON(wl->vif != vif);
1380 __wl1271_op_remove_interface(wl);
1381 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001382
Juuso Oikarinen67353292010-11-18 15:19:02 +02001383 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001384 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385}
1386
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001387static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1388{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001389 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001390
1391 /* combine requested filters with current filter config */
1392 filters = wl->filters | filters;
1393
1394 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1395
1396 if (filters & FIF_PROMISC_IN_BSS) {
1397 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1398 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1399 wl->rx_config |= CFG_BSSID_FILTER_EN;
1400 }
1401 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1402 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1403 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1404 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1405 }
1406 if (filters & FIF_OTHER_BSS) {
1407 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1408 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1409 }
1410 if (filters & FIF_CONTROL) {
1411 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1412 wl->rx_filter |= CFG_RX_CTL_EN;
1413 }
1414 if (filters & FIF_FCSFAIL) {
1415 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1416 wl->rx_filter |= CFG_RX_FCS_ERROR;
1417 }
1418}
1419
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001420static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001421{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001422 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001423 /* we need to use a dummy BSSID for now */
1424 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1425 0xad, 0xbe, 0xef };
1426
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001427 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1428
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001429 /* pass through frames from all BSS */
1430 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1431
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001432 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001433 if (ret < 0)
1434 goto out;
1435
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001436 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001437
1438out:
1439 return ret;
1440}
1441
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001442static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001443{
1444 int ret;
1445
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001446 /*
1447 * One of the side effects of the JOIN command is that is clears
1448 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1449 * to a WPA/WPA2 access point will therefore kill the data-path.
1450 * Currently there is no supported scenario for JOIN during
1451 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1452 * must be handled somehow.
1453 *
1454 */
1455 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1456 wl1271_info("JOIN while associated.");
1457
1458 if (set_assoc)
1459 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1460
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001461 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1462 if (ret < 0)
1463 goto out;
1464
1465 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1466
1467 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1468 goto out;
1469
1470 /*
1471 * The join command disable the keep-alive mode, shut down its process,
1472 * and also clear the template config, so we need to reset it all after
1473 * the join. The acx_aid starts the keep-alive process, and the order
1474 * of the commands below is relevant.
1475 */
1476 ret = wl1271_acx_keep_alive_mode(wl, true);
1477 if (ret < 0)
1478 goto out;
1479
1480 ret = wl1271_acx_aid(wl, wl->aid);
1481 if (ret < 0)
1482 goto out;
1483
1484 ret = wl1271_cmd_build_klv_null_data(wl);
1485 if (ret < 0)
1486 goto out;
1487
1488 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1489 ACX_KEEP_ALIVE_TPL_VALID);
1490 if (ret < 0)
1491 goto out;
1492
1493out:
1494 return ret;
1495}
1496
1497static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001498{
1499 int ret;
1500
1501 /* to stop listening to a channel, we disconnect */
1502 ret = wl1271_cmd_disconnect(wl);
1503 if (ret < 0)
1504 goto out;
1505
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001506 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001507 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001508
1509 /* stop filterting packets based on bssid */
1510 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001511
1512out:
1513 return ret;
1514}
1515
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001516static void wl1271_set_band_rate(struct wl1271 *wl)
1517{
1518 if (wl->band == IEEE80211_BAND_2GHZ)
1519 wl->basic_rate_set = wl->conf.tx.basic_rate;
1520 else
1521 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1522}
1523
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001524static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001525{
1526 int ret;
1527
1528 if (idle) {
1529 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1530 ret = wl1271_unjoin(wl);
1531 if (ret < 0)
1532 goto out;
1533 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001534 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001535 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001536 if (ret < 0)
1537 goto out;
1538 ret = wl1271_acx_keep_alive_config(
1539 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1540 ACX_KEEP_ALIVE_TPL_INVALID);
1541 if (ret < 0)
1542 goto out;
1543 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1544 } else {
1545 /* increment the session counter */
1546 wl->session_counter++;
1547 if (wl->session_counter >= SESSION_COUNTER_MAX)
1548 wl->session_counter = 0;
1549 ret = wl1271_dummy_join(wl);
1550 if (ret < 0)
1551 goto out;
1552 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1553 }
1554
1555out:
1556 return ret;
1557}
1558
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1560{
1561 struct wl1271 *wl = hw->priv;
1562 struct ieee80211_conf *conf = &hw->conf;
1563 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001564 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001565
1566 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1567
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001568 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1569 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 channel,
1571 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001572 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001573 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1574 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001576 /*
1577 * mac80211 will go to idle nearly immediately after transmitting some
1578 * frames, such as the deauth. To make sure those frames reach the air,
1579 * wait here until the TX queue is fully flushed.
1580 */
1581 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1582 (conf->flags & IEEE80211_CONF_IDLE))
1583 wl1271_tx_flush(wl);
1584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 mutex_lock(&wl->mutex);
1586
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001587 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1588 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001589 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001590 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001591
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001592 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1593
Ido Yariva6208652011-03-01 15:14:41 +02001594 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595 if (ret < 0)
1596 goto out;
1597
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001598 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001599 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1600 ((wl->band != conf->channel->band) ||
1601 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001602 wl->band = conf->channel->band;
1603 wl->channel = channel;
1604
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001605 if (!is_ap) {
1606 /*
1607 * FIXME: the mac80211 should really provide a fixed
1608 * rate to use here. for now, just use the smallest
1609 * possible rate for the band as a fixed rate for
1610 * association frames and other control messages.
1611 */
1612 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1613 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001614
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001615 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1616 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001617 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001618 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001619 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001620
1621 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1622 ret = wl1271_join(wl, false);
1623 if (ret < 0)
1624 wl1271_warning("cmd join on channel "
1625 "failed %d", ret);
1626 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001627 }
1628 }
1629
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001630 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1631 ret = wl1271_sta_handle_idle(wl,
1632 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001633 if (ret < 0)
1634 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001635 }
1636
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001637 /*
1638 * if mac80211 changes the PSM mode, make sure the mode is not
1639 * incorrectly changed after the pspoll failure active window.
1640 */
1641 if (changed & IEEE80211_CONF_CHANGE_PS)
1642 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1643
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001644 if (conf->flags & IEEE80211_CONF_PS &&
1645 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1646 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001647
1648 /*
1649 * We enter PSM only if we're already associated.
1650 * If we're not, we'll enter it when joining an SSID,
1651 * through the bss_info_changed() hook.
1652 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001653 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001654 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001655 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001656 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001657 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001659 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001660 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001662 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001664 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001665 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001666 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667 }
1668
1669 if (conf->power_level != wl->power_level) {
1670 ret = wl1271_acx_tx_power(wl, conf->power_level);
1671 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001672 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001673
1674 wl->power_level = conf->power_level;
1675 }
1676
1677out_sleep:
1678 wl1271_ps_elp_sleep(wl);
1679
1680out:
1681 mutex_unlock(&wl->mutex);
1682
1683 return ret;
1684}
1685
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001686struct wl1271_filter_params {
1687 bool enabled;
1688 int mc_list_length;
1689 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1690};
1691
Jiri Pirko22bedad2010-04-01 21:22:57 +00001692static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1693 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001694{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001695 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001696 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001697 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001698
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001699 if (unlikely(wl->state == WL1271_STATE_OFF))
1700 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001701
Juuso Oikarinen74441132009-10-13 12:47:53 +03001702 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001703 if (!fp) {
1704 wl1271_error("Out of memory setting filters.");
1705 return 0;
1706 }
1707
1708 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001709 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001710 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1711 fp->enabled = false;
1712 } else {
1713 fp->enabled = true;
1714 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001715 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001716 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001717 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001718 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001719 }
1720
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001721 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001722}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001724#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1725 FIF_ALLMULTI | \
1726 FIF_FCSFAIL | \
1727 FIF_BCN_PRBRESP_PROMISC | \
1728 FIF_CONTROL | \
1729 FIF_OTHER_BSS)
1730
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1732 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001733 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001734{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001735 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001737 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001738
Arik Nemtsov7d057862010-10-16 19:25:35 +02001739 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1740 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001741
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001742 mutex_lock(&wl->mutex);
1743
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001744 *total &= WL1271_SUPPORTED_FILTERS;
1745 changed &= WL1271_SUPPORTED_FILTERS;
1746
1747 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001748 goto out;
1749
Ido Yariva6208652011-03-01 15:14:41 +02001750 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001751 if (ret < 0)
1752 goto out;
1753
Arik Nemtsov7d057862010-10-16 19:25:35 +02001754 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1755 if (*total & FIF_ALLMULTI)
1756 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1757 else if (fp)
1758 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1759 fp->mc_list,
1760 fp->mc_list_length);
1761 if (ret < 0)
1762 goto out_sleep;
1763 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001765 /* determine, whether supported filter values have changed */
1766 if (changed == 0)
1767 goto out_sleep;
1768
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001769 /* configure filters */
1770 wl->filters = *total;
1771 wl1271_configure_filters(wl, 0);
1772
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001773 /* apply configured filters */
1774 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1775 if (ret < 0)
1776 goto out_sleep;
1777
1778out_sleep:
1779 wl1271_ps_elp_sleep(wl);
1780
1781out:
1782 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001783 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001784}
1785
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001786static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1787 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1788 u16 tx_seq_16)
1789{
1790 struct wl1271_ap_key *ap_key;
1791 int i;
1792
1793 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1794
1795 if (key_size > MAX_KEY_SIZE)
1796 return -EINVAL;
1797
1798 /*
1799 * Find next free entry in ap_keys. Also check we are not replacing
1800 * an existing key.
1801 */
1802 for (i = 0; i < MAX_NUM_KEYS; i++) {
1803 if (wl->recorded_ap_keys[i] == NULL)
1804 break;
1805
1806 if (wl->recorded_ap_keys[i]->id == id) {
1807 wl1271_warning("trying to record key replacement");
1808 return -EINVAL;
1809 }
1810 }
1811
1812 if (i == MAX_NUM_KEYS)
1813 return -EBUSY;
1814
1815 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1816 if (!ap_key)
1817 return -ENOMEM;
1818
1819 ap_key->id = id;
1820 ap_key->key_type = key_type;
1821 ap_key->key_size = key_size;
1822 memcpy(ap_key->key, key, key_size);
1823 ap_key->hlid = hlid;
1824 ap_key->tx_seq_32 = tx_seq_32;
1825 ap_key->tx_seq_16 = tx_seq_16;
1826
1827 wl->recorded_ap_keys[i] = ap_key;
1828 return 0;
1829}
1830
1831static void wl1271_free_ap_keys(struct wl1271 *wl)
1832{
1833 int i;
1834
1835 for (i = 0; i < MAX_NUM_KEYS; i++) {
1836 kfree(wl->recorded_ap_keys[i]);
1837 wl->recorded_ap_keys[i] = NULL;
1838 }
1839}
1840
1841static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1842{
1843 int i, ret = 0;
1844 struct wl1271_ap_key *key;
1845 bool wep_key_added = false;
1846
1847 for (i = 0; i < MAX_NUM_KEYS; i++) {
1848 if (wl->recorded_ap_keys[i] == NULL)
1849 break;
1850
1851 key = wl->recorded_ap_keys[i];
1852 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1853 key->id, key->key_type,
1854 key->key_size, key->key,
1855 key->hlid, key->tx_seq_32,
1856 key->tx_seq_16);
1857 if (ret < 0)
1858 goto out;
1859
1860 if (key->key_type == KEY_WEP)
1861 wep_key_added = true;
1862 }
1863
1864 if (wep_key_added) {
1865 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1866 if (ret < 0)
1867 goto out;
1868 }
1869
1870out:
1871 wl1271_free_ap_keys(wl);
1872 return ret;
1873}
1874
1875static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1876 u8 key_size, const u8 *key, u32 tx_seq_32,
1877 u16 tx_seq_16, struct ieee80211_sta *sta)
1878{
1879 int ret;
1880 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1881
1882 if (is_ap) {
1883 struct wl1271_station *wl_sta;
1884 u8 hlid;
1885
1886 if (sta) {
1887 wl_sta = (struct wl1271_station *)sta->drv_priv;
1888 hlid = wl_sta->hlid;
1889 } else {
1890 hlid = WL1271_AP_BROADCAST_HLID;
1891 }
1892
1893 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1894 /*
1895 * We do not support removing keys after AP shutdown.
1896 * Pretend we do to make mac80211 happy.
1897 */
1898 if (action != KEY_ADD_OR_REPLACE)
1899 return 0;
1900
1901 ret = wl1271_record_ap_key(wl, id,
1902 key_type, key_size,
1903 key, hlid, tx_seq_32,
1904 tx_seq_16);
1905 } else {
1906 ret = wl1271_cmd_set_ap_key(wl, action,
1907 id, key_type, key_size,
1908 key, hlid, tx_seq_32,
1909 tx_seq_16);
1910 }
1911
1912 if (ret < 0)
1913 return ret;
1914 } else {
1915 const u8 *addr;
1916 static const u8 bcast_addr[ETH_ALEN] = {
1917 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1918 };
1919
1920 addr = sta ? sta->addr : bcast_addr;
1921
1922 if (is_zero_ether_addr(addr)) {
1923 /* We dont support TX only encryption */
1924 return -EOPNOTSUPP;
1925 }
1926
1927 /* The wl1271 does not allow to remove unicast keys - they
1928 will be cleared automatically on next CMD_JOIN. Ignore the
1929 request silently, as we dont want the mac80211 to emit
1930 an error message. */
1931 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1932 return 0;
1933
1934 ret = wl1271_cmd_set_sta_key(wl, action,
1935 id, key_type, key_size,
1936 key, addr, tx_seq_32,
1937 tx_seq_16);
1938 if (ret < 0)
1939 return ret;
1940
1941 /* the default WEP key needs to be configured at least once */
1942 if (key_type == KEY_WEP) {
1943 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1944 wl->default_key);
1945 if (ret < 0)
1946 return ret;
1947 }
1948 }
1949
1950 return 0;
1951}
1952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1954 struct ieee80211_vif *vif,
1955 struct ieee80211_sta *sta,
1956 struct ieee80211_key_conf *key_conf)
1957{
1958 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001960 u32 tx_seq_32 = 0;
1961 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 u8 key_type;
1963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1965
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001966 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001968 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969 key_conf->keylen, key_conf->flags);
1970 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972 mutex_lock(&wl->mutex);
1973
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001974 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1975 ret = -EAGAIN;
1976 goto out_unlock;
1977 }
1978
Ido Yariva6208652011-03-01 15:14:41 +02001979 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 if (ret < 0)
1981 goto out_unlock;
1982
Johannes Berg97359d12010-08-10 09:46:38 +02001983 switch (key_conf->cipher) {
1984 case WLAN_CIPHER_SUITE_WEP40:
1985 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 key_type = KEY_WEP;
1987
1988 key_conf->hw_key_idx = key_conf->keyidx;
1989 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001990 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991 key_type = KEY_TKIP;
1992
1993 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001994 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1995 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001996 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001997 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998 key_type = KEY_AES;
1999
2000 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002001 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2002 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002004 case WL1271_CIPHER_SUITE_GEM:
2005 key_type = KEY_GEM;
2006 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2007 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2008 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002010 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011
2012 ret = -EOPNOTSUPP;
2013 goto out_sleep;
2014 }
2015
2016 switch (cmd) {
2017 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002018 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2019 key_conf->keyidx, key_type,
2020 key_conf->keylen, key_conf->key,
2021 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 if (ret < 0) {
2023 wl1271_error("Could not add or replace key");
2024 goto out_sleep;
2025 }
2026 break;
2027
2028 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002029 ret = wl1271_set_key(wl, KEY_REMOVE,
2030 key_conf->keyidx, key_type,
2031 key_conf->keylen, key_conf->key,
2032 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 if (ret < 0) {
2034 wl1271_error("Could not remove key");
2035 goto out_sleep;
2036 }
2037 break;
2038
2039 default:
2040 wl1271_error("Unsupported key cmd 0x%x", cmd);
2041 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042 break;
2043 }
2044
2045out_sleep:
2046 wl1271_ps_elp_sleep(wl);
2047
2048out_unlock:
2049 mutex_unlock(&wl->mutex);
2050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051 return ret;
2052}
2053
2054static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002055 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 struct cfg80211_scan_request *req)
2057{
2058 struct wl1271 *wl = hw->priv;
2059 int ret;
2060 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002061 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002062
2063 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2064
2065 if (req->n_ssids) {
2066 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002067 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068 }
2069
2070 mutex_lock(&wl->mutex);
2071
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002072 if (wl->state == WL1271_STATE_OFF) {
2073 /*
2074 * We cannot return -EBUSY here because cfg80211 will expect
2075 * a call to ieee80211_scan_completed if we do - in this case
2076 * there won't be any call.
2077 */
2078 ret = -EAGAIN;
2079 goto out;
2080 }
2081
Ido Yariva6208652011-03-01 15:14:41 +02002082 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002083 if (ret < 0)
2084 goto out;
2085
Luciano Coelho5924f892010-08-04 03:46:22 +03002086 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087
2088 wl1271_ps_elp_sleep(wl);
2089
2090out:
2091 mutex_unlock(&wl->mutex);
2092
2093 return ret;
2094}
2095
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002096static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2097{
2098 struct wl1271 *wl = hw->priv;
2099 int ret = 0;
2100
2101 mutex_lock(&wl->mutex);
2102
2103 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2104 ret = -EAGAIN;
2105 goto out;
2106 }
2107
Ido Yariva6208652011-03-01 15:14:41 +02002108 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002109 if (ret < 0)
2110 goto out;
2111
2112 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2113 if (ret < 0)
2114 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2115
2116 wl1271_ps_elp_sleep(wl);
2117
2118out:
2119 mutex_unlock(&wl->mutex);
2120
2121 return ret;
2122}
2123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002124static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2125{
2126 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002127 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128
2129 mutex_lock(&wl->mutex);
2130
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002131 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2132 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002133 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002134 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002135
Ido Yariva6208652011-03-01 15:14:41 +02002136 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137 if (ret < 0)
2138 goto out;
2139
2140 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2141 if (ret < 0)
2142 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2143
2144 wl1271_ps_elp_sleep(wl);
2145
2146out:
2147 mutex_unlock(&wl->mutex);
2148
2149 return ret;
2150}
2151
Arik Nemtsove78a2872010-10-16 19:07:21 +02002152static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002153 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002154{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002155 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002156
2157 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002158 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002159 if (ptr[0] == WLAN_EID_SSID) {
2160 wl->ssid_len = ptr[1];
2161 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002162 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002163 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002164 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002165 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002166
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002167 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002168 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002169}
2170
Arik Nemtsove78a2872010-10-16 19:07:21 +02002171static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2172 struct ieee80211_bss_conf *bss_conf,
2173 u32 changed)
2174{
2175 int ret = 0;
2176
2177 if (changed & BSS_CHANGED_ERP_SLOT) {
2178 if (bss_conf->use_short_slot)
2179 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2180 else
2181 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2182 if (ret < 0) {
2183 wl1271_warning("Set slot time failed %d", ret);
2184 goto out;
2185 }
2186 }
2187
2188 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2189 if (bss_conf->use_short_preamble)
2190 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2191 else
2192 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2193 }
2194
2195 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2196 if (bss_conf->use_cts_prot)
2197 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2198 else
2199 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2200 if (ret < 0) {
2201 wl1271_warning("Set ctsprotect failed %d", ret);
2202 goto out;
2203 }
2204 }
2205
2206out:
2207 return ret;
2208}
2209
2210static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2211 struct ieee80211_vif *vif,
2212 struct ieee80211_bss_conf *bss_conf,
2213 u32 changed)
2214{
2215 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2216 int ret = 0;
2217
2218 if ((changed & BSS_CHANGED_BEACON_INT)) {
2219 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2220 bss_conf->beacon_int);
2221
2222 wl->beacon_int = bss_conf->beacon_int;
2223 }
2224
2225 if ((changed & BSS_CHANGED_BEACON)) {
2226 struct ieee80211_hdr *hdr;
2227 int ieoffset = offsetof(struct ieee80211_mgmt,
2228 u.beacon.variable);
2229 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2230 u16 tmpl_id;
2231
2232 if (!beacon)
2233 goto out;
2234
2235 wl1271_debug(DEBUG_MASTER, "beacon updated");
2236
2237 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2238 if (ret < 0) {
2239 dev_kfree_skb(beacon);
2240 goto out;
2241 }
2242 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2243 CMD_TEMPL_BEACON;
2244 ret = wl1271_cmd_template_set(wl, tmpl_id,
2245 beacon->data,
2246 beacon->len, 0,
2247 wl1271_tx_min_rate_get(wl));
2248 if (ret < 0) {
2249 dev_kfree_skb(beacon);
2250 goto out;
2251 }
2252
2253 hdr = (struct ieee80211_hdr *) beacon->data;
2254 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2255 IEEE80211_STYPE_PROBE_RESP);
2256
2257 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2258 CMD_TEMPL_PROBE_RESPONSE;
2259 ret = wl1271_cmd_template_set(wl,
2260 tmpl_id,
2261 beacon->data,
2262 beacon->len, 0,
2263 wl1271_tx_min_rate_get(wl));
2264 dev_kfree_skb(beacon);
2265 if (ret < 0)
2266 goto out;
2267 }
2268
2269out:
2270 return ret;
2271}
2272
2273/* AP mode changes */
2274static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002275 struct ieee80211_vif *vif,
2276 struct ieee80211_bss_conf *bss_conf,
2277 u32 changed)
2278{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002279 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002280
Arik Nemtsove78a2872010-10-16 19:07:21 +02002281 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2282 u32 rates = bss_conf->basic_rates;
2283 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284
Arik Nemtsove78a2872010-10-16 19:07:21 +02002285 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2286 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2287 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2288 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289
Arik Nemtsove78a2872010-10-16 19:07:21 +02002290 /* update the AP management rate policy with the new rates */
2291 mgmt_rc.enabled_rates = wl->basic_rate_set;
2292 mgmt_rc.long_retry_limit = 10;
2293 mgmt_rc.short_retry_limit = 10;
2294 mgmt_rc.aflags = 0;
2295 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2296 ACX_TX_AP_MODE_MGMT_RATE);
2297 if (ret < 0) {
2298 wl1271_error("AP mgmt policy change failed %d", ret);
2299 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002300 }
2301 }
2302
Arik Nemtsove78a2872010-10-16 19:07:21 +02002303 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2304 if (ret < 0)
2305 goto out;
2306
2307 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2308 if (bss_conf->enable_beacon) {
2309 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2310 ret = wl1271_cmd_start_bss(wl);
2311 if (ret < 0)
2312 goto out;
2313
2314 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2315 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002316
2317 ret = wl1271_ap_init_hwenc(wl);
2318 if (ret < 0)
2319 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002320 }
2321 } else {
2322 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2323 ret = wl1271_cmd_stop_bss(wl);
2324 if (ret < 0)
2325 goto out;
2326
2327 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2328 wl1271_debug(DEBUG_AP, "stopped AP");
2329 }
2330 }
2331 }
2332
2333 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2334 if (ret < 0)
2335 goto out;
2336out:
2337 return;
2338}
2339
2340/* STA/IBSS mode changes */
2341static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2342 struct ieee80211_vif *vif,
2343 struct ieee80211_bss_conf *bss_conf,
2344 u32 changed)
2345{
2346 bool do_join = false, set_assoc = false;
2347 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002348 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002349 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002350 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002351 bool sta_exists = false;
2352 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002353
2354 if (is_ibss) {
2355 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2356 changed);
2357 if (ret < 0)
2358 goto out;
2359 }
2360
2361 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2362 do_join = true;
2363
2364 /* Need to update the SSID (for filtering etc) */
2365 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2366 do_join = true;
2367
2368 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002369 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2370 bss_conf->enable_beacon ? "enabled" : "disabled");
2371
2372 if (bss_conf->enable_beacon)
2373 wl->set_bss_type = BSS_TYPE_IBSS;
2374 else
2375 wl->set_bss_type = BSS_TYPE_STA_BSS;
2376 do_join = true;
2377 }
2378
Arik Nemtsove78a2872010-10-16 19:07:21 +02002379 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002380 bool enable = false;
2381 if (bss_conf->cqm_rssi_thold)
2382 enable = true;
2383 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2384 bss_conf->cqm_rssi_thold,
2385 bss_conf->cqm_rssi_hyst);
2386 if (ret < 0)
2387 goto out;
2388 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2389 }
2390
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002391 if ((changed & BSS_CHANGED_BSSID) &&
2392 /*
2393 * Now we know the correct bssid, so we send a new join command
2394 * and enable the BSSID filter
2395 */
2396 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002397 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002398
Eliad Pellerfa287b82010-12-26 09:27:50 +01002399 if (!is_zero_ether_addr(wl->bssid)) {
2400 ret = wl1271_cmd_build_null_data(wl);
2401 if (ret < 0)
2402 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002403
Eliad Pellerfa287b82010-12-26 09:27:50 +01002404 ret = wl1271_build_qos_null_data(wl);
2405 if (ret < 0)
2406 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002407
Eliad Pellerfa287b82010-12-26 09:27:50 +01002408 /* filter out all packets not from this BSSID */
2409 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002410
Eliad Pellerfa287b82010-12-26 09:27:50 +01002411 /* Need to update the BSSID (for filtering etc) */
2412 do_join = true;
2413 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002414 }
2415
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002416 rcu_read_lock();
2417 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2418 if (sta) {
2419 /* save the supp_rates of the ap */
2420 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2421 if (sta->ht_cap.ht_supported)
2422 sta_rate_set |=
2423 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002424 sta_ht_cap = sta->ht_cap;
2425 sta_exists = true;
2426 }
2427 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002428
Arik Nemtsova1008852011-02-12 23:24:20 +02002429 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002430 /* handle new association with HT and HT information change */
2431 if ((changed & BSS_CHANGED_HT) &&
2432 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002433 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002434 true);
2435 if (ret < 0) {
2436 wl1271_warning("Set ht cap true failed %d",
2437 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002438 goto out;
2439 }
2440 ret = wl1271_acx_set_ht_information(wl,
2441 bss_conf->ht_operation_mode);
2442 if (ret < 0) {
2443 wl1271_warning("Set ht information failed %d",
2444 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002445 goto out;
2446 }
2447 }
2448 /* handle new association without HT and disassociation */
2449 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002450 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002451 false);
2452 if (ret < 0) {
2453 wl1271_warning("Set ht cap false failed %d",
2454 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002455 goto out;
2456 }
2457 }
2458 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002459
Arik Nemtsove78a2872010-10-16 19:07:21 +02002460 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002462 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002463 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002465 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002467 wl->ps_poll_failures = 0;
2468
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002469 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002470 * use basic rates from AP, and determine lowest rate
2471 * to use with control frames.
2472 */
2473 rates = bss_conf->basic_rates;
2474 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2475 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002476 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002477 if (sta_rate_set)
2478 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2479 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002480 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002481 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002482 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002483
2484 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002485 * with wl1271, we don't need to update the
2486 * beacon_int and dtim_period, because the firmware
2487 * updates it by itself when the first beacon is
2488 * received after a join.
2489 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002490 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2491 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002492 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002493
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002494 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002495 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002496 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002497 dev_kfree_skb(wl->probereq);
2498 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2499 ieoffset = offsetof(struct ieee80211_mgmt,
2500 u.probe_req.variable);
2501 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002502
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002503 /* enable the connection monitoring feature */
2504 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002505 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002506 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507
2508 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002509 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2510 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002511 enum wl1271_cmd_ps_mode mode;
2512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002514 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002515 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002516 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002518 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002519 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002520 } else {
2521 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002522 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002523 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002524 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002525
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002526 /* free probe-request template */
2527 dev_kfree_skb(wl->probereq);
2528 wl->probereq = NULL;
2529
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002530 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002531 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002532
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002533 /* revert back to minimum rates for the current band */
2534 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002535 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002536 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002537 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002538 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002539
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002540 /* disable connection monitor features */
2541 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002542
2543 /* Disable the keep-alive feature */
2544 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002545 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002546 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002547
2548 /* restore the bssid filter and go to dummy bssid */
2549 wl1271_unjoin(wl);
2550 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551 }
2552 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002553
Arik Nemtsove78a2872010-10-16 19:07:21 +02002554 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2555 if (ret < 0)
2556 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002558 if (changed & BSS_CHANGED_ARP_FILTER) {
2559 __be32 addr = bss_conf->arp_addr_list[0];
2560 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2561
Eliad Pellerc5312772010-12-09 11:31:27 +02002562 if (bss_conf->arp_addr_cnt == 1 &&
2563 bss_conf->arp_filter_enabled) {
2564 /*
2565 * The template should have been configured only upon
2566 * association. however, it seems that the correct ip
2567 * isn't being set (when sending), so we have to
2568 * reconfigure the template upon every ip change.
2569 */
2570 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2571 if (ret < 0) {
2572 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002573 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002574 }
2575
2576 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002577 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002578 addr);
2579 } else
2580 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002581
2582 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002583 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002584 }
2585
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002586 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002587 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002588 if (ret < 0) {
2589 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002590 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002591 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002592 }
2593
Arik Nemtsove78a2872010-10-16 19:07:21 +02002594out:
2595 return;
2596}
2597
2598static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2599 struct ieee80211_vif *vif,
2600 struct ieee80211_bss_conf *bss_conf,
2601 u32 changed)
2602{
2603 struct wl1271 *wl = hw->priv;
2604 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2605 int ret;
2606
2607 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2608 (int)changed);
2609
2610 mutex_lock(&wl->mutex);
2611
2612 if (unlikely(wl->state == WL1271_STATE_OFF))
2613 goto out;
2614
Ido Yariva6208652011-03-01 15:14:41 +02002615 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002616 if (ret < 0)
2617 goto out;
2618
2619 if (is_ap)
2620 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2621 else
2622 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2623
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002624 wl1271_ps_elp_sleep(wl);
2625
2626out:
2627 mutex_unlock(&wl->mutex);
2628}
2629
Kalle Valoc6999d82010-02-18 13:25:41 +02002630static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2631 const struct ieee80211_tx_queue_params *params)
2632{
2633 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002634 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002635 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002636
2637 mutex_lock(&wl->mutex);
2638
2639 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2640
Kalle Valo4695dc92010-03-18 12:26:38 +02002641 if (params->uapsd)
2642 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2643 else
2644 ps_scheme = CONF_PS_SCHEME_LEGACY;
2645
Arik Nemtsov488fc542010-10-16 20:33:45 +02002646 if (wl->state == WL1271_STATE_OFF) {
2647 /*
2648 * If the state is off, the parameters will be recorded and
2649 * configured on init. This happens in AP-mode.
2650 */
2651 struct conf_tx_ac_category *conf_ac =
2652 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2653 struct conf_tx_tid *conf_tid =
2654 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2655
2656 conf_ac->ac = wl1271_tx_get_queue(queue);
2657 conf_ac->cw_min = (u8)params->cw_min;
2658 conf_ac->cw_max = params->cw_max;
2659 conf_ac->aifsn = params->aifs;
2660 conf_ac->tx_op_limit = params->txop << 5;
2661
2662 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2663 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2664 conf_tid->tsid = wl1271_tx_get_queue(queue);
2665 conf_tid->ps_scheme = ps_scheme;
2666 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2667 conf_tid->apsd_conf[0] = 0;
2668 conf_tid->apsd_conf[1] = 0;
2669 } else {
Ido Yariva6208652011-03-01 15:14:41 +02002670 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov488fc542010-10-16 20:33:45 +02002671 if (ret < 0)
2672 goto out;
2673
2674 /*
2675 * the txop is confed in units of 32us by the mac80211,
2676 * we need us
2677 */
2678 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2679 params->cw_min, params->cw_max,
2680 params->aifs, params->txop << 5);
2681 if (ret < 0)
2682 goto out_sleep;
2683
2684 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2685 CONF_CHANNEL_TYPE_EDCF,
2686 wl1271_tx_get_queue(queue),
2687 ps_scheme, CONF_ACK_POLICY_LEGACY,
2688 0, 0);
2689 if (ret < 0)
2690 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002691
2692out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002693 wl1271_ps_elp_sleep(wl);
2694 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002695
2696out:
2697 mutex_unlock(&wl->mutex);
2698
2699 return ret;
2700}
2701
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002702static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2703{
2704
2705 struct wl1271 *wl = hw->priv;
2706 u64 mactime = ULLONG_MAX;
2707 int ret;
2708
2709 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2710
2711 mutex_lock(&wl->mutex);
2712
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002713 if (unlikely(wl->state == WL1271_STATE_OFF))
2714 goto out;
2715
Ido Yariva6208652011-03-01 15:14:41 +02002716 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002717 if (ret < 0)
2718 goto out;
2719
2720 ret = wl1271_acx_tsf_info(wl, &mactime);
2721 if (ret < 0)
2722 goto out_sleep;
2723
2724out_sleep:
2725 wl1271_ps_elp_sleep(wl);
2726
2727out:
2728 mutex_unlock(&wl->mutex);
2729 return mactime;
2730}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731
John W. Linvilleece550d2010-07-28 16:41:06 -04002732static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2733 struct survey_info *survey)
2734{
2735 struct wl1271 *wl = hw->priv;
2736 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002737
John W. Linvilleece550d2010-07-28 16:41:06 -04002738 if (idx != 0)
2739 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002740
John W. Linvilleece550d2010-07-28 16:41:06 -04002741 survey->channel = conf->channel;
2742 survey->filled = SURVEY_INFO_NOISE_DBM;
2743 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002744
John W. Linvilleece550d2010-07-28 16:41:06 -04002745 return 0;
2746}
2747
Arik Nemtsov409622e2011-02-23 00:22:29 +02002748static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002749 struct ieee80211_sta *sta,
2750 u8 *hlid)
2751{
2752 struct wl1271_station *wl_sta;
2753 int id;
2754
2755 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2756 if (id >= AP_MAX_STATIONS) {
2757 wl1271_warning("could not allocate HLID - too much stations");
2758 return -EBUSY;
2759 }
2760
2761 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002762 __set_bit(id, wl->ap_hlid_map);
2763 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2764 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02002765 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002766 return 0;
2767}
2768
Arik Nemtsov409622e2011-02-23 00:22:29 +02002769static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002770{
2771 int id = hlid - WL1271_AP_STA_HLID_START;
2772
Arik Nemtsov409622e2011-02-23 00:22:29 +02002773 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2774 return;
2775
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002776 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002777 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02002778 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02002779 __clear_bit(hlid, &wl->ap_ps_map);
2780 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002781}
2782
2783static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2784 struct ieee80211_vif *vif,
2785 struct ieee80211_sta *sta)
2786{
2787 struct wl1271 *wl = hw->priv;
2788 int ret = 0;
2789 u8 hlid;
2790
2791 mutex_lock(&wl->mutex);
2792
2793 if (unlikely(wl->state == WL1271_STATE_OFF))
2794 goto out;
2795
2796 if (wl->bss_type != BSS_TYPE_AP_BSS)
2797 goto out;
2798
2799 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2800
Arik Nemtsov409622e2011-02-23 00:22:29 +02002801 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002802 if (ret < 0)
2803 goto out;
2804
Ido Yariva6208652011-03-01 15:14:41 +02002805 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002806 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02002807 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002808
2809 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2810 if (ret < 0)
2811 goto out_sleep;
2812
2813out_sleep:
2814 wl1271_ps_elp_sleep(wl);
2815
Arik Nemtsov409622e2011-02-23 00:22:29 +02002816out_free_sta:
2817 if (ret < 0)
2818 wl1271_free_sta(wl, hlid);
2819
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002820out:
2821 mutex_unlock(&wl->mutex);
2822 return ret;
2823}
2824
2825static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2826 struct ieee80211_vif *vif,
2827 struct ieee80211_sta *sta)
2828{
2829 struct wl1271 *wl = hw->priv;
2830 struct wl1271_station *wl_sta;
2831 int ret = 0, id;
2832
2833 mutex_lock(&wl->mutex);
2834
2835 if (unlikely(wl->state == WL1271_STATE_OFF))
2836 goto out;
2837
2838 if (wl->bss_type != BSS_TYPE_AP_BSS)
2839 goto out;
2840
2841 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2842
2843 wl_sta = (struct wl1271_station *)sta->drv_priv;
2844 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2845 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2846 goto out;
2847
Ido Yariva6208652011-03-01 15:14:41 +02002848 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002849 if (ret < 0)
2850 goto out;
2851
2852 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2853 if (ret < 0)
2854 goto out_sleep;
2855
Arik Nemtsov409622e2011-02-23 00:22:29 +02002856 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002857
2858out_sleep:
2859 wl1271_ps_elp_sleep(wl);
2860
2861out:
2862 mutex_unlock(&wl->mutex);
2863 return ret;
2864}
2865
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002866int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002867 enum ieee80211_ampdu_mlme_action action,
2868 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2869 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002870{
2871 struct wl1271 *wl = hw->priv;
2872 int ret;
2873
2874 mutex_lock(&wl->mutex);
2875
2876 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2877 ret = -EAGAIN;
2878 goto out;
2879 }
2880
Ido Yariva6208652011-03-01 15:14:41 +02002881 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002882 if (ret < 0)
2883 goto out;
2884
2885 switch (action) {
2886 case IEEE80211_AMPDU_RX_START:
2887 if (wl->ba_support) {
2888 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2889 true);
2890 if (!ret)
2891 wl->ba_rx_bitmap |= BIT(tid);
2892 } else {
2893 ret = -ENOTSUPP;
2894 }
2895 break;
2896
2897 case IEEE80211_AMPDU_RX_STOP:
2898 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2899 if (!ret)
2900 wl->ba_rx_bitmap &= ~BIT(tid);
2901 break;
2902
2903 /*
2904 * The BA initiator session management in FW independently.
2905 * Falling break here on purpose for all TX APDU commands.
2906 */
2907 case IEEE80211_AMPDU_TX_START:
2908 case IEEE80211_AMPDU_TX_STOP:
2909 case IEEE80211_AMPDU_TX_OPERATIONAL:
2910 ret = -EINVAL;
2911 break;
2912
2913 default:
2914 wl1271_error("Incorrect ampdu action id=%x\n", action);
2915 ret = -EINVAL;
2916 }
2917
2918 wl1271_ps_elp_sleep(wl);
2919
2920out:
2921 mutex_unlock(&wl->mutex);
2922
2923 return ret;
2924}
2925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926/* can't be const, mac80211 writes to this */
2927static struct ieee80211_rate wl1271_rates[] = {
2928 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002929 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2930 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002932 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2933 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2935 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002936 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2937 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002938 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2939 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002940 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2941 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2943 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002944 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2945 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002946 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002947 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2948 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002950 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2951 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002953 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2954 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002956 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2957 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002959 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2960 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002962 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2963 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002965 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2966 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967};
2968
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002969/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002971 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002972 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002973 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2974 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2975 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002976 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002977 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2978 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2979 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002980 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002981 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2982 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2983 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002984 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985};
2986
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002987/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002988static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002989 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002990 7, /* CONF_HW_RXTX_RATE_MCS7 */
2991 6, /* CONF_HW_RXTX_RATE_MCS6 */
2992 5, /* CONF_HW_RXTX_RATE_MCS5 */
2993 4, /* CONF_HW_RXTX_RATE_MCS4 */
2994 3, /* CONF_HW_RXTX_RATE_MCS3 */
2995 2, /* CONF_HW_RXTX_RATE_MCS2 */
2996 1, /* CONF_HW_RXTX_RATE_MCS1 */
2997 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002998
2999 11, /* CONF_HW_RXTX_RATE_54 */
3000 10, /* CONF_HW_RXTX_RATE_48 */
3001 9, /* CONF_HW_RXTX_RATE_36 */
3002 8, /* CONF_HW_RXTX_RATE_24 */
3003
3004 /* TI-specific rate */
3005 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3006
3007 7, /* CONF_HW_RXTX_RATE_18 */
3008 6, /* CONF_HW_RXTX_RATE_12 */
3009 3, /* CONF_HW_RXTX_RATE_11 */
3010 5, /* CONF_HW_RXTX_RATE_9 */
3011 4, /* CONF_HW_RXTX_RATE_6 */
3012 2, /* CONF_HW_RXTX_RATE_5_5 */
3013 1, /* CONF_HW_RXTX_RATE_2 */
3014 0 /* CONF_HW_RXTX_RATE_1 */
3015};
3016
Shahar Levie8b03a22010-10-13 16:09:39 +02003017/* 11n STA capabilities */
3018#define HW_RX_HIGHEST_RATE 72
3019
Shahar Levi00d20102010-11-08 11:20:10 +00003020#ifdef CONFIG_WL12XX_HT
3021#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02003022 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
3023 .ht_supported = true, \
3024 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3025 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3026 .mcs = { \
3027 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3028 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3029 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3030 }, \
3031}
Shahar Levi18357852010-10-13 16:09:41 +02003032#else
Shahar Levi00d20102010-11-08 11:20:10 +00003033#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003034 .ht_supported = false, \
3035}
3036#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003037
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038/* can't be const, mac80211 writes to this */
3039static struct ieee80211_supported_band wl1271_band_2ghz = {
3040 .channels = wl1271_channels,
3041 .n_channels = ARRAY_SIZE(wl1271_channels),
3042 .bitrates = wl1271_rates,
3043 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003044 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003045};
3046
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003047/* 5 GHz data rates for WL1273 */
3048static struct ieee80211_rate wl1271_rates_5ghz[] = {
3049 { .bitrate = 60,
3050 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3051 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3052 { .bitrate = 90,
3053 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3054 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3055 { .bitrate = 120,
3056 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3057 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3058 { .bitrate = 180,
3059 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3060 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3061 { .bitrate = 240,
3062 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3063 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3064 { .bitrate = 360,
3065 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3066 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3067 { .bitrate = 480,
3068 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3069 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3070 { .bitrate = 540,
3071 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3072 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3073};
3074
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003075/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003076static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003077 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003078 { .hw_value = 8, .center_freq = 5040},
3079 { .hw_value = 9, .center_freq = 5045},
3080 { .hw_value = 11, .center_freq = 5055},
3081 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003082 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003083 { .hw_value = 34, .center_freq = 5170},
3084 { .hw_value = 36, .center_freq = 5180},
3085 { .hw_value = 38, .center_freq = 5190},
3086 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003087 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003088 { .hw_value = 44, .center_freq = 5220},
3089 { .hw_value = 46, .center_freq = 5230},
3090 { .hw_value = 48, .center_freq = 5240},
3091 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003092 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003093 { .hw_value = 60, .center_freq = 5300},
3094 { .hw_value = 64, .center_freq = 5320},
3095 { .hw_value = 100, .center_freq = 5500},
3096 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003097 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003098 { .hw_value = 112, .center_freq = 5560},
3099 { .hw_value = 116, .center_freq = 5580},
3100 { .hw_value = 120, .center_freq = 5600},
3101 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003102 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003103 { .hw_value = 132, .center_freq = 5660},
3104 { .hw_value = 136, .center_freq = 5680},
3105 { .hw_value = 140, .center_freq = 5700},
3106 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003107 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003108 { .hw_value = 157, .center_freq = 5785},
3109 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003110 { .hw_value = 165, .center_freq = 5825},
3111};
3112
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003113/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003114static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003115 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003116 7, /* CONF_HW_RXTX_RATE_MCS7 */
3117 6, /* CONF_HW_RXTX_RATE_MCS6 */
3118 5, /* CONF_HW_RXTX_RATE_MCS5 */
3119 4, /* CONF_HW_RXTX_RATE_MCS4 */
3120 3, /* CONF_HW_RXTX_RATE_MCS3 */
3121 2, /* CONF_HW_RXTX_RATE_MCS2 */
3122 1, /* CONF_HW_RXTX_RATE_MCS1 */
3123 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003124
3125 7, /* CONF_HW_RXTX_RATE_54 */
3126 6, /* CONF_HW_RXTX_RATE_48 */
3127 5, /* CONF_HW_RXTX_RATE_36 */
3128 4, /* CONF_HW_RXTX_RATE_24 */
3129
3130 /* TI-specific rate */
3131 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3132
3133 3, /* CONF_HW_RXTX_RATE_18 */
3134 2, /* CONF_HW_RXTX_RATE_12 */
3135 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3136 1, /* CONF_HW_RXTX_RATE_9 */
3137 0, /* CONF_HW_RXTX_RATE_6 */
3138 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3139 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3140 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3141};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003142
3143static struct ieee80211_supported_band wl1271_band_5ghz = {
3144 .channels = wl1271_channels_5ghz,
3145 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3146 .bitrates = wl1271_rates_5ghz,
3147 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003148 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003149};
3150
Tobias Klausera0ea9492010-05-20 10:38:11 +02003151static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003152 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3153 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3154};
3155
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156static const struct ieee80211_ops wl1271_ops = {
3157 .start = wl1271_op_start,
3158 .stop = wl1271_op_stop,
3159 .add_interface = wl1271_op_add_interface,
3160 .remove_interface = wl1271_op_remove_interface,
3161 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003162 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 .configure_filter = wl1271_op_configure_filter,
3164 .tx = wl1271_op_tx,
3165 .set_key = wl1271_op_set_key,
3166 .hw_scan = wl1271_op_hw_scan,
3167 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003168 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003169 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003170 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003171 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003172 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003173 .sta_add = wl1271_op_sta_add,
3174 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003175 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003176 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177};
3178
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003179
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003180u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003181{
3182 u8 idx;
3183
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003184 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003185
3186 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3187 wl1271_error("Illegal RX rate from HW: %d", rate);
3188 return 0;
3189 }
3190
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003191 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003192 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3193 wl1271_error("Unsupported RX rate from HW: %d", rate);
3194 return 0;
3195 }
3196
3197 return idx;
3198}
3199
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003200static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3201 struct device_attribute *attr,
3202 char *buf)
3203{
3204 struct wl1271 *wl = dev_get_drvdata(dev);
3205 ssize_t len;
3206
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003207 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003208
3209 mutex_lock(&wl->mutex);
3210 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3211 wl->sg_enabled);
3212 mutex_unlock(&wl->mutex);
3213
3214 return len;
3215
3216}
3217
3218static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3219 struct device_attribute *attr,
3220 const char *buf, size_t count)
3221{
3222 struct wl1271 *wl = dev_get_drvdata(dev);
3223 unsigned long res;
3224 int ret;
3225
3226 ret = strict_strtoul(buf, 10, &res);
3227
3228 if (ret < 0) {
3229 wl1271_warning("incorrect value written to bt_coex_mode");
3230 return count;
3231 }
3232
3233 mutex_lock(&wl->mutex);
3234
3235 res = !!res;
3236
3237 if (res == wl->sg_enabled)
3238 goto out;
3239
3240 wl->sg_enabled = res;
3241
3242 if (wl->state == WL1271_STATE_OFF)
3243 goto out;
3244
Ido Yariva6208652011-03-01 15:14:41 +02003245 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003246 if (ret < 0)
3247 goto out;
3248
3249 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3250 wl1271_ps_elp_sleep(wl);
3251
3252 out:
3253 mutex_unlock(&wl->mutex);
3254 return count;
3255}
3256
3257static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3258 wl1271_sysfs_show_bt_coex_state,
3259 wl1271_sysfs_store_bt_coex_state);
3260
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003261static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3262 struct device_attribute *attr,
3263 char *buf)
3264{
3265 struct wl1271 *wl = dev_get_drvdata(dev);
3266 ssize_t len;
3267
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003268 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003269
3270 mutex_lock(&wl->mutex);
3271 if (wl->hw_pg_ver >= 0)
3272 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3273 else
3274 len = snprintf(buf, len, "n/a\n");
3275 mutex_unlock(&wl->mutex);
3276
3277 return len;
3278}
3279
3280static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3281 wl1271_sysfs_show_hw_pg_ver, NULL);
3282
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003283int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003284{
3285 int ret;
3286
3287 if (wl->mac80211_registered)
3288 return 0;
3289
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003290 ret = wl1271_fetch_nvs(wl);
3291 if (ret == 0) {
3292 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3293
3294 wl->mac_addr[0] = nvs_ptr[11];
3295 wl->mac_addr[1] = nvs_ptr[10];
3296 wl->mac_addr[2] = nvs_ptr[6];
3297 wl->mac_addr[3] = nvs_ptr[5];
3298 wl->mac_addr[4] = nvs_ptr[4];
3299 wl->mac_addr[5] = nvs_ptr[3];
3300 }
3301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3303
3304 ret = ieee80211_register_hw(wl->hw);
3305 if (ret < 0) {
3306 wl1271_error("unable to register mac80211 hw: %d", ret);
3307 return ret;
3308 }
3309
3310 wl->mac80211_registered = true;
3311
Eliad Pellerd60080a2010-11-24 12:53:16 +02003312 wl1271_debugfs_init(wl);
3313
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003314 register_netdevice_notifier(&wl1271_dev_notifier);
3315
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316 wl1271_notice("loaded");
3317
3318 return 0;
3319}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003320EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003321
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003322void wl1271_unregister_hw(struct wl1271 *wl)
3323{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003324 if (wl->state == WL1271_STATE_PLT)
3325 __wl1271_plt_stop(wl);
3326
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003327 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003328 ieee80211_unregister_hw(wl->hw);
3329 wl->mac80211_registered = false;
3330
3331}
3332EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3333
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003334int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003335{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003336 static const u32 cipher_suites[] = {
3337 WLAN_CIPHER_SUITE_WEP40,
3338 WLAN_CIPHER_SUITE_WEP104,
3339 WLAN_CIPHER_SUITE_TKIP,
3340 WLAN_CIPHER_SUITE_CCMP,
3341 WL1271_CIPHER_SUITE_GEM,
3342 };
3343
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003344 /* The tx descriptor buffer and the TKIP space. */
3345 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3346 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003347
3348 /* unit us */
3349 /* FIXME: find a proper value */
3350 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003351 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003352
3353 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003354 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003355 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003356 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003357 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003358 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003359 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003360 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
3361 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003362
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003363 wl->hw->wiphy->cipher_suites = cipher_suites;
3364 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3365
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003366 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003367 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003368 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003369 /*
3370 * Maximum length of elements in scanning probe request templates
3371 * should be the maximum length possible for a template, without
3372 * the IEEE80211 header of the template
3373 */
3374 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3375 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003376
3377 /*
3378 * We keep local copies of the band structs because we need to
3379 * modify them on a per-device basis.
3380 */
3381 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3382 sizeof(wl1271_band_2ghz));
3383 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3384 sizeof(wl1271_band_5ghz));
3385
3386 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3387 &wl->bands[IEEE80211_BAND_2GHZ];
3388 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3389 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003390
Kalle Valo12bd8942010-03-18 12:26:33 +02003391 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003392 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003393
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003394 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3395
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003396 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003397
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003398 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3399
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003400 wl->hw->max_rx_aggregation_subframes = 8;
3401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003402 return 0;
3403}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003404EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003406#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003407
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003408struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003409{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003410 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003411 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003412 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003413 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003414 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003415
3416 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3417 if (!hw) {
3418 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003419 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003420 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003421 }
3422
Julia Lawall929ebd32010-05-15 23:16:39 +02003423 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003424 if (!plat_dev) {
3425 wl1271_error("could not allocate platform_device");
3426 ret = -ENOMEM;
3427 goto err_plat_alloc;
3428 }
3429
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003430 wl = hw->priv;
3431 memset(wl, 0, sizeof(*wl));
3432
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003433 INIT_LIST_HEAD(&wl->list);
3434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003435 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003436 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003437
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003438 for (i = 0; i < NUM_TX_QUEUES; i++)
3439 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003441 for (i = 0; i < NUM_TX_QUEUES; i++)
3442 for (j = 0; j < AP_MAX_LINKS; j++)
3443 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3444
Ido Yariva6208652011-03-01 15:14:41 +02003445 skb_queue_head_init(&wl->deferred_rx_queue);
3446 skb_queue_head_init(&wl->deferred_tx_queue);
3447
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003448 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003449 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003450 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003451 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3452 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3453 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003454 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003455 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003456 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003457 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003458 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3459 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003460 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003462 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003463 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003464 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003465 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003466 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003467 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003468 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003469 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003470 wl->bss_type = MAX_BSS_TYPE;
3471 wl->set_bss_type = MAX_BSS_TYPE;
3472 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003473 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003474 wl->ap_ps_map = 0;
3475 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003476 wl->quirks = 0;
Shahar Levi48a61472011-03-06 16:32:08 +02003477 wl->block_size = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003478
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003479 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003480 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003481 wl->tx_frames[i] = NULL;
3482
3483 spin_lock_init(&wl->wl_lock);
3484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003485 wl->state = WL1271_STATE_OFF;
3486 mutex_init(&wl->mutex);
3487
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003488 /* Apply default driver configuration. */
3489 wl1271_conf_init(wl);
3490
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003491 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3492 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3493 if (!wl->aggr_buf) {
3494 ret = -ENOMEM;
3495 goto err_hw;
3496 }
3497
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003498 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003499 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003500 if (ret) {
3501 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003502 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003503 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003504 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003505
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003506 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003507 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003508 if (ret < 0) {
3509 wl1271_error("failed to create sysfs file bt_coex_state");
3510 goto err_platform;
3511 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003512
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003513 /* Create sysfs file to get HW PG version */
3514 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3515 if (ret < 0) {
3516 wl1271_error("failed to create sysfs file hw_pg_ver");
3517 goto err_bt_coex_state;
3518 }
3519
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003520 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003521
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003522err_bt_coex_state:
3523 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3524
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003525err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003526 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003527
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003528err_aggr:
3529 free_pages((unsigned long)wl->aggr_buf, order);
3530
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003531err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003532 wl1271_debugfs_exit(wl);
3533 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003534
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003535err_plat_alloc:
3536 ieee80211_free_hw(hw);
3537
3538err_hw_alloc:
3539
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003540 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003541}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003542EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003543
3544int wl1271_free_hw(struct wl1271 *wl)
3545{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003546 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003547 free_pages((unsigned long)wl->aggr_buf,
3548 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003549 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003550
3551 wl1271_debugfs_exit(wl);
3552
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003553 vfree(wl->fw);
3554 wl->fw = NULL;
3555 kfree(wl->nvs);
3556 wl->nvs = NULL;
3557
3558 kfree(wl->fw_status);
3559 kfree(wl->tx_res_if);
3560
3561 ieee80211_free_hw(wl->hw);
3562
3563 return 0;
3564}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003565EXPORT_SYMBOL_GPL(wl1271_free_hw);
3566
Guy Eilam491bbd62011-01-12 10:33:29 +01003567u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003568EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003569module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003570MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3571
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003572MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003573MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003574MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");