blob: e535e79e269d2ad0b1c31c44867da6feda0d1f54 [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 Coelhod6e19d132009-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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-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 Pirko22bedad32010-04-01 21:22:57 +00001600 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001601 fp->mc_list_length++;
Jiri Pirko22bedad32010-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,
2448 (ACX_ARP_FILTER_ARP_FILTERING |
2449 ACX_ARP_FILTER_AUTO_ARP),
2450 addr);
2451 } else
2452 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002453
2454 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002455 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002456 }
2457
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002458 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002459 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002460 if (ret < 0) {
2461 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002462 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002463 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002464 }
2465
Arik Nemtsove78a2872010-10-16 19:07:21 +02002466out:
2467 return;
2468}
2469
2470static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2471 struct ieee80211_vif *vif,
2472 struct ieee80211_bss_conf *bss_conf,
2473 u32 changed)
2474{
2475 struct wl1271 *wl = hw->priv;
2476 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2477 int ret;
2478
2479 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2480 (int)changed);
2481
2482 mutex_lock(&wl->mutex);
2483
2484 if (unlikely(wl->state == WL1271_STATE_OFF))
2485 goto out;
2486
2487 ret = wl1271_ps_elp_wakeup(wl, false);
2488 if (ret < 0)
2489 goto out;
2490
2491 if (is_ap)
2492 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2493 else
2494 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002496 wl1271_ps_elp_sleep(wl);
2497
2498out:
2499 mutex_unlock(&wl->mutex);
2500}
2501
Kalle Valoc6999d82010-02-18 13:25:41 +02002502static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2503 const struct ieee80211_tx_queue_params *params)
2504{
2505 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002506 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002507 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002508
2509 mutex_lock(&wl->mutex);
2510
2511 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2512
Kalle Valo4695dc92010-03-18 12:26:38 +02002513 if (params->uapsd)
2514 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2515 else
2516 ps_scheme = CONF_PS_SCHEME_LEGACY;
2517
Arik Nemtsov488fc542010-10-16 20:33:45 +02002518 if (wl->state == WL1271_STATE_OFF) {
2519 /*
2520 * If the state is off, the parameters will be recorded and
2521 * configured on init. This happens in AP-mode.
2522 */
2523 struct conf_tx_ac_category *conf_ac =
2524 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2525 struct conf_tx_tid *conf_tid =
2526 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2527
2528 conf_ac->ac = wl1271_tx_get_queue(queue);
2529 conf_ac->cw_min = (u8)params->cw_min;
2530 conf_ac->cw_max = params->cw_max;
2531 conf_ac->aifsn = params->aifs;
2532 conf_ac->tx_op_limit = params->txop << 5;
2533
2534 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2535 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2536 conf_tid->tsid = wl1271_tx_get_queue(queue);
2537 conf_tid->ps_scheme = ps_scheme;
2538 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2539 conf_tid->apsd_conf[0] = 0;
2540 conf_tid->apsd_conf[1] = 0;
2541 } else {
2542 ret = wl1271_ps_elp_wakeup(wl, false);
2543 if (ret < 0)
2544 goto out;
2545
2546 /*
2547 * the txop is confed in units of 32us by the mac80211,
2548 * we need us
2549 */
2550 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2551 params->cw_min, params->cw_max,
2552 params->aifs, params->txop << 5);
2553 if (ret < 0)
2554 goto out_sleep;
2555
2556 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2557 CONF_CHANNEL_TYPE_EDCF,
2558 wl1271_tx_get_queue(queue),
2559 ps_scheme, CONF_ACK_POLICY_LEGACY,
2560 0, 0);
2561 if (ret < 0)
2562 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002563
2564out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002565 wl1271_ps_elp_sleep(wl);
2566 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002567
2568out:
2569 mutex_unlock(&wl->mutex);
2570
2571 return ret;
2572}
2573
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002574static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2575{
2576
2577 struct wl1271 *wl = hw->priv;
2578 u64 mactime = ULLONG_MAX;
2579 int ret;
2580
2581 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2582
2583 mutex_lock(&wl->mutex);
2584
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002585 if (unlikely(wl->state == WL1271_STATE_OFF))
2586 goto out;
2587
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002588 ret = wl1271_ps_elp_wakeup(wl, false);
2589 if (ret < 0)
2590 goto out;
2591
2592 ret = wl1271_acx_tsf_info(wl, &mactime);
2593 if (ret < 0)
2594 goto out_sleep;
2595
2596out_sleep:
2597 wl1271_ps_elp_sleep(wl);
2598
2599out:
2600 mutex_unlock(&wl->mutex);
2601 return mactime;
2602}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002603
John W. Linvilleece550d2010-07-28 16:41:06 -04002604static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2605 struct survey_info *survey)
2606{
2607 struct wl1271 *wl = hw->priv;
2608 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002609
John W. Linvilleece550d2010-07-28 16:41:06 -04002610 if (idx != 0)
2611 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002612
John W. Linvilleece550d2010-07-28 16:41:06 -04002613 survey->channel = conf->channel;
2614 survey->filled = SURVEY_INFO_NOISE_DBM;
2615 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002616
John W. Linvilleece550d2010-07-28 16:41:06 -04002617 return 0;
2618}
2619
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002620static int wl1271_allocate_hlid(struct wl1271 *wl,
2621 struct ieee80211_sta *sta,
2622 u8 *hlid)
2623{
2624 struct wl1271_station *wl_sta;
2625 int id;
2626
2627 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2628 if (id >= AP_MAX_STATIONS) {
2629 wl1271_warning("could not allocate HLID - too much stations");
2630 return -EBUSY;
2631 }
2632
2633 wl_sta = (struct wl1271_station *)sta->drv_priv;
2634
2635 __set_bit(id, wl->ap_hlid_map);
2636 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2637 *hlid = wl_sta->hlid;
2638 return 0;
2639}
2640
2641static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2642{
2643 int id = hlid - WL1271_AP_STA_HLID_START;
2644
2645 __clear_bit(id, wl->ap_hlid_map);
2646}
2647
2648static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2649 struct ieee80211_vif *vif,
2650 struct ieee80211_sta *sta)
2651{
2652 struct wl1271 *wl = hw->priv;
2653 int ret = 0;
2654 u8 hlid;
2655
2656 mutex_lock(&wl->mutex);
2657
2658 if (unlikely(wl->state == WL1271_STATE_OFF))
2659 goto out;
2660
2661 if (wl->bss_type != BSS_TYPE_AP_BSS)
2662 goto out;
2663
2664 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2665
2666 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2667 if (ret < 0)
2668 goto out;
2669
2670 ret = wl1271_ps_elp_wakeup(wl, false);
2671 if (ret < 0)
2672 goto out;
2673
2674 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2675 if (ret < 0)
2676 goto out_sleep;
2677
2678out_sleep:
2679 wl1271_ps_elp_sleep(wl);
2680
2681out:
2682 mutex_unlock(&wl->mutex);
2683 return ret;
2684}
2685
2686static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2687 struct ieee80211_vif *vif,
2688 struct ieee80211_sta *sta)
2689{
2690 struct wl1271 *wl = hw->priv;
2691 struct wl1271_station *wl_sta;
2692 int ret = 0, id;
2693
2694 mutex_lock(&wl->mutex);
2695
2696 if (unlikely(wl->state == WL1271_STATE_OFF))
2697 goto out;
2698
2699 if (wl->bss_type != BSS_TYPE_AP_BSS)
2700 goto out;
2701
2702 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2703
2704 wl_sta = (struct wl1271_station *)sta->drv_priv;
2705 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2706 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2707 goto out;
2708
2709 ret = wl1271_ps_elp_wakeup(wl, false);
2710 if (ret < 0)
2711 goto out;
2712
2713 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2714 if (ret < 0)
2715 goto out_sleep;
2716
2717 wl1271_free_hlid(wl, wl_sta->hlid);
2718
2719out_sleep:
2720 wl1271_ps_elp_sleep(wl);
2721
2722out:
2723 mutex_unlock(&wl->mutex);
2724 return ret;
2725}
2726
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002727int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2728 enum ieee80211_ampdu_mlme_action action,
2729 struct ieee80211_sta *sta, u16 tid, u16 *ssn)
2730{
2731 struct wl1271 *wl = hw->priv;
2732 int ret;
2733
2734 mutex_lock(&wl->mutex);
2735
2736 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2737 ret = -EAGAIN;
2738 goto out;
2739 }
2740
2741 ret = wl1271_ps_elp_wakeup(wl, false);
2742 if (ret < 0)
2743 goto out;
2744
2745 switch (action) {
2746 case IEEE80211_AMPDU_RX_START:
2747 if (wl->ba_support) {
2748 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2749 true);
2750 if (!ret)
2751 wl->ba_rx_bitmap |= BIT(tid);
2752 } else {
2753 ret = -ENOTSUPP;
2754 }
2755 break;
2756
2757 case IEEE80211_AMPDU_RX_STOP:
2758 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2759 if (!ret)
2760 wl->ba_rx_bitmap &= ~BIT(tid);
2761 break;
2762
2763 /*
2764 * The BA initiator session management in FW independently.
2765 * Falling break here on purpose for all TX APDU commands.
2766 */
2767 case IEEE80211_AMPDU_TX_START:
2768 case IEEE80211_AMPDU_TX_STOP:
2769 case IEEE80211_AMPDU_TX_OPERATIONAL:
2770 ret = -EINVAL;
2771 break;
2772
2773 default:
2774 wl1271_error("Incorrect ampdu action id=%x\n", action);
2775 ret = -EINVAL;
2776 }
2777
2778 wl1271_ps_elp_sleep(wl);
2779
2780out:
2781 mutex_unlock(&wl->mutex);
2782
2783 return ret;
2784}
2785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002786/* can't be const, mac80211 writes to this */
2787static struct ieee80211_rate wl1271_rates[] = {
2788 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002789 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2790 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002791 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002792 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2793 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002794 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2795 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002796 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2797 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002798 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2799 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002800 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2801 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2803 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002804 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2805 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002806 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002807 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2808 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002810 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2811 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002812 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002813 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2814 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002816 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2817 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002818 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002819 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2820 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002821 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002822 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2823 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002825 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2826 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002827};
2828
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002829/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002830static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002831 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002832 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002833 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2834 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2835 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002836 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002837 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2838 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2839 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002840 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002841 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2842 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2843 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002844 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002845};
2846
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002847/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002848static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002849 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002850 7, /* CONF_HW_RXTX_RATE_MCS7 */
2851 6, /* CONF_HW_RXTX_RATE_MCS6 */
2852 5, /* CONF_HW_RXTX_RATE_MCS5 */
2853 4, /* CONF_HW_RXTX_RATE_MCS4 */
2854 3, /* CONF_HW_RXTX_RATE_MCS3 */
2855 2, /* CONF_HW_RXTX_RATE_MCS2 */
2856 1, /* CONF_HW_RXTX_RATE_MCS1 */
2857 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002858
2859 11, /* CONF_HW_RXTX_RATE_54 */
2860 10, /* CONF_HW_RXTX_RATE_48 */
2861 9, /* CONF_HW_RXTX_RATE_36 */
2862 8, /* CONF_HW_RXTX_RATE_24 */
2863
2864 /* TI-specific rate */
2865 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2866
2867 7, /* CONF_HW_RXTX_RATE_18 */
2868 6, /* CONF_HW_RXTX_RATE_12 */
2869 3, /* CONF_HW_RXTX_RATE_11 */
2870 5, /* CONF_HW_RXTX_RATE_9 */
2871 4, /* CONF_HW_RXTX_RATE_6 */
2872 2, /* CONF_HW_RXTX_RATE_5_5 */
2873 1, /* CONF_HW_RXTX_RATE_2 */
2874 0 /* CONF_HW_RXTX_RATE_1 */
2875};
2876
Shahar Levie8b03a22010-10-13 16:09:39 +02002877/* 11n STA capabilities */
2878#define HW_RX_HIGHEST_RATE 72
2879
Shahar Levi00d20102010-11-08 11:20:10 +00002880#ifdef CONFIG_WL12XX_HT
2881#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002882 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2883 .ht_supported = true, \
2884 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2885 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2886 .mcs = { \
2887 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2888 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2889 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2890 }, \
2891}
Shahar Levi18357852010-10-13 16:09:41 +02002892#else
Shahar Levi00d20102010-11-08 11:20:10 +00002893#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002894 .ht_supported = false, \
2895}
2896#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898/* can't be const, mac80211 writes to this */
2899static struct ieee80211_supported_band wl1271_band_2ghz = {
2900 .channels = wl1271_channels,
2901 .n_channels = ARRAY_SIZE(wl1271_channels),
2902 .bitrates = wl1271_rates,
2903 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002904 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002905};
2906
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002907/* 5 GHz data rates for WL1273 */
2908static struct ieee80211_rate wl1271_rates_5ghz[] = {
2909 { .bitrate = 60,
2910 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2911 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2912 { .bitrate = 90,
2913 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2914 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2915 { .bitrate = 120,
2916 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2917 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2918 { .bitrate = 180,
2919 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2920 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2921 { .bitrate = 240,
2922 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2923 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2924 { .bitrate = 360,
2925 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2926 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2927 { .bitrate = 480,
2928 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2929 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2930 { .bitrate = 540,
2931 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2932 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2933};
2934
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002935/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002936static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002937 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002938 { .hw_value = 8, .center_freq = 5040},
2939 { .hw_value = 9, .center_freq = 5045},
2940 { .hw_value = 11, .center_freq = 5055},
2941 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002942 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002943 { .hw_value = 34, .center_freq = 5170},
2944 { .hw_value = 36, .center_freq = 5180},
2945 { .hw_value = 38, .center_freq = 5190},
2946 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002947 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002948 { .hw_value = 44, .center_freq = 5220},
2949 { .hw_value = 46, .center_freq = 5230},
2950 { .hw_value = 48, .center_freq = 5240},
2951 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002952 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002953 { .hw_value = 60, .center_freq = 5300},
2954 { .hw_value = 64, .center_freq = 5320},
2955 { .hw_value = 100, .center_freq = 5500},
2956 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002957 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002958 { .hw_value = 112, .center_freq = 5560},
2959 { .hw_value = 116, .center_freq = 5580},
2960 { .hw_value = 120, .center_freq = 5600},
2961 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002962 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002963 { .hw_value = 132, .center_freq = 5660},
2964 { .hw_value = 136, .center_freq = 5680},
2965 { .hw_value = 140, .center_freq = 5700},
2966 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002967 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002968 { .hw_value = 157, .center_freq = 5785},
2969 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002970 { .hw_value = 165, .center_freq = 5825},
2971};
2972
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002973/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002974static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002975 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002976 7, /* CONF_HW_RXTX_RATE_MCS7 */
2977 6, /* CONF_HW_RXTX_RATE_MCS6 */
2978 5, /* CONF_HW_RXTX_RATE_MCS5 */
2979 4, /* CONF_HW_RXTX_RATE_MCS4 */
2980 3, /* CONF_HW_RXTX_RATE_MCS3 */
2981 2, /* CONF_HW_RXTX_RATE_MCS2 */
2982 1, /* CONF_HW_RXTX_RATE_MCS1 */
2983 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002984
2985 7, /* CONF_HW_RXTX_RATE_54 */
2986 6, /* CONF_HW_RXTX_RATE_48 */
2987 5, /* CONF_HW_RXTX_RATE_36 */
2988 4, /* CONF_HW_RXTX_RATE_24 */
2989
2990 /* TI-specific rate */
2991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2992
2993 3, /* CONF_HW_RXTX_RATE_18 */
2994 2, /* CONF_HW_RXTX_RATE_12 */
2995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2996 1, /* CONF_HW_RXTX_RATE_9 */
2997 0, /* CONF_HW_RXTX_RATE_6 */
2998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3000 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3001};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003002
3003static struct ieee80211_supported_band wl1271_band_5ghz = {
3004 .channels = wl1271_channels_5ghz,
3005 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3006 .bitrates = wl1271_rates_5ghz,
3007 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003008 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003009};
3010
Tobias Klausera0ea9492010-05-20 10:38:11 +02003011static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003012 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3013 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3014};
3015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003016static const struct ieee80211_ops wl1271_ops = {
3017 .start = wl1271_op_start,
3018 .stop = wl1271_op_stop,
3019 .add_interface = wl1271_op_add_interface,
3020 .remove_interface = wl1271_op_remove_interface,
3021 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003022 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 .configure_filter = wl1271_op_configure_filter,
3024 .tx = wl1271_op_tx,
3025 .set_key = wl1271_op_set_key,
3026 .hw_scan = wl1271_op_hw_scan,
3027 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003028 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003030 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003031 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003032 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003033 .sta_add = wl1271_op_sta_add,
3034 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003035 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003036 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037};
3038
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003039
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003040u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003041{
3042 u8 idx;
3043
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003044 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003045
3046 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3047 wl1271_error("Illegal RX rate from HW: %d", rate);
3048 return 0;
3049 }
3050
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003051 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003052 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3053 wl1271_error("Unsupported RX rate from HW: %d", rate);
3054 return 0;
3055 }
3056
3057 return idx;
3058}
3059
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003060static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3061 struct device_attribute *attr,
3062 char *buf)
3063{
3064 struct wl1271 *wl = dev_get_drvdata(dev);
3065 ssize_t len;
3066
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003067 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003068
3069 mutex_lock(&wl->mutex);
3070 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3071 wl->sg_enabled);
3072 mutex_unlock(&wl->mutex);
3073
3074 return len;
3075
3076}
3077
3078static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3079 struct device_attribute *attr,
3080 const char *buf, size_t count)
3081{
3082 struct wl1271 *wl = dev_get_drvdata(dev);
3083 unsigned long res;
3084 int ret;
3085
3086 ret = strict_strtoul(buf, 10, &res);
3087
3088 if (ret < 0) {
3089 wl1271_warning("incorrect value written to bt_coex_mode");
3090 return count;
3091 }
3092
3093 mutex_lock(&wl->mutex);
3094
3095 res = !!res;
3096
3097 if (res == wl->sg_enabled)
3098 goto out;
3099
3100 wl->sg_enabled = res;
3101
3102 if (wl->state == WL1271_STATE_OFF)
3103 goto out;
3104
3105 ret = wl1271_ps_elp_wakeup(wl, false);
3106 if (ret < 0)
3107 goto out;
3108
3109 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3110 wl1271_ps_elp_sleep(wl);
3111
3112 out:
3113 mutex_unlock(&wl->mutex);
3114 return count;
3115}
3116
3117static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3118 wl1271_sysfs_show_bt_coex_state,
3119 wl1271_sysfs_store_bt_coex_state);
3120
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003121static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3122 struct device_attribute *attr,
3123 char *buf)
3124{
3125 struct wl1271 *wl = dev_get_drvdata(dev);
3126 ssize_t len;
3127
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003128 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003129
3130 mutex_lock(&wl->mutex);
3131 if (wl->hw_pg_ver >= 0)
3132 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3133 else
3134 len = snprintf(buf, len, "n/a\n");
3135 mutex_unlock(&wl->mutex);
3136
3137 return len;
3138}
3139
3140static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3141 wl1271_sysfs_show_hw_pg_ver, NULL);
3142
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003143int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003144{
3145 int ret;
3146
3147 if (wl->mac80211_registered)
3148 return 0;
3149
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003150 ret = wl1271_fetch_nvs(wl);
3151 if (ret == 0) {
3152 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3153
3154 wl->mac_addr[0] = nvs_ptr[11];
3155 wl->mac_addr[1] = nvs_ptr[10];
3156 wl->mac_addr[2] = nvs_ptr[6];
3157 wl->mac_addr[3] = nvs_ptr[5];
3158 wl->mac_addr[4] = nvs_ptr[4];
3159 wl->mac_addr[5] = nvs_ptr[3];
3160 }
3161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3163
3164 ret = ieee80211_register_hw(wl->hw);
3165 if (ret < 0) {
3166 wl1271_error("unable to register mac80211 hw: %d", ret);
3167 return ret;
3168 }
3169
3170 wl->mac80211_registered = true;
3171
Eliad Pellerd60080a2010-11-24 12:53:16 +02003172 wl1271_debugfs_init(wl);
3173
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003174 register_netdevice_notifier(&wl1271_dev_notifier);
3175
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003176 wl1271_notice("loaded");
3177
3178 return 0;
3179}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003180EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003181
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003182void wl1271_unregister_hw(struct wl1271 *wl)
3183{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003184 if (wl->state == WL1271_STATE_PLT)
3185 __wl1271_plt_stop(wl);
3186
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003187 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003188 ieee80211_unregister_hw(wl->hw);
3189 wl->mac80211_registered = false;
3190
3191}
3192EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3193
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003194int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003195{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003196 static const u32 cipher_suites[] = {
3197 WLAN_CIPHER_SUITE_WEP40,
3198 WLAN_CIPHER_SUITE_WEP104,
3199 WLAN_CIPHER_SUITE_TKIP,
3200 WLAN_CIPHER_SUITE_CCMP,
3201 WL1271_CIPHER_SUITE_GEM,
3202 };
3203
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003204 /* The tx descriptor buffer and the TKIP space. */
3205 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3206 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003207
3208 /* unit us */
3209 /* FIXME: find a proper value */
3210 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003211 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212
3213 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003214 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003215 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003216 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003217 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003218 IEEE80211_HW_CONNECTION_MONITOR |
3219 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003221 wl->hw->wiphy->cipher_suites = cipher_suites;
3222 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3223
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003224 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003225 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003227 /*
3228 * Maximum length of elements in scanning probe request templates
3229 * should be the maximum length possible for a template, without
3230 * the IEEE80211 header of the template
3231 */
3232 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3233 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003234
3235 /*
3236 * We keep local copies of the band structs because we need to
3237 * modify them on a per-device basis.
3238 */
3239 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3240 sizeof(wl1271_band_2ghz));
3241 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3242 sizeof(wl1271_band_5ghz));
3243
3244 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3245 &wl->bands[IEEE80211_BAND_2GHZ];
3246 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3247 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003248
Kalle Valo12bd8942010-03-18 12:26:33 +02003249 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003250 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003251
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003252 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3253
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003254 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003256 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3257
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003258 wl->hw->max_rx_aggregation_subframes = 8;
3259
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003260 return 0;
3261}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003262EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003263
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003265
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003266struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003267{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003269 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003270 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003271 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003272 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003273
3274 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3275 if (!hw) {
3276 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003277 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003278 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003279 }
3280
Julia Lawall929ebd32010-05-15 23:16:39 +02003281 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003282 if (!plat_dev) {
3283 wl1271_error("could not allocate platform_device");
3284 ret = -ENOMEM;
3285 goto err_plat_alloc;
3286 }
3287
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003288 wl = hw->priv;
3289 memset(wl, 0, sizeof(*wl));
3290
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003291 INIT_LIST_HEAD(&wl->list);
3292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003293 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003294 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003295
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003296 for (i = 0; i < NUM_TX_QUEUES; i++)
3297 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003298
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003299 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003300 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003301 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3302 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3303 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3304 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003306 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003307 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003309 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3310 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003311 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003312 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003313 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003314 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003315 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3316 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003317 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003318 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003319 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003320 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003321 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003322 wl->bss_type = MAX_BSS_TYPE;
3323 wl->set_bss_type = MAX_BSS_TYPE;
3324 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003326 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003327 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328 wl->tx_frames[i] = NULL;
3329
3330 spin_lock_init(&wl->wl_lock);
3331
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003332 wl->state = WL1271_STATE_OFF;
3333 mutex_init(&wl->mutex);
3334
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003335 /* Apply default driver configuration. */
3336 wl1271_conf_init(wl);
3337
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003338 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3339 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3340 if (!wl->aggr_buf) {
3341 ret = -ENOMEM;
3342 goto err_hw;
3343 }
3344
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003345 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003346 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003347 if (ret) {
3348 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003349 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003350 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003351 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003352
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003353 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003354 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003355 if (ret < 0) {
3356 wl1271_error("failed to create sysfs file bt_coex_state");
3357 goto err_platform;
3358 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003359
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003360 /* Create sysfs file to get HW PG version */
3361 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3362 if (ret < 0) {
3363 wl1271_error("failed to create sysfs file hw_pg_ver");
3364 goto err_bt_coex_state;
3365 }
3366
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003367 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003368
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003369err_bt_coex_state:
3370 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3371
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003372err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003373 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003374
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003375err_aggr:
3376 free_pages((unsigned long)wl->aggr_buf, order);
3377
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003378err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003379 wl1271_debugfs_exit(wl);
3380 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003381
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003382err_plat_alloc:
3383 ieee80211_free_hw(hw);
3384
3385err_hw_alloc:
3386
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003387 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003388}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003389EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003390
3391int wl1271_free_hw(struct wl1271 *wl)
3392{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003393 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003394 free_pages((unsigned long)wl->aggr_buf,
3395 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003396 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003397
3398 wl1271_debugfs_exit(wl);
3399
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003400 vfree(wl->fw);
3401 wl->fw = NULL;
3402 kfree(wl->nvs);
3403 wl->nvs = NULL;
3404
3405 kfree(wl->fw_status);
3406 kfree(wl->tx_res_if);
3407
3408 ieee80211_free_hw(wl->hw);
3409
3410 return 0;
3411}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003412EXPORT_SYMBOL_GPL(wl1271_free_hw);
3413
Guy Eilam491bbd62011-01-12 10:33:29 +01003414u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003415EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003416module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003417MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3418
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003419MODULE_LICENSE("GPL");
3420MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3421MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");