blob: dfab21e2e5dcd73c4550e33c32b0f5e46bd2c021 [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,
259 .psm_entry_nullfunc_retries = 3,
260 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300261 .keep_alive_interval = 55000,
262 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200264 .itrim = {
265 .enable = false,
266 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200267 },
268 .pm_config = {
269 .host_clk_settling_time = 5000,
270 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300271 },
272 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300273 .trigger_pacing = 1,
274 .avg_weight_rssi_beacon = 20,
275 .avg_weight_rssi_data = 10,
276 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100277 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200278 },
279 .scan = {
280 .min_dwell_time_active = 7500,
281 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100282 .min_dwell_time_passive = 100000,
283 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200284 .num_probe_reqs = 2,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100296 .ht = {
297 .tx_ba_win_size = 64,
298 .inactivity_timeout = 10000,
299 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300300};
301
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200302static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200303static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200304
305
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200306static void wl1271_device_release(struct device *dev)
307{
308
309}
310
311static struct platform_device wl1271_device = {
312 .name = "wl1271",
313 .id = -1,
314
315 /* device model insists to have a release function */
316 .dev = {
317 .release = wl1271_device_release,
318 },
319};
320
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300321static LIST_HEAD(wl_list);
322
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300323static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
324 void *arg)
325{
326 struct net_device *dev = arg;
327 struct wireless_dev *wdev;
328 struct wiphy *wiphy;
329 struct ieee80211_hw *hw;
330 struct wl1271 *wl;
331 struct wl1271 *wl_temp;
332 int ret = 0;
333
334 /* Check that this notification is for us. */
335 if (what != NETDEV_CHANGE)
336 return NOTIFY_DONE;
337
338 wdev = dev->ieee80211_ptr;
339 if (wdev == NULL)
340 return NOTIFY_DONE;
341
342 wiphy = wdev->wiphy;
343 if (wiphy == NULL)
344 return NOTIFY_DONE;
345
346 hw = wiphy_priv(wiphy);
347 if (hw == NULL)
348 return NOTIFY_DONE;
349
350 wl_temp = hw->priv;
351 list_for_each_entry(wl, &wl_list, list) {
352 if (wl == wl_temp)
353 break;
354 }
355 if (wl != wl_temp)
356 return NOTIFY_DONE;
357
358 mutex_lock(&wl->mutex);
359
360 if (wl->state == WL1271_STATE_OFF)
361 goto out;
362
363 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
364 goto out;
365
366 ret = wl1271_ps_elp_wakeup(wl, false);
367 if (ret < 0)
368 goto out;
369
370 if ((dev->operstate == IF_OPER_UP) &&
371 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
372 wl1271_cmd_set_sta_state(wl);
373 wl1271_info("Association completed.");
374 }
375
376 wl1271_ps_elp_sleep(wl);
377
378out:
379 mutex_unlock(&wl->mutex);
380
381 return NOTIFY_OK;
382}
383
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100384static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200385 struct regulatory_request *request)
386{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100387 struct ieee80211_supported_band *band;
388 struct ieee80211_channel *ch;
389 int i;
390
391 band = wiphy->bands[IEEE80211_BAND_5GHZ];
392 for (i = 0; i < band->n_channels; i++) {
393 ch = &band->channels[i];
394 if (ch->flags & IEEE80211_CHAN_DISABLED)
395 continue;
396
397 if (ch->flags & IEEE80211_CHAN_RADAR)
398 ch->flags |= IEEE80211_CHAN_NO_IBSS |
399 IEEE80211_CHAN_PASSIVE_SCAN;
400
401 }
402
403 return 0;
404}
405
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300406static void wl1271_conf_init(struct wl1271 *wl)
407{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300408
409 /*
410 * This function applies the default configuration to the driver. This
411 * function is invoked upon driver load (spi probe.)
412 *
413 * The configuration is stored in a run-time structure in order to
414 * facilitate for run-time adjustment of any of the parameters. Making
415 * changes to the configuration structure will apply the new values on
416 * the next interface up (wl1271_op_start.)
417 */
418
419 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300420 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300421}
422
423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424static int wl1271_plt_init(struct wl1271 *wl)
425{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200426 struct conf_tx_ac_category *conf_ac;
427 struct conf_tx_tid *conf_tid;
428 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300429
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200430 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200431 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200432 return ret;
433
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200434 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200435 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200436 return ret;
437
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200438 ret = wl1271_cmd_ext_radio_parms(wl);
439 if (ret < 0)
440 return ret;
441
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200442 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200443 if (ret < 0)
444 return ret;
445
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300446 ret = wl1271_acx_init_mem_config(wl);
447 if (ret < 0)
448 return ret;
449
Luciano Coelho12419cc2010-02-18 13:25:44 +0200450 /* PHY layer config */
451 ret = wl1271_init_phy_config(wl);
452 if (ret < 0)
453 goto out_free_memmap;
454
455 ret = wl1271_acx_dco_itrim_params(wl);
456 if (ret < 0)
457 goto out_free_memmap;
458
459 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200460 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200461 if (ret < 0)
462 goto out_free_memmap;
463
464 /* Bluetooth WLAN coexistence */
465 ret = wl1271_init_pta(wl);
466 if (ret < 0)
467 goto out_free_memmap;
468
469 /* Energy detection */
470 ret = wl1271_init_energy_detection(wl);
471 if (ret < 0)
472 goto out_free_memmap;
473
474 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100475 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200476 if (ret < 0)
477 goto out_free_memmap;
478
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200479 /* Default TID/AC configuration */
480 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200481 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200482 conf_ac = &wl->conf.tx.ac_conf[i];
483 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
484 conf_ac->cw_max, conf_ac->aifsn,
485 conf_ac->tx_op_limit);
486 if (ret < 0)
487 goto out_free_memmap;
488
Luciano Coelho12419cc2010-02-18 13:25:44 +0200489 conf_tid = &wl->conf.tx.tid_conf[i];
490 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
491 conf_tid->channel_type,
492 conf_tid->tsid,
493 conf_tid->ps_scheme,
494 conf_tid->ack_policy,
495 conf_tid->apsd_conf[0],
496 conf_tid->apsd_conf[1]);
497 if (ret < 0)
498 goto out_free_memmap;
499 }
500
Luciano Coelho12419cc2010-02-18 13:25:44 +0200501 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200502 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300503 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200504 goto out_free_memmap;
505
506 /* Configure for CAM power saving (ie. always active) */
507 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
508 if (ret < 0)
509 goto out_free_memmap;
510
511 /* configure PM */
512 ret = wl1271_acx_pm_config(wl);
513 if (ret < 0)
514 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515
516 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200517
518 out_free_memmap:
519 kfree(wl->target_mem_map);
520 wl->target_mem_map = NULL;
521
522 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523}
524
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300525static void wl1271_fw_status(struct wl1271 *wl,
526 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300527{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200528 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529 u32 total = 0;
530 int i;
531
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200532 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300533
534 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
535 "drv_rx_counter = %d, tx_results_counter = %d)",
536 status->intr,
537 status->fw_rx_counter,
538 status->drv_rx_counter,
539 status->tx_results_counter);
540
541 /* update number of available TX blocks */
542 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300543 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
544 wl->tx_blocks_freed[i];
545
546 wl->tx_blocks_freed[i] =
547 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300548 wl->tx_blocks_available += cnt;
549 total += cnt;
550 }
551
Ido Yariva5225502010-10-12 14:49:10 +0200552 /* if more blocks are available now, tx work can be scheduled */
553 if (total)
554 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555
556 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200557 getnstimeofday(&ts);
558 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
559 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560}
561
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200562#define WL1271_IRQ_MAX_LOOPS 10
563
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300564static void wl1271_irq_work(struct work_struct *work)
565{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300566 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300567 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200568 int loopcount = WL1271_IRQ_MAX_LOOPS;
569 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570 struct wl1271 *wl =
571 container_of(work, struct wl1271, irq_work);
572
573 mutex_lock(&wl->mutex);
574
575 wl1271_debug(DEBUG_IRQ, "IRQ work");
576
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200577 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578 goto out;
579
580 ret = wl1271_ps_elp_wakeup(wl, true);
581 if (ret < 0)
582 goto out;
583
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200584 spin_lock_irqsave(&wl->wl_lock, flags);
585 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
586 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
587 spin_unlock_irqrestore(&wl->wl_lock, flags);
588 loopcount--;
589
590 wl1271_fw_status(wl, wl->fw_status);
591 intr = le32_to_cpu(wl->fw_status->intr);
592 if (!intr) {
593 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200594 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200595 continue;
596 }
597
598 intr &= WL1271_INTR_MASK;
599
Eliad Pellerccc83b02010-10-27 14:09:57 +0200600 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
601 wl1271_error("watchdog interrupt received! "
602 "starting recovery.");
603 ieee80211_queue_work(wl->hw, &wl->recovery_work);
604
605 /* restarting the chip. ignore any other interrupt. */
606 goto out;
607 }
608
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200609 if (intr & WL1271_ACX_INTR_DATA) {
610 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
611
612 /* check for tx results */
613 if (wl->fw_status->tx_results_counter !=
614 (wl->tx_results_count & 0xff))
615 wl1271_tx_complete(wl);
616
Ido Yariva5225502010-10-12 14:49:10 +0200617 /* Check if any tx blocks were freed */
618 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200619 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200620 /*
621 * In order to avoid starvation of the TX path,
622 * call the work function directly.
623 */
624 wl1271_tx_work_locked(wl);
625 }
626
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200627 wl1271_rx(wl, wl->fw_status);
628 }
629
630 if (intr & WL1271_ACX_INTR_EVENT_A) {
631 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
632 wl1271_event_handle(wl, 0);
633 }
634
635 if (intr & WL1271_ACX_INTR_EVENT_B) {
636 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
637 wl1271_event_handle(wl, 1);
638 }
639
640 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
641 wl1271_debug(DEBUG_IRQ,
642 "WL1271_ACX_INTR_INIT_COMPLETE");
643
644 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
645 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
646
647 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648 }
649
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200650 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
651 ieee80211_queue_work(wl->hw, &wl->irq_work);
652 else
653 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
654 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 wl1271_ps_elp_sleep(wl);
657
658out:
659 mutex_unlock(&wl->mutex);
660}
661
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662static int wl1271_fetch_firmware(struct wl1271 *wl)
663{
664 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200665 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300666 int ret;
667
Arik Nemtsov166d5042010-10-16 21:44:57 +0200668 switch (wl->bss_type) {
669 case BSS_TYPE_AP_BSS:
670 fw_name = WL1271_AP_FW_NAME;
671 break;
672 case BSS_TYPE_IBSS:
673 case BSS_TYPE_STA_BSS:
674 fw_name = WL1271_FW_NAME;
675 break;
676 default:
677 wl1271_error("no compatible firmware for bss_type %d",
678 wl->bss_type);
679 return -EINVAL;
680 }
681
682 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
683
684 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685
686 if (ret < 0) {
687 wl1271_error("could not get firmware: %d", ret);
688 return ret;
689 }
690
691 if (fw->size % 4) {
692 wl1271_error("firmware size is not multiple of 32 bits: %zu",
693 fw->size);
694 ret = -EILSEQ;
695 goto out;
696 }
697
Arik Nemtsov166d5042010-10-16 21:44:57 +0200698 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300700 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701
702 if (!wl->fw) {
703 wl1271_error("could not allocate memory for the firmware");
704 ret = -ENOMEM;
705 goto out;
706 }
707
708 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200709 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300710 ret = 0;
711
712out:
713 release_firmware(fw);
714
715 return ret;
716}
717
718static int wl1271_fetch_nvs(struct wl1271 *wl)
719{
720 const struct firmware *fw;
721 int ret;
722
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200723 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724
725 if (ret < 0) {
726 wl1271_error("could not get nvs file: %d", ret);
727 return ret;
728 }
729
Julia Lawall929ebd32010-05-15 23:16:39 +0200730 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731
732 if (!wl->nvs) {
733 wl1271_error("could not allocate memory for the nvs file");
734 ret = -ENOMEM;
735 goto out;
736 }
737
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200738 wl->nvs_len = fw->size;
739
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740out:
741 release_firmware(fw);
742
743 return ret;
744}
745
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200746static void wl1271_recovery_work(struct work_struct *work)
747{
748 struct wl1271 *wl =
749 container_of(work, struct wl1271, recovery_work);
750
751 mutex_lock(&wl->mutex);
752
753 if (wl->state != WL1271_STATE_ON)
754 goto out;
755
756 wl1271_info("Hardware recovery in progress.");
757
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200758 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
759 ieee80211_connection_loss(wl->vif);
760
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200761 /* reboot the chipset */
762 __wl1271_op_remove_interface(wl);
763 ieee80211_restart_hw(wl->hw);
764
765out:
766 mutex_unlock(&wl->mutex);
767}
768
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769static void wl1271_fw_wakeup(struct wl1271 *wl)
770{
771 u32 elp_reg;
772
773 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300774 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775}
776
777static int wl1271_setup(struct wl1271 *wl)
778{
779 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
780 if (!wl->fw_status)
781 return -ENOMEM;
782
783 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
784 if (!wl->tx_res_if) {
785 kfree(wl->fw_status);
786 return -ENOMEM;
787 }
788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789 return 0;
790}
791
792static int wl1271_chip_wakeup(struct wl1271 *wl)
793{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300794 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795 int ret = 0;
796
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200797 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200798 ret = wl1271_power_on(wl);
799 if (ret < 0)
800 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300801 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200802 wl1271_io_reset(wl);
803 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804
805 /* We don't need a real memory partition here, because we only want
806 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300807 memset(&partition, 0, sizeof(partition));
808 partition.reg.start = REGISTERS_BASE;
809 partition.reg.size = REGISTERS_DOWN_SIZE;
810 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300811
812 /* ELP module wake up */
813 wl1271_fw_wakeup(wl);
814
815 /* whal_FwCtrl_BootSm() */
816
817 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200818 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300819
820 /* 1. check if chip id is valid */
821
822 switch (wl->chip.id) {
823 case CHIP_ID_1271_PG10:
824 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
825 wl->chip.id);
826
827 ret = wl1271_setup(wl);
828 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200829 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830 break;
831 case CHIP_ID_1271_PG20:
832 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
833 wl->chip.id);
834
835 ret = wl1271_setup(wl);
836 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200837 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838 break;
839 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200840 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200842 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 }
844
Arik Nemtsov166d5042010-10-16 21:44:57 +0200845 /* Make sure the firmware type matches the BSS type */
846 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847 ret = wl1271_fetch_firmware(wl);
848 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200849 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300850 }
851
852 /* No NVS from netlink, try to get it from the filesystem */
853 if (wl->nvs == NULL) {
854 ret = wl1271_fetch_nvs(wl);
855 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200856 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300857 }
858
859out:
860 return ret;
861}
862
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863int wl1271_plt_start(struct wl1271 *wl)
864{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200865 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866 int ret;
867
868 mutex_lock(&wl->mutex);
869
870 wl1271_notice("power up");
871
872 if (wl->state != WL1271_STATE_OFF) {
873 wl1271_error("cannot go into PLT state because not "
874 "in off state: %d", wl->state);
875 ret = -EBUSY;
876 goto out;
877 }
878
Arik Nemtsov166d5042010-10-16 21:44:57 +0200879 wl->bss_type = BSS_TYPE_STA_BSS;
880
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200881 while (retries) {
882 retries--;
883 ret = wl1271_chip_wakeup(wl);
884 if (ret < 0)
885 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200887 ret = wl1271_boot(wl);
888 if (ret < 0)
889 goto power_off;
890
891 ret = wl1271_plt_init(wl);
892 if (ret < 0)
893 goto irq_disable;
894
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200895 wl->state = WL1271_STATE_PLT;
896 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100897 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 goto out;
899
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200900irq_disable:
901 wl1271_disable_interrupts(wl);
902 mutex_unlock(&wl->mutex);
903 /* Unlocking the mutex in the middle of handling is
904 inherently unsafe. In this case we deem it safe to do,
905 because we need to let any possibly pending IRQ out of
906 the system (and while we are WL1271_STATE_OFF the IRQ
907 work function will not do anything.) Also, any other
908 possible concurrent operations will fail due to the
909 current state, hence the wl1271 struct should be safe. */
910 cancel_work_sync(&wl->irq_work);
911 mutex_lock(&wl->mutex);
912power_off:
913 wl1271_power_off(wl);
914 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200916 wl1271_error("firmware boot in PLT mode failed despite %d retries",
917 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918out:
919 mutex_unlock(&wl->mutex);
920
921 return ret;
922}
923
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100924int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925{
926 int ret = 0;
927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 wl1271_notice("power down");
929
930 if (wl->state != WL1271_STATE_PLT) {
931 wl1271_error("cannot power down because not in PLT "
932 "state: %d", wl->state);
933 ret = -EBUSY;
934 goto out;
935 }
936
937 wl1271_disable_interrupts(wl);
938 wl1271_power_off(wl);
939
940 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300941 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200944 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200945 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100946 mutex_lock(&wl->mutex);
947out:
948 return ret;
949}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200950
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100951int wl1271_plt_stop(struct wl1271 *wl)
952{
953 int ret;
954
955 mutex_lock(&wl->mutex);
956 ret = __wl1271_plt_stop(wl);
957 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 return ret;
959}
960
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
962{
963 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200964 struct ieee80211_conf *conf = &hw->conf;
965 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
966 struct ieee80211_sta *sta = txinfo->control.sta;
967 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200968 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969
Shahar Levi18357852010-10-13 16:09:41 +0200970 /*
971 * peek into the rates configured in the STA entry.
972 * The rates set after connection stage, The first block only BG sets:
973 * the compare is for bit 0-16 of sta_rate_set. The second block add
974 * HT rates in case of HT supported.
975 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200976 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200977 if (sta &&
978 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200979 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
980 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200981 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
982 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
983 }
Shahar Levi18357852010-10-13 16:09:41 +0200984
Shahar Levi00d20102010-11-08 11:20:10 +0000985#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200986 if (sta &&
987 sta->ht_cap.ht_supported &&
988 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
989 sta->ht_cap.mcs.rx_mask[0])) {
990 /* Clean MCS bits before setting them */
991 wl->sta_rate_set &= HW_BG_RATES_MASK;
992 wl->sta_rate_set |=
993 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
994 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
995 }
996#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200997 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200998 spin_unlock_irqrestore(&wl->wl_lock, flags);
999
1000 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001001 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1002 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
1004 /*
1005 * The chip specific setup must run before the first TX packet -
1006 * before that, the tx_work will not be initialized!
1007 */
1008
Ido Yariva5225502010-10-12 14:49:10 +02001009 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1010 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
1012 /*
1013 * The workqueue is slow to process the tx_queue and we need stop
1014 * the queue here, otherwise the queue will get too long.
1015 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001016 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001017 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001019 spin_lock_irqsave(&wl->wl_lock, flags);
1020 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001021 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001022 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 }
1024
1025 return NETDEV_TX_OK;
1026}
1027
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001028static struct notifier_block wl1271_dev_notifier = {
1029 .notifier_call = wl1271_dev_notify,
1030};
1031
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032static int wl1271_op_start(struct ieee80211_hw *hw)
1033{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001034 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1035
1036 /*
1037 * We have to delay the booting of the hardware because
1038 * we need to know the local MAC address before downloading and
1039 * initializing the firmware. The MAC address cannot be changed
1040 * after boot, and without the proper MAC address, the firmware
1041 * will not function properly.
1042 *
1043 * The MAC address is first known when the corresponding interface
1044 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001045 *
1046 * In addition, we currently have different firmwares for AP and managed
1047 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001048 */
1049
1050 return 0;
1051}
1052
1053static void wl1271_op_stop(struct ieee80211_hw *hw)
1054{
1055 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1056}
1057
1058static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1059 struct ieee80211_vif *vif)
1060{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001062 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001063 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001065 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001067 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1068 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069
1070 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001071 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001072 wl1271_debug(DEBUG_MAC80211,
1073 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001074 ret = -EBUSY;
1075 goto out;
1076 }
1077
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001078 switch (vif->type) {
1079 case NL80211_IFTYPE_STATION:
1080 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001081 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001082 break;
1083 case NL80211_IFTYPE_ADHOC:
1084 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001085 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001086 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001087 case NL80211_IFTYPE_AP:
1088 wl->bss_type = BSS_TYPE_AP_BSS;
1089 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001090 default:
1091 ret = -EOPNOTSUPP;
1092 goto out;
1093 }
1094
1095 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096
1097 if (wl->state != WL1271_STATE_OFF) {
1098 wl1271_error("cannot start because not in off state: %d",
1099 wl->state);
1100 ret = -EBUSY;
1101 goto out;
1102 }
1103
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001104 while (retries) {
1105 retries--;
1106 ret = wl1271_chip_wakeup(wl);
1107 if (ret < 0)
1108 goto power_off;
1109
1110 ret = wl1271_boot(wl);
1111 if (ret < 0)
1112 goto power_off;
1113
1114 ret = wl1271_hw_init(wl);
1115 if (ret < 0)
1116 goto irq_disable;
1117
Eliad Peller71125ab2010-10-28 21:46:43 +02001118 booted = true;
1119 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001121irq_disable:
1122 wl1271_disable_interrupts(wl);
1123 mutex_unlock(&wl->mutex);
1124 /* Unlocking the mutex in the middle of handling is
1125 inherently unsafe. In this case we deem it safe to do,
1126 because we need to let any possibly pending IRQ out of
1127 the system (and while we are WL1271_STATE_OFF the IRQ
1128 work function will not do anything.) Also, any other
1129 possible concurrent operations will fail due to the
1130 current state, hence the wl1271 struct should be safe. */
1131 cancel_work_sync(&wl->irq_work);
1132 mutex_lock(&wl->mutex);
1133power_off:
1134 wl1271_power_off(wl);
1135 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001136
Eliad Peller71125ab2010-10-28 21:46:43 +02001137 if (!booted) {
1138 wl1271_error("firmware boot failed despite %d retries",
1139 WL1271_BOOT_RETRIES);
1140 goto out;
1141 }
1142
1143 wl->vif = vif;
1144 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001145 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001146
1147 /* update hw/fw version info in wiphy struct */
1148 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001149 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001150 sizeof(wiphy->fw_version));
1151
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001152 /*
1153 * Now we know if 11a is supported (info from the NVS), so disable
1154 * 11a channels if not supported
1155 */
1156 if (!wl->enable_11a)
1157 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1158
1159 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1160 wl->enable_11a ? "" : "not ");
1161
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001162out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163 mutex_unlock(&wl->mutex);
1164
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001165 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001166 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001167
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168 return ret;
1169}
1170
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001171static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173 int i;
1174
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001175 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001177 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001179 list_del(&wl->list);
1180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 WARN_ON(wl->state != WL1271_STATE_ON);
1182
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001183 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001184 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001185 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001186
Luciano Coelho08688d62010-07-08 17:50:07 +03001187 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001188 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1189 kfree(wl->scan.scanned_ch);
1190 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001191 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001192 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193 }
1194
1195 wl->state = WL1271_STATE_OFF;
1196
1197 wl1271_disable_interrupts(wl);
1198
1199 mutex_unlock(&wl->mutex);
1200
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001201 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202 cancel_work_sync(&wl->irq_work);
1203 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001204 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001205 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206
1207 mutex_lock(&wl->mutex);
1208
1209 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001210 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 wl1271_power_off(wl);
1212
1213 memset(wl->bssid, 0, ETH_ALEN);
1214 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1215 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001217 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001218 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219
1220 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001221 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1223 wl->tx_blocks_available = 0;
1224 wl->tx_results_count = 0;
1225 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001226 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001227 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228 wl->time_offset = 0;
1229 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001230 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1231 wl->sta_rate_set = 0;
1232 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001233 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001234 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001235 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001236 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001237
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 for (i = 0; i < NUM_TX_QUEUES; i++)
1239 wl->tx_blocks_freed[i] = 0;
1240
1241 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001242
1243 kfree(wl->fw_status);
1244 wl->fw_status = NULL;
1245 kfree(wl->tx_res_if);
1246 wl->tx_res_if = NULL;
1247 kfree(wl->target_mem_map);
1248 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001249}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001250
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001251static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1252 struct ieee80211_vif *vif)
1253{
1254 struct wl1271 *wl = hw->priv;
1255
1256 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001257 /*
1258 * wl->vif can be null here if someone shuts down the interface
1259 * just when hardware recovery has been started.
1260 */
1261 if (wl->vif) {
1262 WARN_ON(wl->vif != vif);
1263 __wl1271_op_remove_interface(wl);
1264 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001265
Juuso Oikarinen67353292010-11-18 15:19:02 +02001266 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001267 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268}
1269
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001270static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1271{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001272 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001273
1274 /* combine requested filters with current filter config */
1275 filters = wl->filters | filters;
1276
1277 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1278
1279 if (filters & FIF_PROMISC_IN_BSS) {
1280 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1281 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1282 wl->rx_config |= CFG_BSSID_FILTER_EN;
1283 }
1284 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1285 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1286 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1287 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1288 }
1289 if (filters & FIF_OTHER_BSS) {
1290 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1291 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1292 }
1293 if (filters & FIF_CONTROL) {
1294 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1295 wl->rx_filter |= CFG_RX_CTL_EN;
1296 }
1297 if (filters & FIF_FCSFAIL) {
1298 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1299 wl->rx_filter |= CFG_RX_FCS_ERROR;
1300 }
1301}
1302
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001303static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001304{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001305 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001306 /* we need to use a dummy BSSID for now */
1307 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1308 0xad, 0xbe, 0xef };
1309
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001310 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1311
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001312 /* pass through frames from all BSS */
1313 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1314
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001315 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001316 if (ret < 0)
1317 goto out;
1318
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001319 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001320
1321out:
1322 return ret;
1323}
1324
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001325static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001326{
1327 int ret;
1328
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001329 /*
1330 * One of the side effects of the JOIN command is that is clears
1331 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1332 * to a WPA/WPA2 access point will therefore kill the data-path.
1333 * Currently there is no supported scenario for JOIN during
1334 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1335 * must be handled somehow.
1336 *
1337 */
1338 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1339 wl1271_info("JOIN while associated.");
1340
1341 if (set_assoc)
1342 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1343
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001344 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1345 if (ret < 0)
1346 goto out;
1347
1348 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1349
1350 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1351 goto out;
1352
1353 /*
1354 * The join command disable the keep-alive mode, shut down its process,
1355 * and also clear the template config, so we need to reset it all after
1356 * the join. The acx_aid starts the keep-alive process, and the order
1357 * of the commands below is relevant.
1358 */
1359 ret = wl1271_acx_keep_alive_mode(wl, true);
1360 if (ret < 0)
1361 goto out;
1362
1363 ret = wl1271_acx_aid(wl, wl->aid);
1364 if (ret < 0)
1365 goto out;
1366
1367 ret = wl1271_cmd_build_klv_null_data(wl);
1368 if (ret < 0)
1369 goto out;
1370
1371 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1372 ACX_KEEP_ALIVE_TPL_VALID);
1373 if (ret < 0)
1374 goto out;
1375
1376out:
1377 return ret;
1378}
1379
1380static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001381{
1382 int ret;
1383
1384 /* to stop listening to a channel, we disconnect */
1385 ret = wl1271_cmd_disconnect(wl);
1386 if (ret < 0)
1387 goto out;
1388
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001389 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001390 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001391
1392 /* stop filterting packets based on bssid */
1393 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001394
1395out:
1396 return ret;
1397}
1398
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001399static void wl1271_set_band_rate(struct wl1271 *wl)
1400{
1401 if (wl->band == IEEE80211_BAND_2GHZ)
1402 wl->basic_rate_set = wl->conf.tx.basic_rate;
1403 else
1404 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1405}
1406
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001407static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001408{
1409 int ret;
1410
1411 if (idle) {
1412 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1413 ret = wl1271_unjoin(wl);
1414 if (ret < 0)
1415 goto out;
1416 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001417 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001418 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001419 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001420 if (ret < 0)
1421 goto out;
1422 ret = wl1271_acx_keep_alive_config(
1423 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1424 ACX_KEEP_ALIVE_TPL_INVALID);
1425 if (ret < 0)
1426 goto out;
1427 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1428 } else {
1429 /* increment the session counter */
1430 wl->session_counter++;
1431 if (wl->session_counter >= SESSION_COUNTER_MAX)
1432 wl->session_counter = 0;
1433 ret = wl1271_dummy_join(wl);
1434 if (ret < 0)
1435 goto out;
1436 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1437 }
1438
1439out:
1440 return ret;
1441}
1442
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1444{
1445 struct wl1271 *wl = hw->priv;
1446 struct ieee80211_conf *conf = &hw->conf;
1447 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001448 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449
1450 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1451
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001452 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1453 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 channel,
1455 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001456 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001457 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1458 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001460 /*
1461 * mac80211 will go to idle nearly immediately after transmitting some
1462 * frames, such as the deauth. To make sure those frames reach the air,
1463 * wait here until the TX queue is fully flushed.
1464 */
1465 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1466 (conf->flags & IEEE80211_CONF_IDLE))
1467 wl1271_tx_flush(wl);
1468
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469 mutex_lock(&wl->mutex);
1470
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001471 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1472 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001473 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001474 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001475
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001476 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1477
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 ret = wl1271_ps_elp_wakeup(wl, false);
1479 if (ret < 0)
1480 goto out;
1481
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001482 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001483 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1484 ((wl->band != conf->channel->band) ||
1485 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001486 wl->band = conf->channel->band;
1487 wl->channel = channel;
1488
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001489 if (!is_ap) {
1490 /*
1491 * FIXME: the mac80211 should really provide a fixed
1492 * rate to use here. for now, just use the smallest
1493 * possible rate for the band as a fixed rate for
1494 * association frames and other control messages.
1495 */
1496 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1497 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001498
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001499 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1500 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001501 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001502 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001503 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001504
1505 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1506 ret = wl1271_join(wl, false);
1507 if (ret < 0)
1508 wl1271_warning("cmd join on channel "
1509 "failed %d", ret);
1510 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001511 }
1512 }
1513
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001514 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1515 ret = wl1271_sta_handle_idle(wl,
1516 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001517 if (ret < 0)
1518 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519 }
1520
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001521 /*
1522 * if mac80211 changes the PSM mode, make sure the mode is not
1523 * incorrectly changed after the pspoll failure active window.
1524 */
1525 if (changed & IEEE80211_CONF_CHANGE_PS)
1526 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1527
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001528 if (conf->flags & IEEE80211_CONF_PS &&
1529 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1530 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531
1532 /*
1533 * We enter PSM only if we're already associated.
1534 * If we're not, we'll enter it when joining an SSID,
1535 * through the bss_info_changed() hook.
1536 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001537 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001538 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001539 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001540 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001541 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001543 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001544 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001546 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001548 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001549 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001550 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551 }
1552
1553 if (conf->power_level != wl->power_level) {
1554 ret = wl1271_acx_tx_power(wl, conf->power_level);
1555 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001556 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557
1558 wl->power_level = conf->power_level;
1559 }
1560
1561out_sleep:
1562 wl1271_ps_elp_sleep(wl);
1563
1564out:
1565 mutex_unlock(&wl->mutex);
1566
1567 return ret;
1568}
1569
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001570struct wl1271_filter_params {
1571 bool enabled;
1572 int mc_list_length;
1573 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1574};
1575
Jiri Pirko22bedad2010-04-01 21:22:57 +00001576static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1577 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001578{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001579 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001580 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001581 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001582
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001583 if (unlikely(wl->state == WL1271_STATE_OFF))
1584 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001585
Juuso Oikarinen74441132009-10-13 12:47:53 +03001586 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001587 if (!fp) {
1588 wl1271_error("Out of memory setting filters.");
1589 return 0;
1590 }
1591
1592 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001593 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001594 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1595 fp->enabled = false;
1596 } else {
1597 fp->enabled = true;
1598 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001599 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001600 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001601 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001602 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001603 }
1604
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001605 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001606}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001608#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1609 FIF_ALLMULTI | \
1610 FIF_FCSFAIL | \
1611 FIF_BCN_PRBRESP_PROMISC | \
1612 FIF_CONTROL | \
1613 FIF_OTHER_BSS)
1614
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1616 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001617 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001618{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001619 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001621 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001622
Arik Nemtsov7d057862010-10-16 19:25:35 +02001623 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1624 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001625
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001626 mutex_lock(&wl->mutex);
1627
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001628 *total &= WL1271_SUPPORTED_FILTERS;
1629 changed &= WL1271_SUPPORTED_FILTERS;
1630
1631 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001632 goto out;
1633
1634 ret = wl1271_ps_elp_wakeup(wl, false);
1635 if (ret < 0)
1636 goto out;
1637
Arik Nemtsov7d057862010-10-16 19:25:35 +02001638 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1639 if (*total & FIF_ALLMULTI)
1640 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1641 else if (fp)
1642 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1643 fp->mc_list,
1644 fp->mc_list_length);
1645 if (ret < 0)
1646 goto out_sleep;
1647 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001648
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001649 /* determine, whether supported filter values have changed */
1650 if (changed == 0)
1651 goto out_sleep;
1652
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001653 /* configure filters */
1654 wl->filters = *total;
1655 wl1271_configure_filters(wl, 0);
1656
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001657 /* apply configured filters */
1658 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1659 if (ret < 0)
1660 goto out_sleep;
1661
1662out_sleep:
1663 wl1271_ps_elp_sleep(wl);
1664
1665out:
1666 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001667 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668}
1669
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001670static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1671 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1672 u16 tx_seq_16)
1673{
1674 struct wl1271_ap_key *ap_key;
1675 int i;
1676
1677 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1678
1679 if (key_size > MAX_KEY_SIZE)
1680 return -EINVAL;
1681
1682 /*
1683 * Find next free entry in ap_keys. Also check we are not replacing
1684 * an existing key.
1685 */
1686 for (i = 0; i < MAX_NUM_KEYS; i++) {
1687 if (wl->recorded_ap_keys[i] == NULL)
1688 break;
1689
1690 if (wl->recorded_ap_keys[i]->id == id) {
1691 wl1271_warning("trying to record key replacement");
1692 return -EINVAL;
1693 }
1694 }
1695
1696 if (i == MAX_NUM_KEYS)
1697 return -EBUSY;
1698
1699 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1700 if (!ap_key)
1701 return -ENOMEM;
1702
1703 ap_key->id = id;
1704 ap_key->key_type = key_type;
1705 ap_key->key_size = key_size;
1706 memcpy(ap_key->key, key, key_size);
1707 ap_key->hlid = hlid;
1708 ap_key->tx_seq_32 = tx_seq_32;
1709 ap_key->tx_seq_16 = tx_seq_16;
1710
1711 wl->recorded_ap_keys[i] = ap_key;
1712 return 0;
1713}
1714
1715static void wl1271_free_ap_keys(struct wl1271 *wl)
1716{
1717 int i;
1718
1719 for (i = 0; i < MAX_NUM_KEYS; i++) {
1720 kfree(wl->recorded_ap_keys[i]);
1721 wl->recorded_ap_keys[i] = NULL;
1722 }
1723}
1724
1725static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1726{
1727 int i, ret = 0;
1728 struct wl1271_ap_key *key;
1729 bool wep_key_added = false;
1730
1731 for (i = 0; i < MAX_NUM_KEYS; i++) {
1732 if (wl->recorded_ap_keys[i] == NULL)
1733 break;
1734
1735 key = wl->recorded_ap_keys[i];
1736 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1737 key->id, key->key_type,
1738 key->key_size, key->key,
1739 key->hlid, key->tx_seq_32,
1740 key->tx_seq_16);
1741 if (ret < 0)
1742 goto out;
1743
1744 if (key->key_type == KEY_WEP)
1745 wep_key_added = true;
1746 }
1747
1748 if (wep_key_added) {
1749 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1750 if (ret < 0)
1751 goto out;
1752 }
1753
1754out:
1755 wl1271_free_ap_keys(wl);
1756 return ret;
1757}
1758
1759static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1760 u8 key_size, const u8 *key, u32 tx_seq_32,
1761 u16 tx_seq_16, struct ieee80211_sta *sta)
1762{
1763 int ret;
1764 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1765
1766 if (is_ap) {
1767 struct wl1271_station *wl_sta;
1768 u8 hlid;
1769
1770 if (sta) {
1771 wl_sta = (struct wl1271_station *)sta->drv_priv;
1772 hlid = wl_sta->hlid;
1773 } else {
1774 hlid = WL1271_AP_BROADCAST_HLID;
1775 }
1776
1777 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1778 /*
1779 * We do not support removing keys after AP shutdown.
1780 * Pretend we do to make mac80211 happy.
1781 */
1782 if (action != KEY_ADD_OR_REPLACE)
1783 return 0;
1784
1785 ret = wl1271_record_ap_key(wl, id,
1786 key_type, key_size,
1787 key, hlid, tx_seq_32,
1788 tx_seq_16);
1789 } else {
1790 ret = wl1271_cmd_set_ap_key(wl, action,
1791 id, key_type, key_size,
1792 key, hlid, tx_seq_32,
1793 tx_seq_16);
1794 }
1795
1796 if (ret < 0)
1797 return ret;
1798 } else {
1799 const u8 *addr;
1800 static const u8 bcast_addr[ETH_ALEN] = {
1801 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1802 };
1803
1804 addr = sta ? sta->addr : bcast_addr;
1805
1806 if (is_zero_ether_addr(addr)) {
1807 /* We dont support TX only encryption */
1808 return -EOPNOTSUPP;
1809 }
1810
1811 /* The wl1271 does not allow to remove unicast keys - they
1812 will be cleared automatically on next CMD_JOIN. Ignore the
1813 request silently, as we dont want the mac80211 to emit
1814 an error message. */
1815 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1816 return 0;
1817
1818 ret = wl1271_cmd_set_sta_key(wl, action,
1819 id, key_type, key_size,
1820 key, addr, tx_seq_32,
1821 tx_seq_16);
1822 if (ret < 0)
1823 return ret;
1824
1825 /* the default WEP key needs to be configured at least once */
1826 if (key_type == KEY_WEP) {
1827 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1828 wl->default_key);
1829 if (ret < 0)
1830 return ret;
1831 }
1832 }
1833
1834 return 0;
1835}
1836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1838 struct ieee80211_vif *vif,
1839 struct ieee80211_sta *sta,
1840 struct ieee80211_key_conf *key_conf)
1841{
1842 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001844 u32 tx_seq_32 = 0;
1845 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 u8 key_type;
1847
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001848 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1849
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001850 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001852 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853 key_conf->keylen, key_conf->flags);
1854 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1855
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856 mutex_lock(&wl->mutex);
1857
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001858 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1859 ret = -EAGAIN;
1860 goto out_unlock;
1861 }
1862
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 ret = wl1271_ps_elp_wakeup(wl, false);
1864 if (ret < 0)
1865 goto out_unlock;
1866
Johannes Berg97359d12010-08-10 09:46:38 +02001867 switch (key_conf->cipher) {
1868 case WLAN_CIPHER_SUITE_WEP40:
1869 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870 key_type = KEY_WEP;
1871
1872 key_conf->hw_key_idx = key_conf->keyidx;
1873 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001874 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875 key_type = KEY_TKIP;
1876
1877 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001878 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1879 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001881 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882 key_type = KEY_AES;
1883
1884 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001885 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1886 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001887 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001888 case WL1271_CIPHER_SUITE_GEM:
1889 key_type = KEY_GEM;
1890 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1891 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1892 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001893 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001894 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895
1896 ret = -EOPNOTSUPP;
1897 goto out_sleep;
1898 }
1899
1900 switch (cmd) {
1901 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001902 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1903 key_conf->keyidx, key_type,
1904 key_conf->keylen, key_conf->key,
1905 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001906 if (ret < 0) {
1907 wl1271_error("Could not add or replace key");
1908 goto out_sleep;
1909 }
1910 break;
1911
1912 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001913 ret = wl1271_set_key(wl, KEY_REMOVE,
1914 key_conf->keyidx, key_type,
1915 key_conf->keylen, key_conf->key,
1916 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001917 if (ret < 0) {
1918 wl1271_error("Could not remove key");
1919 goto out_sleep;
1920 }
1921 break;
1922
1923 default:
1924 wl1271_error("Unsupported key cmd 0x%x", cmd);
1925 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 break;
1927 }
1928
1929out_sleep:
1930 wl1271_ps_elp_sleep(wl);
1931
1932out_unlock:
1933 mutex_unlock(&wl->mutex);
1934
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935 return ret;
1936}
1937
1938static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001939 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 struct cfg80211_scan_request *req)
1941{
1942 struct wl1271 *wl = hw->priv;
1943 int ret;
1944 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001945 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946
1947 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1948
1949 if (req->n_ssids) {
1950 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001951 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 }
1953
1954 mutex_lock(&wl->mutex);
1955
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001956 if (wl->state == WL1271_STATE_OFF) {
1957 /*
1958 * We cannot return -EBUSY here because cfg80211 will expect
1959 * a call to ieee80211_scan_completed if we do - in this case
1960 * there won't be any call.
1961 */
1962 ret = -EAGAIN;
1963 goto out;
1964 }
1965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966 ret = wl1271_ps_elp_wakeup(wl, false);
1967 if (ret < 0)
1968 goto out;
1969
Luciano Coelho5924f892010-08-04 03:46:22 +03001970 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971
1972 wl1271_ps_elp_sleep(wl);
1973
1974out:
1975 mutex_unlock(&wl->mutex);
1976
1977 return ret;
1978}
1979
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001980static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1981{
1982 struct wl1271 *wl = hw->priv;
1983 int ret = 0;
1984
1985 mutex_lock(&wl->mutex);
1986
1987 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1988 ret = -EAGAIN;
1989 goto out;
1990 }
1991
1992 ret = wl1271_ps_elp_wakeup(wl, false);
1993 if (ret < 0)
1994 goto out;
1995
1996 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1997 if (ret < 0)
1998 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1999
2000 wl1271_ps_elp_sleep(wl);
2001
2002out:
2003 mutex_unlock(&wl->mutex);
2004
2005 return ret;
2006}
2007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2009{
2010 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002011 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012
2013 mutex_lock(&wl->mutex);
2014
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002015 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2016 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002017 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002018 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020 ret = wl1271_ps_elp_wakeup(wl, false);
2021 if (ret < 0)
2022 goto out;
2023
2024 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2025 if (ret < 0)
2026 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2027
2028 wl1271_ps_elp_sleep(wl);
2029
2030out:
2031 mutex_unlock(&wl->mutex);
2032
2033 return ret;
2034}
2035
Arik Nemtsove78a2872010-10-16 19:07:21 +02002036static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002037 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002038{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002039 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002040
2041 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002042 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002043 if (ptr[0] == WLAN_EID_SSID) {
2044 wl->ssid_len = ptr[1];
2045 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002046 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002047 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002048 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002049 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002050
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002051 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002052 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002053}
2054
Arik Nemtsove78a2872010-10-16 19:07:21 +02002055static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2056 struct ieee80211_bss_conf *bss_conf,
2057 u32 changed)
2058{
2059 int ret = 0;
2060
2061 if (changed & BSS_CHANGED_ERP_SLOT) {
2062 if (bss_conf->use_short_slot)
2063 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2064 else
2065 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2066 if (ret < 0) {
2067 wl1271_warning("Set slot time failed %d", ret);
2068 goto out;
2069 }
2070 }
2071
2072 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2073 if (bss_conf->use_short_preamble)
2074 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2075 else
2076 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2077 }
2078
2079 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2080 if (bss_conf->use_cts_prot)
2081 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2082 else
2083 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2084 if (ret < 0) {
2085 wl1271_warning("Set ctsprotect failed %d", ret);
2086 goto out;
2087 }
2088 }
2089
2090out:
2091 return ret;
2092}
2093
2094static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2095 struct ieee80211_vif *vif,
2096 struct ieee80211_bss_conf *bss_conf,
2097 u32 changed)
2098{
2099 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2100 int ret = 0;
2101
2102 if ((changed & BSS_CHANGED_BEACON_INT)) {
2103 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2104 bss_conf->beacon_int);
2105
2106 wl->beacon_int = bss_conf->beacon_int;
2107 }
2108
2109 if ((changed & BSS_CHANGED_BEACON)) {
2110 struct ieee80211_hdr *hdr;
2111 int ieoffset = offsetof(struct ieee80211_mgmt,
2112 u.beacon.variable);
2113 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2114 u16 tmpl_id;
2115
2116 if (!beacon)
2117 goto out;
2118
2119 wl1271_debug(DEBUG_MASTER, "beacon updated");
2120
2121 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2122 if (ret < 0) {
2123 dev_kfree_skb(beacon);
2124 goto out;
2125 }
2126 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2127 CMD_TEMPL_BEACON;
2128 ret = wl1271_cmd_template_set(wl, tmpl_id,
2129 beacon->data,
2130 beacon->len, 0,
2131 wl1271_tx_min_rate_get(wl));
2132 if (ret < 0) {
2133 dev_kfree_skb(beacon);
2134 goto out;
2135 }
2136
2137 hdr = (struct ieee80211_hdr *) beacon->data;
2138 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2139 IEEE80211_STYPE_PROBE_RESP);
2140
2141 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2142 CMD_TEMPL_PROBE_RESPONSE;
2143 ret = wl1271_cmd_template_set(wl,
2144 tmpl_id,
2145 beacon->data,
2146 beacon->len, 0,
2147 wl1271_tx_min_rate_get(wl));
2148 dev_kfree_skb(beacon);
2149 if (ret < 0)
2150 goto out;
2151 }
2152
2153out:
2154 return ret;
2155}
2156
2157/* AP mode changes */
2158static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159 struct ieee80211_vif *vif,
2160 struct ieee80211_bss_conf *bss_conf,
2161 u32 changed)
2162{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002163 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164
Arik Nemtsove78a2872010-10-16 19:07:21 +02002165 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2166 u32 rates = bss_conf->basic_rates;
2167 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168
Arik Nemtsove78a2872010-10-16 19:07:21 +02002169 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2170 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2171 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2172 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173
Arik Nemtsove78a2872010-10-16 19:07:21 +02002174 /* update the AP management rate policy with the new rates */
2175 mgmt_rc.enabled_rates = wl->basic_rate_set;
2176 mgmt_rc.long_retry_limit = 10;
2177 mgmt_rc.short_retry_limit = 10;
2178 mgmt_rc.aflags = 0;
2179 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2180 ACX_TX_AP_MODE_MGMT_RATE);
2181 if (ret < 0) {
2182 wl1271_error("AP mgmt policy change failed %d", ret);
2183 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002184 }
2185 }
2186
Arik Nemtsove78a2872010-10-16 19:07:21 +02002187 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2188 if (ret < 0)
2189 goto out;
2190
2191 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2192 if (bss_conf->enable_beacon) {
2193 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2194 ret = wl1271_cmd_start_bss(wl);
2195 if (ret < 0)
2196 goto out;
2197
2198 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2199 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002200
2201 ret = wl1271_ap_init_hwenc(wl);
2202 if (ret < 0)
2203 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002204 }
2205 } else {
2206 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2207 ret = wl1271_cmd_stop_bss(wl);
2208 if (ret < 0)
2209 goto out;
2210
2211 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2212 wl1271_debug(DEBUG_AP, "stopped AP");
2213 }
2214 }
2215 }
2216
2217 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2218 if (ret < 0)
2219 goto out;
2220out:
2221 return;
2222}
2223
2224/* STA/IBSS mode changes */
2225static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2226 struct ieee80211_vif *vif,
2227 struct ieee80211_bss_conf *bss_conf,
2228 u32 changed)
2229{
2230 bool do_join = false, set_assoc = false;
2231 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2232 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002233 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002234
2235 if (is_ibss) {
2236 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2237 changed);
2238 if (ret < 0)
2239 goto out;
2240 }
2241
2242 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2243 do_join = true;
2244
2245 /* Need to update the SSID (for filtering etc) */
2246 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2247 do_join = true;
2248
2249 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002250 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2251 bss_conf->enable_beacon ? "enabled" : "disabled");
2252
2253 if (bss_conf->enable_beacon)
2254 wl->set_bss_type = BSS_TYPE_IBSS;
2255 else
2256 wl->set_bss_type = BSS_TYPE_STA_BSS;
2257 do_join = true;
2258 }
2259
Arik Nemtsove78a2872010-10-16 19:07:21 +02002260 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002261 bool enable = false;
2262 if (bss_conf->cqm_rssi_thold)
2263 enable = true;
2264 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2265 bss_conf->cqm_rssi_thold,
2266 bss_conf->cqm_rssi_hyst);
2267 if (ret < 0)
2268 goto out;
2269 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2270 }
2271
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002272 if ((changed & BSS_CHANGED_BSSID) &&
2273 /*
2274 * Now we know the correct bssid, so we send a new join command
2275 * and enable the BSSID filter
2276 */
2277 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002278 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002279
Eliad Pellerfa287b82010-12-26 09:27:50 +01002280 if (!is_zero_ether_addr(wl->bssid)) {
2281 ret = wl1271_cmd_build_null_data(wl);
2282 if (ret < 0)
2283 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002284
Eliad Pellerfa287b82010-12-26 09:27:50 +01002285 ret = wl1271_build_qos_null_data(wl);
2286 if (ret < 0)
2287 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002288
Eliad Pellerfa287b82010-12-26 09:27:50 +01002289 /* filter out all packets not from this BSSID */
2290 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002291
Eliad Pellerfa287b82010-12-26 09:27:50 +01002292 /* Need to update the BSSID (for filtering etc) */
2293 do_join = true;
2294 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002295 }
2296
Arik Nemtsove78a2872010-10-16 19:07:21 +02002297 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002299 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002300 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002302 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002304 wl->ps_poll_failures = 0;
2305
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002306 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002307 * use basic rates from AP, and determine lowest rate
2308 * to use with control frames.
2309 */
2310 rates = bss_conf->basic_rates;
2311 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2312 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002313 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002314 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002315 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002316 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002317
2318 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002319 * with wl1271, we don't need to update the
2320 * beacon_int and dtim_period, because the firmware
2321 * updates it by itself when the first beacon is
2322 * received after a join.
2323 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2325 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002326 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002328 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002329 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002330 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002331 dev_kfree_skb(wl->probereq);
2332 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2333 ieoffset = offsetof(struct ieee80211_mgmt,
2334 u.probe_req.variable);
2335 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002336
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002337 /* enable the connection monitoring feature */
2338 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002339 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002340 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341
2342 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002343 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2344 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002345 enum wl1271_cmd_ps_mode mode;
2346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002348 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002349 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002350 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002352 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002353 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002354 } else {
2355 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002356 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002357 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002358 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002359
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002360 /* free probe-request template */
2361 dev_kfree_skb(wl->probereq);
2362 wl->probereq = NULL;
2363
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002364 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002365 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002366
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002367 /* revert back to minimum rates for the current band */
2368 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002369 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002370 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002371 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002372 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002373
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002374 /* disable connection monitor features */
2375 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002376
2377 /* Disable the keep-alive feature */
2378 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002379 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002380 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002381
2382 /* restore the bssid filter and go to dummy bssid */
2383 wl1271_unjoin(wl);
2384 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002385 }
2386 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002387
Arik Nemtsove78a2872010-10-16 19:07:21 +02002388 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2389 if (ret < 0)
2390 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002392 rcu_read_lock();
2393 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2394 if (sta) {
2395 /* handle new association with HT and HT information change */
2396 if ((changed & BSS_CHANGED_HT) &&
2397 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2398 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2399 true);
2400 if (ret < 0) {
2401 wl1271_warning("Set ht cap true failed %d",
2402 ret);
2403 rcu_read_unlock();
2404 goto out;
2405 }
Shahar Levi18357852010-10-13 16:09:41 +02002406 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002407 bss_conf->ht_operation_mode);
2408 if (ret < 0) {
2409 wl1271_warning("Set ht information failed %d",
2410 ret);
2411 rcu_read_unlock();
2412 goto out;
2413 }
2414 }
2415 /* handle new association without HT and disassociation */
2416 else if (changed & BSS_CHANGED_ASSOC) {
2417 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2418 false);
2419 if (ret < 0) {
2420 wl1271_warning("Set ht cap false failed %d",
2421 ret);
2422 rcu_read_unlock();
2423 goto out;
2424 }
Shahar Levi18357852010-10-13 16:09:41 +02002425 }
2426 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002427 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002428
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002429 if (changed & BSS_CHANGED_ARP_FILTER) {
2430 __be32 addr = bss_conf->arp_addr_list[0];
2431 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2432
Eliad Pellerc5312772010-12-09 11:31:27 +02002433 if (bss_conf->arp_addr_cnt == 1 &&
2434 bss_conf->arp_filter_enabled) {
2435 /*
2436 * The template should have been configured only upon
2437 * association. however, it seems that the correct ip
2438 * isn't being set (when sending), so we have to
2439 * reconfigure the template upon every ip change.
2440 */
2441 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2442 if (ret < 0) {
2443 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002444 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002445 }
2446
2447 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002448 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002449 addr);
2450 } else
2451 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002452
2453 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002454 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002455 }
2456
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002457 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002458 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002459 if (ret < 0) {
2460 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002461 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002462 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002463 }
2464
Arik Nemtsove78a2872010-10-16 19:07:21 +02002465out:
2466 return;
2467}
2468
2469static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2470 struct ieee80211_vif *vif,
2471 struct ieee80211_bss_conf *bss_conf,
2472 u32 changed)
2473{
2474 struct wl1271 *wl = hw->priv;
2475 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2476 int ret;
2477
2478 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2479 (int)changed);
2480
2481 mutex_lock(&wl->mutex);
2482
2483 if (unlikely(wl->state == WL1271_STATE_OFF))
2484 goto out;
2485
2486 ret = wl1271_ps_elp_wakeup(wl, false);
2487 if (ret < 0)
2488 goto out;
2489
2490 if (is_ap)
2491 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2492 else
2493 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2494
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002495 wl1271_ps_elp_sleep(wl);
2496
2497out:
2498 mutex_unlock(&wl->mutex);
2499}
2500
Kalle Valoc6999d82010-02-18 13:25:41 +02002501static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2502 const struct ieee80211_tx_queue_params *params)
2503{
2504 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002505 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002506 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002507
2508 mutex_lock(&wl->mutex);
2509
2510 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2511
Kalle Valo4695dc92010-03-18 12:26:38 +02002512 if (params->uapsd)
2513 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2514 else
2515 ps_scheme = CONF_PS_SCHEME_LEGACY;
2516
Arik Nemtsov488fc542010-10-16 20:33:45 +02002517 if (wl->state == WL1271_STATE_OFF) {
2518 /*
2519 * If the state is off, the parameters will be recorded and
2520 * configured on init. This happens in AP-mode.
2521 */
2522 struct conf_tx_ac_category *conf_ac =
2523 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2524 struct conf_tx_tid *conf_tid =
2525 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2526
2527 conf_ac->ac = wl1271_tx_get_queue(queue);
2528 conf_ac->cw_min = (u8)params->cw_min;
2529 conf_ac->cw_max = params->cw_max;
2530 conf_ac->aifsn = params->aifs;
2531 conf_ac->tx_op_limit = params->txop << 5;
2532
2533 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2534 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2535 conf_tid->tsid = wl1271_tx_get_queue(queue);
2536 conf_tid->ps_scheme = ps_scheme;
2537 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2538 conf_tid->apsd_conf[0] = 0;
2539 conf_tid->apsd_conf[1] = 0;
2540 } else {
2541 ret = wl1271_ps_elp_wakeup(wl, false);
2542 if (ret < 0)
2543 goto out;
2544
2545 /*
2546 * the txop is confed in units of 32us by the mac80211,
2547 * we need us
2548 */
2549 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2550 params->cw_min, params->cw_max,
2551 params->aifs, params->txop << 5);
2552 if (ret < 0)
2553 goto out_sleep;
2554
2555 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2556 CONF_CHANNEL_TYPE_EDCF,
2557 wl1271_tx_get_queue(queue),
2558 ps_scheme, CONF_ACK_POLICY_LEGACY,
2559 0, 0);
2560 if (ret < 0)
2561 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002562
2563out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002564 wl1271_ps_elp_sleep(wl);
2565 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002566
2567out:
2568 mutex_unlock(&wl->mutex);
2569
2570 return ret;
2571}
2572
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002573static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2574{
2575
2576 struct wl1271 *wl = hw->priv;
2577 u64 mactime = ULLONG_MAX;
2578 int ret;
2579
2580 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2581
2582 mutex_lock(&wl->mutex);
2583
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002584 if (unlikely(wl->state == WL1271_STATE_OFF))
2585 goto out;
2586
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002587 ret = wl1271_ps_elp_wakeup(wl, false);
2588 if (ret < 0)
2589 goto out;
2590
2591 ret = wl1271_acx_tsf_info(wl, &mactime);
2592 if (ret < 0)
2593 goto out_sleep;
2594
2595out_sleep:
2596 wl1271_ps_elp_sleep(wl);
2597
2598out:
2599 mutex_unlock(&wl->mutex);
2600 return mactime;
2601}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002602
John W. Linvilleece550d2010-07-28 16:41:06 -04002603static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2604 struct survey_info *survey)
2605{
2606 struct wl1271 *wl = hw->priv;
2607 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002608
John W. Linvilleece550d2010-07-28 16:41:06 -04002609 if (idx != 0)
2610 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002611
John W. Linvilleece550d2010-07-28 16:41:06 -04002612 survey->channel = conf->channel;
2613 survey->filled = SURVEY_INFO_NOISE_DBM;
2614 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002615
John W. Linvilleece550d2010-07-28 16:41:06 -04002616 return 0;
2617}
2618
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002619static int wl1271_allocate_hlid(struct wl1271 *wl,
2620 struct ieee80211_sta *sta,
2621 u8 *hlid)
2622{
2623 struct wl1271_station *wl_sta;
2624 int id;
2625
2626 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2627 if (id >= AP_MAX_STATIONS) {
2628 wl1271_warning("could not allocate HLID - too much stations");
2629 return -EBUSY;
2630 }
2631
2632 wl_sta = (struct wl1271_station *)sta->drv_priv;
2633
2634 __set_bit(id, wl->ap_hlid_map);
2635 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2636 *hlid = wl_sta->hlid;
2637 return 0;
2638}
2639
2640static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2641{
2642 int id = hlid - WL1271_AP_STA_HLID_START;
2643
2644 __clear_bit(id, wl->ap_hlid_map);
2645}
2646
2647static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2648 struct ieee80211_vif *vif,
2649 struct ieee80211_sta *sta)
2650{
2651 struct wl1271 *wl = hw->priv;
2652 int ret = 0;
2653 u8 hlid;
2654
2655 mutex_lock(&wl->mutex);
2656
2657 if (unlikely(wl->state == WL1271_STATE_OFF))
2658 goto out;
2659
2660 if (wl->bss_type != BSS_TYPE_AP_BSS)
2661 goto out;
2662
2663 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2664
2665 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2666 if (ret < 0)
2667 goto out;
2668
2669 ret = wl1271_ps_elp_wakeup(wl, false);
2670 if (ret < 0)
2671 goto out;
2672
2673 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2674 if (ret < 0)
2675 goto out_sleep;
2676
2677out_sleep:
2678 wl1271_ps_elp_sleep(wl);
2679
2680out:
2681 mutex_unlock(&wl->mutex);
2682 return ret;
2683}
2684
2685static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2686 struct ieee80211_vif *vif,
2687 struct ieee80211_sta *sta)
2688{
2689 struct wl1271 *wl = hw->priv;
2690 struct wl1271_station *wl_sta;
2691 int ret = 0, id;
2692
2693 mutex_lock(&wl->mutex);
2694
2695 if (unlikely(wl->state == WL1271_STATE_OFF))
2696 goto out;
2697
2698 if (wl->bss_type != BSS_TYPE_AP_BSS)
2699 goto out;
2700
2701 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2702
2703 wl_sta = (struct wl1271_station *)sta->drv_priv;
2704 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2705 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2706 goto out;
2707
2708 ret = wl1271_ps_elp_wakeup(wl, false);
2709 if (ret < 0)
2710 goto out;
2711
2712 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2713 if (ret < 0)
2714 goto out_sleep;
2715
2716 wl1271_free_hlid(wl, wl_sta->hlid);
2717
2718out_sleep:
2719 wl1271_ps_elp_sleep(wl);
2720
2721out:
2722 mutex_unlock(&wl->mutex);
2723 return ret;
2724}
2725
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002726int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2727 enum ieee80211_ampdu_mlme_action action,
2728 struct ieee80211_sta *sta, u16 tid, u16 *ssn)
2729{
2730 struct wl1271 *wl = hw->priv;
2731 int ret;
2732
2733 mutex_lock(&wl->mutex);
2734
2735 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2736 ret = -EAGAIN;
2737 goto out;
2738 }
2739
2740 ret = wl1271_ps_elp_wakeup(wl, false);
2741 if (ret < 0)
2742 goto out;
2743
2744 switch (action) {
2745 case IEEE80211_AMPDU_RX_START:
2746 if (wl->ba_support) {
2747 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2748 true);
2749 if (!ret)
2750 wl->ba_rx_bitmap |= BIT(tid);
2751 } else {
2752 ret = -ENOTSUPP;
2753 }
2754 break;
2755
2756 case IEEE80211_AMPDU_RX_STOP:
2757 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2758 if (!ret)
2759 wl->ba_rx_bitmap &= ~BIT(tid);
2760 break;
2761
2762 /*
2763 * The BA initiator session management in FW independently.
2764 * Falling break here on purpose for all TX APDU commands.
2765 */
2766 case IEEE80211_AMPDU_TX_START:
2767 case IEEE80211_AMPDU_TX_STOP:
2768 case IEEE80211_AMPDU_TX_OPERATIONAL:
2769 ret = -EINVAL;
2770 break;
2771
2772 default:
2773 wl1271_error("Incorrect ampdu action id=%x\n", action);
2774 ret = -EINVAL;
2775 }
2776
2777 wl1271_ps_elp_sleep(wl);
2778
2779out:
2780 mutex_unlock(&wl->mutex);
2781
2782 return ret;
2783}
2784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785/* can't be const, mac80211 writes to this */
2786static struct ieee80211_rate wl1271_rates[] = {
2787 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002788 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2789 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002790 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002791 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2792 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2794 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002795 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2796 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2798 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002799 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2800 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002801 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2802 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002803 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2804 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002805 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002806 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2807 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002809 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2810 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002811 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002812 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2813 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002814 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002815 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2816 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002817 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002818 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2819 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002820 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002821 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2822 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002823 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002824 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2825 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002826};
2827
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002828/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002829static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002830 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002831 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002832 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2833 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2834 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002835 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002836 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2837 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2838 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002839 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002840 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2841 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2842 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002843 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002844};
2845
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002846/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002847static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002848 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002849 7, /* CONF_HW_RXTX_RATE_MCS7 */
2850 6, /* CONF_HW_RXTX_RATE_MCS6 */
2851 5, /* CONF_HW_RXTX_RATE_MCS5 */
2852 4, /* CONF_HW_RXTX_RATE_MCS4 */
2853 3, /* CONF_HW_RXTX_RATE_MCS3 */
2854 2, /* CONF_HW_RXTX_RATE_MCS2 */
2855 1, /* CONF_HW_RXTX_RATE_MCS1 */
2856 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002857
2858 11, /* CONF_HW_RXTX_RATE_54 */
2859 10, /* CONF_HW_RXTX_RATE_48 */
2860 9, /* CONF_HW_RXTX_RATE_36 */
2861 8, /* CONF_HW_RXTX_RATE_24 */
2862
2863 /* TI-specific rate */
2864 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2865
2866 7, /* CONF_HW_RXTX_RATE_18 */
2867 6, /* CONF_HW_RXTX_RATE_12 */
2868 3, /* CONF_HW_RXTX_RATE_11 */
2869 5, /* CONF_HW_RXTX_RATE_9 */
2870 4, /* CONF_HW_RXTX_RATE_6 */
2871 2, /* CONF_HW_RXTX_RATE_5_5 */
2872 1, /* CONF_HW_RXTX_RATE_2 */
2873 0 /* CONF_HW_RXTX_RATE_1 */
2874};
2875
Shahar Levie8b03a22010-10-13 16:09:39 +02002876/* 11n STA capabilities */
2877#define HW_RX_HIGHEST_RATE 72
2878
Shahar Levi00d20102010-11-08 11:20:10 +00002879#ifdef CONFIG_WL12XX_HT
2880#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002881 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2882 .ht_supported = true, \
2883 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2884 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2885 .mcs = { \
2886 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2887 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2888 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2889 }, \
2890}
Shahar Levi18357852010-10-13 16:09:41 +02002891#else
Shahar Levi00d20102010-11-08 11:20:10 +00002892#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002893 .ht_supported = false, \
2894}
2895#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897/* can't be const, mac80211 writes to this */
2898static struct ieee80211_supported_band wl1271_band_2ghz = {
2899 .channels = wl1271_channels,
2900 .n_channels = ARRAY_SIZE(wl1271_channels),
2901 .bitrates = wl1271_rates,
2902 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002903 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904};
2905
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002906/* 5 GHz data rates for WL1273 */
2907static struct ieee80211_rate wl1271_rates_5ghz[] = {
2908 { .bitrate = 60,
2909 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2910 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2911 { .bitrate = 90,
2912 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2913 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2914 { .bitrate = 120,
2915 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2916 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2917 { .bitrate = 180,
2918 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2919 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2920 { .bitrate = 240,
2921 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2922 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2923 { .bitrate = 360,
2924 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2925 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2926 { .bitrate = 480,
2927 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2928 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2929 { .bitrate = 540,
2930 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2931 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2932};
2933
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002934/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002935static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002936 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002937 { .hw_value = 8, .center_freq = 5040},
2938 { .hw_value = 9, .center_freq = 5045},
2939 { .hw_value = 11, .center_freq = 5055},
2940 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002941 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002942 { .hw_value = 34, .center_freq = 5170},
2943 { .hw_value = 36, .center_freq = 5180},
2944 { .hw_value = 38, .center_freq = 5190},
2945 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002946 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002947 { .hw_value = 44, .center_freq = 5220},
2948 { .hw_value = 46, .center_freq = 5230},
2949 { .hw_value = 48, .center_freq = 5240},
2950 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002951 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002952 { .hw_value = 60, .center_freq = 5300},
2953 { .hw_value = 64, .center_freq = 5320},
2954 { .hw_value = 100, .center_freq = 5500},
2955 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002956 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002957 { .hw_value = 112, .center_freq = 5560},
2958 { .hw_value = 116, .center_freq = 5580},
2959 { .hw_value = 120, .center_freq = 5600},
2960 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002961 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002962 { .hw_value = 132, .center_freq = 5660},
2963 { .hw_value = 136, .center_freq = 5680},
2964 { .hw_value = 140, .center_freq = 5700},
2965 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002966 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002967 { .hw_value = 157, .center_freq = 5785},
2968 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002969 { .hw_value = 165, .center_freq = 5825},
2970};
2971
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002972/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002973static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002974 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002975 7, /* CONF_HW_RXTX_RATE_MCS7 */
2976 6, /* CONF_HW_RXTX_RATE_MCS6 */
2977 5, /* CONF_HW_RXTX_RATE_MCS5 */
2978 4, /* CONF_HW_RXTX_RATE_MCS4 */
2979 3, /* CONF_HW_RXTX_RATE_MCS3 */
2980 2, /* CONF_HW_RXTX_RATE_MCS2 */
2981 1, /* CONF_HW_RXTX_RATE_MCS1 */
2982 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002983
2984 7, /* CONF_HW_RXTX_RATE_54 */
2985 6, /* CONF_HW_RXTX_RATE_48 */
2986 5, /* CONF_HW_RXTX_RATE_36 */
2987 4, /* CONF_HW_RXTX_RATE_24 */
2988
2989 /* TI-specific rate */
2990 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2991
2992 3, /* CONF_HW_RXTX_RATE_18 */
2993 2, /* CONF_HW_RXTX_RATE_12 */
2994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2995 1, /* CONF_HW_RXTX_RATE_9 */
2996 0, /* CONF_HW_RXTX_RATE_6 */
2997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2999 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3000};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003001
3002static struct ieee80211_supported_band wl1271_band_5ghz = {
3003 .channels = wl1271_channels_5ghz,
3004 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3005 .bitrates = wl1271_rates_5ghz,
3006 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003007 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003008};
3009
Tobias Klausera0ea9492010-05-20 10:38:11 +02003010static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003011 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3012 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3013};
3014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015static const struct ieee80211_ops wl1271_ops = {
3016 .start = wl1271_op_start,
3017 .stop = wl1271_op_stop,
3018 .add_interface = wl1271_op_add_interface,
3019 .remove_interface = wl1271_op_remove_interface,
3020 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003021 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 .configure_filter = wl1271_op_configure_filter,
3023 .tx = wl1271_op_tx,
3024 .set_key = wl1271_op_set_key,
3025 .hw_scan = wl1271_op_hw_scan,
3026 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003027 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003029 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003030 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003031 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003032 .sta_add = wl1271_op_sta_add,
3033 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003034 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003035 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036};
3037
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003038
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003039u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003040{
3041 u8 idx;
3042
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003043 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003044
3045 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3046 wl1271_error("Illegal RX rate from HW: %d", rate);
3047 return 0;
3048 }
3049
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003050 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003051 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3052 wl1271_error("Unsupported RX rate from HW: %d", rate);
3053 return 0;
3054 }
3055
3056 return idx;
3057}
3058
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003059static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3060 struct device_attribute *attr,
3061 char *buf)
3062{
3063 struct wl1271 *wl = dev_get_drvdata(dev);
3064 ssize_t len;
3065
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003066 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003067
3068 mutex_lock(&wl->mutex);
3069 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3070 wl->sg_enabled);
3071 mutex_unlock(&wl->mutex);
3072
3073 return len;
3074
3075}
3076
3077static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3078 struct device_attribute *attr,
3079 const char *buf, size_t count)
3080{
3081 struct wl1271 *wl = dev_get_drvdata(dev);
3082 unsigned long res;
3083 int ret;
3084
3085 ret = strict_strtoul(buf, 10, &res);
3086
3087 if (ret < 0) {
3088 wl1271_warning("incorrect value written to bt_coex_mode");
3089 return count;
3090 }
3091
3092 mutex_lock(&wl->mutex);
3093
3094 res = !!res;
3095
3096 if (res == wl->sg_enabled)
3097 goto out;
3098
3099 wl->sg_enabled = res;
3100
3101 if (wl->state == WL1271_STATE_OFF)
3102 goto out;
3103
3104 ret = wl1271_ps_elp_wakeup(wl, false);
3105 if (ret < 0)
3106 goto out;
3107
3108 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3109 wl1271_ps_elp_sleep(wl);
3110
3111 out:
3112 mutex_unlock(&wl->mutex);
3113 return count;
3114}
3115
3116static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3117 wl1271_sysfs_show_bt_coex_state,
3118 wl1271_sysfs_store_bt_coex_state);
3119
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003120static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3121 struct device_attribute *attr,
3122 char *buf)
3123{
3124 struct wl1271 *wl = dev_get_drvdata(dev);
3125 ssize_t len;
3126
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003127 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003128
3129 mutex_lock(&wl->mutex);
3130 if (wl->hw_pg_ver >= 0)
3131 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3132 else
3133 len = snprintf(buf, len, "n/a\n");
3134 mutex_unlock(&wl->mutex);
3135
3136 return len;
3137}
3138
3139static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3140 wl1271_sysfs_show_hw_pg_ver, NULL);
3141
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003142int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143{
3144 int ret;
3145
3146 if (wl->mac80211_registered)
3147 return 0;
3148
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003149 ret = wl1271_fetch_nvs(wl);
3150 if (ret == 0) {
3151 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3152
3153 wl->mac_addr[0] = nvs_ptr[11];
3154 wl->mac_addr[1] = nvs_ptr[10];
3155 wl->mac_addr[2] = nvs_ptr[6];
3156 wl->mac_addr[3] = nvs_ptr[5];
3157 wl->mac_addr[4] = nvs_ptr[4];
3158 wl->mac_addr[5] = nvs_ptr[3];
3159 }
3160
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003161 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3162
3163 ret = ieee80211_register_hw(wl->hw);
3164 if (ret < 0) {
3165 wl1271_error("unable to register mac80211 hw: %d", ret);
3166 return ret;
3167 }
3168
3169 wl->mac80211_registered = true;
3170
Eliad Pellerd60080a2010-11-24 12:53:16 +02003171 wl1271_debugfs_init(wl);
3172
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003173 register_netdevice_notifier(&wl1271_dev_notifier);
3174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003175 wl1271_notice("loaded");
3176
3177 return 0;
3178}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003179EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003180
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003181void wl1271_unregister_hw(struct wl1271 *wl)
3182{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003183 if (wl->state == WL1271_STATE_PLT)
3184 __wl1271_plt_stop(wl);
3185
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003186 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003187 ieee80211_unregister_hw(wl->hw);
3188 wl->mac80211_registered = false;
3189
3190}
3191EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3192
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003193int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003194{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003195 static const u32 cipher_suites[] = {
3196 WLAN_CIPHER_SUITE_WEP40,
3197 WLAN_CIPHER_SUITE_WEP104,
3198 WLAN_CIPHER_SUITE_TKIP,
3199 WLAN_CIPHER_SUITE_CCMP,
3200 WL1271_CIPHER_SUITE_GEM,
3201 };
3202
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003203 /* The tx descriptor buffer and the TKIP space. */
3204 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3205 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206
3207 /* unit us */
3208 /* FIXME: find a proper value */
3209 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003210 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211
3212 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003213 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003214 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003215 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003216 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003217 IEEE80211_HW_CONNECTION_MONITOR |
3218 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003220 wl->hw->wiphy->cipher_suites = cipher_suites;
3221 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3222
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003223 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003224 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003225 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003226 /*
3227 * Maximum length of elements in scanning probe request templates
3228 * should be the maximum length possible for a template, without
3229 * the IEEE80211 header of the template
3230 */
3231 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3232 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003233
3234 /*
3235 * We keep local copies of the band structs because we need to
3236 * modify them on a per-device basis.
3237 */
3238 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3239 sizeof(wl1271_band_2ghz));
3240 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3241 sizeof(wl1271_band_5ghz));
3242
3243 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3244 &wl->bands[IEEE80211_BAND_2GHZ];
3245 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3246 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003247
Kalle Valo12bd8942010-03-18 12:26:33 +02003248 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003249 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003250
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003251 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3252
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003253 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003254
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003255 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3256
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003257 wl->hw->max_rx_aggregation_subframes = 8;
3258
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003259 return 0;
3260}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003261EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003263#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003264
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003265struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003266{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003268 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003269 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003270 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003271 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003272
3273 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3274 if (!hw) {
3275 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003276 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003277 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003278 }
3279
Julia Lawall929ebd32010-05-15 23:16:39 +02003280 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003281 if (!plat_dev) {
3282 wl1271_error("could not allocate platform_device");
3283 ret = -ENOMEM;
3284 goto err_plat_alloc;
3285 }
3286
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003287 wl = hw->priv;
3288 memset(wl, 0, sizeof(*wl));
3289
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003290 INIT_LIST_HEAD(&wl->list);
3291
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003292 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003293 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003295 for (i = 0; i < NUM_TX_QUEUES; i++)
3296 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003297
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003298 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003299 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003300 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3301 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3302 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3303 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003304 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003305 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003308 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3309 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003310 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003311 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003312 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003313 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003314 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3315 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003316 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003317 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003318 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003319 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003320 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003321 wl->bss_type = MAX_BSS_TYPE;
3322 wl->set_bss_type = MAX_BSS_TYPE;
3323 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003324
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003325 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003326 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003327 wl->tx_frames[i] = NULL;
3328
3329 spin_lock_init(&wl->wl_lock);
3330
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331 wl->state = WL1271_STATE_OFF;
3332 mutex_init(&wl->mutex);
3333
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003334 /* Apply default driver configuration. */
3335 wl1271_conf_init(wl);
3336
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003337 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3338 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3339 if (!wl->aggr_buf) {
3340 ret = -ENOMEM;
3341 goto err_hw;
3342 }
3343
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003344 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003345 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003346 if (ret) {
3347 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003348 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003349 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003350 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003351
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003352 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003353 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003354 if (ret < 0) {
3355 wl1271_error("failed to create sysfs file bt_coex_state");
3356 goto err_platform;
3357 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003358
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003359 /* Create sysfs file to get HW PG version */
3360 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3361 if (ret < 0) {
3362 wl1271_error("failed to create sysfs file hw_pg_ver");
3363 goto err_bt_coex_state;
3364 }
3365
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003366 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003367
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003368err_bt_coex_state:
3369 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3370
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003371err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003372 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003373
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003374err_aggr:
3375 free_pages((unsigned long)wl->aggr_buf, order);
3376
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003377err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003378 wl1271_debugfs_exit(wl);
3379 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003380
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003381err_plat_alloc:
3382 ieee80211_free_hw(hw);
3383
3384err_hw_alloc:
3385
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003386 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003387}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003388EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003389
3390int wl1271_free_hw(struct wl1271 *wl)
3391{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003392 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003393 free_pages((unsigned long)wl->aggr_buf,
3394 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003395 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003396
3397 wl1271_debugfs_exit(wl);
3398
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003399 vfree(wl->fw);
3400 wl->fw = NULL;
3401 kfree(wl->nvs);
3402 wl->nvs = NULL;
3403
3404 kfree(wl->fw_status);
3405 kfree(wl->tx_res_if);
3406
3407 ieee80211_free_hw(wl->hw);
3408
3409 return 0;
3410}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003411EXPORT_SYMBOL_GPL(wl1271_free_hw);
3412
Guy Eilam491bbd62011-01-12 10:33:29 +01003413u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003414EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003415module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003416MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3417
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003418MODULE_LICENSE("GPL");
3419MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3420MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");