blob: 522bb09c953524e76478730530b6de367376bb8f [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
Eliad Pelleree608332011-02-02 09:59:34 +0200259 .psm_exit_retries = 255,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200260 .psm_entry_nullfunc_retries = 3,
261 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300262 .keep_alive_interval = 55000,
263 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200265 .itrim = {
266 .enable = false,
267 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200268 },
269 .pm_config = {
270 .host_clk_settling_time = 5000,
271 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300272 },
273 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300274 .trigger_pacing = 1,
275 .avg_weight_rssi_beacon = 20,
276 .avg_weight_rssi_data = 10,
277 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100278 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200279 },
280 .scan = {
281 .min_dwell_time_active = 7500,
282 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100283 .min_dwell_time_passive = 100000,
284 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200285 .num_probe_reqs = 2,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
300 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300301};
302
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200303static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200304static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200305
306
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200307static void wl1271_device_release(struct device *dev)
308{
309
310}
311
312static struct platform_device wl1271_device = {
313 .name = "wl1271",
314 .id = -1,
315
316 /* device model insists to have a release function */
317 .dev = {
318 .release = wl1271_device_release,
319 },
320};
321
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300322static LIST_HEAD(wl_list);
323
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300324static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
325 void *arg)
326{
327 struct net_device *dev = arg;
328 struct wireless_dev *wdev;
329 struct wiphy *wiphy;
330 struct ieee80211_hw *hw;
331 struct wl1271 *wl;
332 struct wl1271 *wl_temp;
333 int ret = 0;
334
335 /* Check that this notification is for us. */
336 if (what != NETDEV_CHANGE)
337 return NOTIFY_DONE;
338
339 wdev = dev->ieee80211_ptr;
340 if (wdev == NULL)
341 return NOTIFY_DONE;
342
343 wiphy = wdev->wiphy;
344 if (wiphy == NULL)
345 return NOTIFY_DONE;
346
347 hw = wiphy_priv(wiphy);
348 if (hw == NULL)
349 return NOTIFY_DONE;
350
351 wl_temp = hw->priv;
352 list_for_each_entry(wl, &wl_list, list) {
353 if (wl == wl_temp)
354 break;
355 }
356 if (wl != wl_temp)
357 return NOTIFY_DONE;
358
359 mutex_lock(&wl->mutex);
360
361 if (wl->state == WL1271_STATE_OFF)
362 goto out;
363
364 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
365 goto out;
366
367 ret = wl1271_ps_elp_wakeup(wl, false);
368 if (ret < 0)
369 goto out;
370
371 if ((dev->operstate == IF_OPER_UP) &&
372 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
373 wl1271_cmd_set_sta_state(wl);
374 wl1271_info("Association completed.");
375 }
376
377 wl1271_ps_elp_sleep(wl);
378
379out:
380 mutex_unlock(&wl->mutex);
381
382 return NOTIFY_OK;
383}
384
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100385static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200386 struct regulatory_request *request)
387{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100388 struct ieee80211_supported_band *band;
389 struct ieee80211_channel *ch;
390 int i;
391
392 band = wiphy->bands[IEEE80211_BAND_5GHZ];
393 for (i = 0; i < band->n_channels; i++) {
394 ch = &band->channels[i];
395 if (ch->flags & IEEE80211_CHAN_DISABLED)
396 continue;
397
398 if (ch->flags & IEEE80211_CHAN_RADAR)
399 ch->flags |= IEEE80211_CHAN_NO_IBSS |
400 IEEE80211_CHAN_PASSIVE_SCAN;
401
402 }
403
404 return 0;
405}
406
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300407static void wl1271_conf_init(struct wl1271 *wl)
408{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300409
410 /*
411 * This function applies the default configuration to the driver. This
412 * function is invoked upon driver load (spi probe.)
413 *
414 * The configuration is stored in a run-time structure in order to
415 * facilitate for run-time adjustment of any of the parameters. Making
416 * changes to the configuration structure will apply the new values on
417 * the next interface up (wl1271_op_start.)
418 */
419
420 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300421 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300422}
423
424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425static int wl1271_plt_init(struct wl1271 *wl)
426{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200427 struct conf_tx_ac_category *conf_ac;
428 struct conf_tx_tid *conf_tid;
429 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200431 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200432 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200433 return ret;
434
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200435 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200436 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200437 return ret;
438
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200439 ret = wl1271_cmd_ext_radio_parms(wl);
440 if (ret < 0)
441 return ret;
442
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200443 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200444 if (ret < 0)
445 return ret;
446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447 ret = wl1271_acx_init_mem_config(wl);
448 if (ret < 0)
449 return ret;
450
Luciano Coelho12419cc2010-02-18 13:25:44 +0200451 /* PHY layer config */
452 ret = wl1271_init_phy_config(wl);
453 if (ret < 0)
454 goto out_free_memmap;
455
456 ret = wl1271_acx_dco_itrim_params(wl);
457 if (ret < 0)
458 goto out_free_memmap;
459
460 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200461 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200462 if (ret < 0)
463 goto out_free_memmap;
464
465 /* Bluetooth WLAN coexistence */
466 ret = wl1271_init_pta(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Energy detection */
471 ret = wl1271_init_energy_detection(wl);
472 if (ret < 0)
473 goto out_free_memmap;
474
475 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100476 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200477 if (ret < 0)
478 goto out_free_memmap;
479
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200480 /* Default TID/AC configuration */
481 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200482 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200483 conf_ac = &wl->conf.tx.ac_conf[i];
484 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
485 conf_ac->cw_max, conf_ac->aifsn,
486 conf_ac->tx_op_limit);
487 if (ret < 0)
488 goto out_free_memmap;
489
Luciano Coelho12419cc2010-02-18 13:25:44 +0200490 conf_tid = &wl->conf.tx.tid_conf[i];
491 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
492 conf_tid->channel_type,
493 conf_tid->tsid,
494 conf_tid->ps_scheme,
495 conf_tid->ack_policy,
496 conf_tid->apsd_conf[0],
497 conf_tid->apsd_conf[1]);
498 if (ret < 0)
499 goto out_free_memmap;
500 }
501
Luciano Coelho12419cc2010-02-18 13:25:44 +0200502 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200503 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200505 goto out_free_memmap;
506
507 /* Configure for CAM power saving (ie. always active) */
508 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
509 if (ret < 0)
510 goto out_free_memmap;
511
512 /* configure PM */
513 ret = wl1271_acx_pm_config(wl);
514 if (ret < 0)
515 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300516
517 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200518
519 out_free_memmap:
520 kfree(wl->target_mem_map);
521 wl->target_mem_map = NULL;
522
523 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524}
525
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300526static void wl1271_fw_status(struct wl1271 *wl,
527 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200529 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530 u32 total = 0;
531 int i;
532
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200533 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300534
535 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
536 "drv_rx_counter = %d, tx_results_counter = %d)",
537 status->intr,
538 status->fw_rx_counter,
539 status->drv_rx_counter,
540 status->tx_results_counter);
541
542 /* update number of available TX blocks */
543 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300544 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
545 wl->tx_blocks_freed[i];
546
547 wl->tx_blocks_freed[i] =
548 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300549 wl->tx_blocks_available += cnt;
550 total += cnt;
551 }
552
Ido Yariva5225502010-10-12 14:49:10 +0200553 /* if more blocks are available now, tx work can be scheduled */
554 if (total)
555 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556
557 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200558 getnstimeofday(&ts);
559 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
560 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561}
562
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200563#define WL1271_IRQ_MAX_LOOPS 10
564
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300565static void wl1271_irq_work(struct work_struct *work)
566{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300567 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300568 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200569 int loopcount = WL1271_IRQ_MAX_LOOPS;
570 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300571 struct wl1271 *wl =
572 container_of(work, struct wl1271, irq_work);
573
574 mutex_lock(&wl->mutex);
575
576 wl1271_debug(DEBUG_IRQ, "IRQ work");
577
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200578 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 goto out;
580
581 ret = wl1271_ps_elp_wakeup(wl, true);
582 if (ret < 0)
583 goto out;
584
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200585 spin_lock_irqsave(&wl->wl_lock, flags);
586 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
587 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
588 spin_unlock_irqrestore(&wl->wl_lock, flags);
589 loopcount--;
590
591 wl1271_fw_status(wl, wl->fw_status);
592 intr = le32_to_cpu(wl->fw_status->intr);
593 if (!intr) {
594 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200595 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200596 continue;
597 }
598
599 intr &= WL1271_INTR_MASK;
600
Eliad Pellerccc83b02010-10-27 14:09:57 +0200601 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
602 wl1271_error("watchdog interrupt received! "
603 "starting recovery.");
604 ieee80211_queue_work(wl->hw, &wl->recovery_work);
605
606 /* restarting the chip. ignore any other interrupt. */
607 goto out;
608 }
609
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200610 if (intr & WL1271_ACX_INTR_DATA) {
611 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
612
613 /* check for tx results */
614 if (wl->fw_status->tx_results_counter !=
615 (wl->tx_results_count & 0xff))
616 wl1271_tx_complete(wl);
617
Ido Yariva5225502010-10-12 14:49:10 +0200618 /* Check if any tx blocks were freed */
619 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200620 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200621 /*
622 * In order to avoid starvation of the TX path,
623 * call the work function directly.
624 */
625 wl1271_tx_work_locked(wl);
626 }
627
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200628 wl1271_rx(wl, wl->fw_status);
629 }
630
631 if (intr & WL1271_ACX_INTR_EVENT_A) {
632 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
633 wl1271_event_handle(wl, 0);
634 }
635
636 if (intr & WL1271_ACX_INTR_EVENT_B) {
637 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
638 wl1271_event_handle(wl, 1);
639 }
640
641 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
642 wl1271_debug(DEBUG_IRQ,
643 "WL1271_ACX_INTR_INIT_COMPLETE");
644
645 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
646 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
647
648 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649 }
650
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200651 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
652 ieee80211_queue_work(wl->hw, &wl->irq_work);
653 else
654 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
655 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300657 wl1271_ps_elp_sleep(wl);
658
659out:
660 mutex_unlock(&wl->mutex);
661}
662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663static int wl1271_fetch_firmware(struct wl1271 *wl)
664{
665 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200666 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 int ret;
668
Arik Nemtsov166d5042010-10-16 21:44:57 +0200669 switch (wl->bss_type) {
670 case BSS_TYPE_AP_BSS:
671 fw_name = WL1271_AP_FW_NAME;
672 break;
673 case BSS_TYPE_IBSS:
674 case BSS_TYPE_STA_BSS:
675 fw_name = WL1271_FW_NAME;
676 break;
677 default:
678 wl1271_error("no compatible firmware for bss_type %d",
679 wl->bss_type);
680 return -EINVAL;
681 }
682
683 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
684
685 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686
687 if (ret < 0) {
688 wl1271_error("could not get firmware: %d", ret);
689 return ret;
690 }
691
692 if (fw->size % 4) {
693 wl1271_error("firmware size is not multiple of 32 bits: %zu",
694 fw->size);
695 ret = -EILSEQ;
696 goto out;
697 }
698
Arik Nemtsov166d5042010-10-16 21:44:57 +0200699 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300701 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702
703 if (!wl->fw) {
704 wl1271_error("could not allocate memory for the firmware");
705 ret = -ENOMEM;
706 goto out;
707 }
708
709 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200710 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711 ret = 0;
712
713out:
714 release_firmware(fw);
715
716 return ret;
717}
718
719static int wl1271_fetch_nvs(struct wl1271 *wl)
720{
721 const struct firmware *fw;
722 int ret;
723
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200724 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725
726 if (ret < 0) {
727 wl1271_error("could not get nvs file: %d", ret);
728 return ret;
729 }
730
Julia Lawall929ebd32010-05-15 23:16:39 +0200731 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732
733 if (!wl->nvs) {
734 wl1271_error("could not allocate memory for the nvs file");
735 ret = -ENOMEM;
736 goto out;
737 }
738
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200739 wl->nvs_len = fw->size;
740
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741out:
742 release_firmware(fw);
743
744 return ret;
745}
746
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200747static void wl1271_recovery_work(struct work_struct *work)
748{
749 struct wl1271 *wl =
750 container_of(work, struct wl1271, recovery_work);
751
752 mutex_lock(&wl->mutex);
753
754 if (wl->state != WL1271_STATE_ON)
755 goto out;
756
757 wl1271_info("Hardware recovery in progress.");
758
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200759 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
760 ieee80211_connection_loss(wl->vif);
761
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200762 /* reboot the chipset */
763 __wl1271_op_remove_interface(wl);
764 ieee80211_restart_hw(wl->hw);
765
766out:
767 mutex_unlock(&wl->mutex);
768}
769
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770static void wl1271_fw_wakeup(struct wl1271 *wl)
771{
772 u32 elp_reg;
773
774 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300775 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300776}
777
778static int wl1271_setup(struct wl1271 *wl)
779{
780 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
781 if (!wl->fw_status)
782 return -ENOMEM;
783
784 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
785 if (!wl->tx_res_if) {
786 kfree(wl->fw_status);
787 return -ENOMEM;
788 }
789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 return 0;
791}
792
793static int wl1271_chip_wakeup(struct wl1271 *wl)
794{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300795 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796 int ret = 0;
797
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +0200798 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200799 ret = wl1271_power_on(wl);
800 if (ret < 0)
801 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200803 wl1271_io_reset(wl);
804 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805
806 /* We don't need a real memory partition here, because we only want
807 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300808 memset(&partition, 0, sizeof(partition));
809 partition.reg.start = REGISTERS_BASE;
810 partition.reg.size = REGISTERS_DOWN_SIZE;
811 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812
813 /* ELP module wake up */
814 wl1271_fw_wakeup(wl);
815
816 /* whal_FwCtrl_BootSm() */
817
818 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200819 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820
821 /* 1. check if chip id is valid */
822
823 switch (wl->chip.id) {
824 case CHIP_ID_1271_PG10:
825 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
826 wl->chip.id);
827
828 ret = wl1271_setup(wl);
829 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200830 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831 break;
832 case CHIP_ID_1271_PG20:
833 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
834 wl->chip.id);
835
836 ret = wl1271_setup(wl);
837 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200838 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 break;
840 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200841 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200843 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844 }
845
Arik Nemtsov166d5042010-10-16 21:44:57 +0200846 /* Make sure the firmware type matches the BSS type */
847 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848 ret = wl1271_fetch_firmware(wl);
849 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200850 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851 }
852
853 /* No NVS from netlink, try to get it from the filesystem */
854 if (wl->nvs == NULL) {
855 ret = wl1271_fetch_nvs(wl);
856 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200857 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300858 }
859
860out:
861 return ret;
862}
863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864int wl1271_plt_start(struct wl1271 *wl)
865{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200866 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
868
869 mutex_lock(&wl->mutex);
870
871 wl1271_notice("power up");
872
873 if (wl->state != WL1271_STATE_OFF) {
874 wl1271_error("cannot go into PLT state because not "
875 "in off state: %d", wl->state);
876 ret = -EBUSY;
877 goto out;
878 }
879
Arik Nemtsov166d5042010-10-16 21:44:57 +0200880 wl->bss_type = BSS_TYPE_STA_BSS;
881
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200882 while (retries) {
883 retries--;
884 ret = wl1271_chip_wakeup(wl);
885 if (ret < 0)
886 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200888 ret = wl1271_boot(wl);
889 if (ret < 0)
890 goto power_off;
891
892 ret = wl1271_plt_init(wl);
893 if (ret < 0)
894 goto irq_disable;
895
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200896 wl->state = WL1271_STATE_PLT;
897 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100898 wl->chip.fw_ver_str);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 goto out;
900
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200901irq_disable:
902 wl1271_disable_interrupts(wl);
903 mutex_unlock(&wl->mutex);
904 /* Unlocking the mutex in the middle of handling is
905 inherently unsafe. In this case we deem it safe to do,
906 because we need to let any possibly pending IRQ out of
907 the system (and while we are WL1271_STATE_OFF the IRQ
908 work function will not do anything.) Also, any other
909 possible concurrent operations will fail due to the
910 current state, hence the wl1271 struct should be safe. */
911 cancel_work_sync(&wl->irq_work);
912 mutex_lock(&wl->mutex);
913power_off:
914 wl1271_power_off(wl);
915 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200917 wl1271_error("firmware boot in PLT mode failed despite %d retries",
918 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300919out:
920 mutex_unlock(&wl->mutex);
921
922 return ret;
923}
924
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100925int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926{
927 int ret = 0;
928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929 wl1271_notice("power down");
930
931 if (wl->state != WL1271_STATE_PLT) {
932 wl1271_error("cannot power down because not in PLT "
933 "state: %d", wl->state);
934 ret = -EBUSY;
935 goto out;
936 }
937
938 wl1271_disable_interrupts(wl);
939 wl1271_power_off(wl);
940
941 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300942 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200945 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200946 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100947 mutex_lock(&wl->mutex);
948out:
949 return ret;
950}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200951
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100952int wl1271_plt_stop(struct wl1271 *wl)
953{
954 int ret;
955
956 mutex_lock(&wl->mutex);
957 ret = __wl1271_plt_stop(wl);
958 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959 return ret;
960}
961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300962static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
963{
964 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200965 struct ieee80211_conf *conf = &hw->conf;
966 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
967 struct ieee80211_sta *sta = txinfo->control.sta;
968 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200969 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970
Shahar Levi18357852010-10-13 16:09:41 +0200971 /*
972 * peek into the rates configured in the STA entry.
973 * The rates set after connection stage, The first block only BG sets:
974 * the compare is for bit 0-16 of sta_rate_set. The second block add
975 * HT rates in case of HT supported.
976 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200977 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200978 if (sta &&
979 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200980 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
981 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200982 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
983 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
984 }
Shahar Levi18357852010-10-13 16:09:41 +0200985
Shahar Levi00d20102010-11-08 11:20:10 +0000986#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200987 if (sta &&
988 sta->ht_cap.ht_supported &&
989 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
990 sta->ht_cap.mcs.rx_mask[0])) {
991 /* Clean MCS bits before setting them */
992 wl->sta_rate_set &= HW_BG_RATES_MASK;
993 wl->sta_rate_set |=
994 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
995 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
996 }
997#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200998 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200999 spin_unlock_irqrestore(&wl->wl_lock, flags);
1000
1001 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001002 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1003 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004
1005 /*
1006 * The chip specific setup must run before the first TX packet -
1007 * before that, the tx_work will not be initialized!
1008 */
1009
Ido Yariva5225502010-10-12 14:49:10 +02001010 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1011 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012
1013 /*
1014 * The workqueue is slow to process the tx_queue and we need stop
1015 * the queue here, otherwise the queue will get too long.
1016 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001017 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001018 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001020 spin_lock_irqsave(&wl->wl_lock, flags);
1021 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001022 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001023 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 }
1025
1026 return NETDEV_TX_OK;
1027}
1028
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001029static struct notifier_block wl1271_dev_notifier = {
1030 .notifier_call = wl1271_dev_notify,
1031};
1032
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033static int wl1271_op_start(struct ieee80211_hw *hw)
1034{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001035 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1036
1037 /*
1038 * We have to delay the booting of the hardware because
1039 * we need to know the local MAC address before downloading and
1040 * initializing the firmware. The MAC address cannot be changed
1041 * after boot, and without the proper MAC address, the firmware
1042 * will not function properly.
1043 *
1044 * The MAC address is first known when the corresponding interface
1045 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001046 *
1047 * In addition, we currently have different firmwares for AP and managed
1048 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001049 */
1050
1051 return 0;
1052}
1053
1054static void wl1271_op_stop(struct ieee80211_hw *hw)
1055{
1056 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1057}
1058
1059static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1060 struct ieee80211_vif *vif)
1061{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001063 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001064 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001066 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001068 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1069 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
1071 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001072 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001073 wl1271_debug(DEBUG_MAC80211,
1074 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001075 ret = -EBUSY;
1076 goto out;
1077 }
1078
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001079 switch (vif->type) {
1080 case NL80211_IFTYPE_STATION:
1081 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001082 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001083 break;
1084 case NL80211_IFTYPE_ADHOC:
1085 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001086 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001087 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001088 case NL80211_IFTYPE_AP:
1089 wl->bss_type = BSS_TYPE_AP_BSS;
1090 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001091 default:
1092 ret = -EOPNOTSUPP;
1093 goto out;
1094 }
1095
1096 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097
1098 if (wl->state != WL1271_STATE_OFF) {
1099 wl1271_error("cannot start because not in off state: %d",
1100 wl->state);
1101 ret = -EBUSY;
1102 goto out;
1103 }
1104
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001105 while (retries) {
1106 retries--;
1107 ret = wl1271_chip_wakeup(wl);
1108 if (ret < 0)
1109 goto power_off;
1110
1111 ret = wl1271_boot(wl);
1112 if (ret < 0)
1113 goto power_off;
1114
1115 ret = wl1271_hw_init(wl);
1116 if (ret < 0)
1117 goto irq_disable;
1118
Eliad Peller71125ab2010-10-28 21:46:43 +02001119 booted = true;
1120 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001122irq_disable:
1123 wl1271_disable_interrupts(wl);
1124 mutex_unlock(&wl->mutex);
1125 /* Unlocking the mutex in the middle of handling is
1126 inherently unsafe. In this case we deem it safe to do,
1127 because we need to let any possibly pending IRQ out of
1128 the system (and while we are WL1271_STATE_OFF the IRQ
1129 work function will not do anything.) Also, any other
1130 possible concurrent operations will fail due to the
1131 current state, hence the wl1271 struct should be safe. */
1132 cancel_work_sync(&wl->irq_work);
1133 mutex_lock(&wl->mutex);
1134power_off:
1135 wl1271_power_off(wl);
1136 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137
Eliad Peller71125ab2010-10-28 21:46:43 +02001138 if (!booted) {
1139 wl1271_error("firmware boot failed despite %d retries",
1140 WL1271_BOOT_RETRIES);
1141 goto out;
1142 }
1143
1144 wl->vif = vif;
1145 wl->state = WL1271_STATE_ON;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001146 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001147
1148 /* update hw/fw version info in wiphy struct */
1149 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001150 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001151 sizeof(wiphy->fw_version));
1152
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001153 /*
1154 * Now we know if 11a is supported (info from the NVS), so disable
1155 * 11a channels if not supported
1156 */
1157 if (!wl->enable_11a)
1158 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1159
1160 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1161 wl->enable_11a ? "" : "not ");
1162
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001163out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164 mutex_unlock(&wl->mutex);
1165
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001166 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001167 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001168
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001169 return ret;
1170}
1171
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001172static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174 int i;
1175
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001176 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001177
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001178 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001180 list_del(&wl->list);
1181
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182 WARN_ON(wl->state != WL1271_STATE_ON);
1183
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001184 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001185 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001186 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001187
Luciano Coelho08688d62010-07-08 17:50:07 +03001188 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001189 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1190 kfree(wl->scan.scanned_ch);
1191 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001192 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001193 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194 }
1195
1196 wl->state = WL1271_STATE_OFF;
1197
1198 wl1271_disable_interrupts(wl);
1199
1200 mutex_unlock(&wl->mutex);
1201
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001202 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 cancel_work_sync(&wl->irq_work);
1204 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001205 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001206 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207
1208 mutex_lock(&wl->mutex);
1209
1210 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001211 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 wl1271_power_off(wl);
1213
1214 memset(wl->bssid, 0, ETH_ALEN);
1215 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1216 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001218 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001219 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220
1221 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001222 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1224 wl->tx_blocks_available = 0;
1225 wl->tx_results_count = 0;
1226 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001227 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001228 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 wl->time_offset = 0;
1230 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001231 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1232 wl->sta_rate_set = 0;
1233 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001234 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001235 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001236 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001237 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 for (i = 0; i < NUM_TX_QUEUES; i++)
1240 wl->tx_blocks_freed[i] = 0;
1241
1242 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001243
1244 kfree(wl->fw_status);
1245 wl->fw_status = NULL;
1246 kfree(wl->tx_res_if);
1247 wl->tx_res_if = NULL;
1248 kfree(wl->target_mem_map);
1249 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001250}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001251
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001252static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1253 struct ieee80211_vif *vif)
1254{
1255 struct wl1271 *wl = hw->priv;
1256
1257 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001258 /*
1259 * wl->vif can be null here if someone shuts down the interface
1260 * just when hardware recovery has been started.
1261 */
1262 if (wl->vif) {
1263 WARN_ON(wl->vif != vif);
1264 __wl1271_op_remove_interface(wl);
1265 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001266
Juuso Oikarinen67353292010-11-18 15:19:02 +02001267 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001268 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269}
1270
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001271static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1272{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001273 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001274
1275 /* combine requested filters with current filter config */
1276 filters = wl->filters | filters;
1277
1278 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1279
1280 if (filters & FIF_PROMISC_IN_BSS) {
1281 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1282 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1283 wl->rx_config |= CFG_BSSID_FILTER_EN;
1284 }
1285 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1286 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1287 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1288 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1289 }
1290 if (filters & FIF_OTHER_BSS) {
1291 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1292 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1293 }
1294 if (filters & FIF_CONTROL) {
1295 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1296 wl->rx_filter |= CFG_RX_CTL_EN;
1297 }
1298 if (filters & FIF_FCSFAIL) {
1299 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1300 wl->rx_filter |= CFG_RX_FCS_ERROR;
1301 }
1302}
1303
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001304static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001305{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001306 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001307 /* we need to use a dummy BSSID for now */
1308 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1309 0xad, 0xbe, 0xef };
1310
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001311 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1312
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001313 /* pass through frames from all BSS */
1314 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1315
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001316 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001317 if (ret < 0)
1318 goto out;
1319
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001320 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001321
1322out:
1323 return ret;
1324}
1325
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001326static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001327{
1328 int ret;
1329
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001330 /*
1331 * One of the side effects of the JOIN command is that is clears
1332 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1333 * to a WPA/WPA2 access point will therefore kill the data-path.
1334 * Currently there is no supported scenario for JOIN during
1335 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1336 * must be handled somehow.
1337 *
1338 */
1339 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1340 wl1271_info("JOIN while associated.");
1341
1342 if (set_assoc)
1343 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1344
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001345 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1346 if (ret < 0)
1347 goto out;
1348
1349 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1350
1351 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1352 goto out;
1353
1354 /*
1355 * The join command disable the keep-alive mode, shut down its process,
1356 * and also clear the template config, so we need to reset it all after
1357 * the join. The acx_aid starts the keep-alive process, and the order
1358 * of the commands below is relevant.
1359 */
1360 ret = wl1271_acx_keep_alive_mode(wl, true);
1361 if (ret < 0)
1362 goto out;
1363
1364 ret = wl1271_acx_aid(wl, wl->aid);
1365 if (ret < 0)
1366 goto out;
1367
1368 ret = wl1271_cmd_build_klv_null_data(wl);
1369 if (ret < 0)
1370 goto out;
1371
1372 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1373 ACX_KEEP_ALIVE_TPL_VALID);
1374 if (ret < 0)
1375 goto out;
1376
1377out:
1378 return ret;
1379}
1380
1381static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001382{
1383 int ret;
1384
1385 /* to stop listening to a channel, we disconnect */
1386 ret = wl1271_cmd_disconnect(wl);
1387 if (ret < 0)
1388 goto out;
1389
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001390 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001391 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001392
1393 /* stop filterting packets based on bssid */
1394 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001395
1396out:
1397 return ret;
1398}
1399
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001400static void wl1271_set_band_rate(struct wl1271 *wl)
1401{
1402 if (wl->band == IEEE80211_BAND_2GHZ)
1403 wl->basic_rate_set = wl->conf.tx.basic_rate;
1404 else
1405 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1406}
1407
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001408static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001409{
1410 int ret;
1411
1412 if (idle) {
1413 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1414 ret = wl1271_unjoin(wl);
1415 if (ret < 0)
1416 goto out;
1417 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001418 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001419 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001420 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001421 if (ret < 0)
1422 goto out;
1423 ret = wl1271_acx_keep_alive_config(
1424 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1425 ACX_KEEP_ALIVE_TPL_INVALID);
1426 if (ret < 0)
1427 goto out;
1428 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1429 } else {
1430 /* increment the session counter */
1431 wl->session_counter++;
1432 if (wl->session_counter >= SESSION_COUNTER_MAX)
1433 wl->session_counter = 0;
1434 ret = wl1271_dummy_join(wl);
1435 if (ret < 0)
1436 goto out;
1437 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1438 }
1439
1440out:
1441 return ret;
1442}
1443
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1445{
1446 struct wl1271 *wl = hw->priv;
1447 struct ieee80211_conf *conf = &hw->conf;
1448 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001449 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450
1451 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1452
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001453 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1454 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455 channel,
1456 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001457 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001458 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1459 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001461 /*
1462 * mac80211 will go to idle nearly immediately after transmitting some
1463 * frames, such as the deauth. To make sure those frames reach the air,
1464 * wait here until the TX queue is fully flushed.
1465 */
1466 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1467 (conf->flags & IEEE80211_CONF_IDLE))
1468 wl1271_tx_flush(wl);
1469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 mutex_lock(&wl->mutex);
1471
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001472 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1473 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001474 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001475 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001476
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001477 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1478
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001479 ret = wl1271_ps_elp_wakeup(wl, false);
1480 if (ret < 0)
1481 goto out;
1482
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001483 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001484 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1485 ((wl->band != conf->channel->band) ||
1486 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001487 wl->band = conf->channel->band;
1488 wl->channel = channel;
1489
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001490 if (!is_ap) {
1491 /*
1492 * FIXME: the mac80211 should really provide a fixed
1493 * rate to use here. for now, just use the smallest
1494 * possible rate for the band as a fixed rate for
1495 * association frames and other control messages.
1496 */
1497 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1498 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001499
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001500 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1501 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001502 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001503 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001504 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001505
1506 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1507 ret = wl1271_join(wl, false);
1508 if (ret < 0)
1509 wl1271_warning("cmd join on channel "
1510 "failed %d", ret);
1511 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001512 }
1513 }
1514
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001515 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1516 ret = wl1271_sta_handle_idle(wl,
1517 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001518 if (ret < 0)
1519 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520 }
1521
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001522 /*
1523 * if mac80211 changes the PSM mode, make sure the mode is not
1524 * incorrectly changed after the pspoll failure active window.
1525 */
1526 if (changed & IEEE80211_CONF_CHANGE_PS)
1527 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1528
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001529 if (conf->flags & IEEE80211_CONF_PS &&
1530 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1531 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532
1533 /*
1534 * We enter PSM only if we're already associated.
1535 * If we're not, we'll enter it when joining an SSID,
1536 * through the bss_info_changed() hook.
1537 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001538 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001539 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001540 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001541 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001542 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001544 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001545 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001547 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001549 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001550 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001551 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 }
1553
1554 if (conf->power_level != wl->power_level) {
1555 ret = wl1271_acx_tx_power(wl, conf->power_level);
1556 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001557 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558
1559 wl->power_level = conf->power_level;
1560 }
1561
1562out_sleep:
1563 wl1271_ps_elp_sleep(wl);
1564
1565out:
1566 mutex_unlock(&wl->mutex);
1567
1568 return ret;
1569}
1570
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001571struct wl1271_filter_params {
1572 bool enabled;
1573 int mc_list_length;
1574 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1575};
1576
Jiri Pirko22bedad2010-04-01 21:22:57 +00001577static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1578 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001579{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001580 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001581 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001582 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001583
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001584 if (unlikely(wl->state == WL1271_STATE_OFF))
1585 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001586
Juuso Oikarinen74441132009-10-13 12:47:53 +03001587 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001588 if (!fp) {
1589 wl1271_error("Out of memory setting filters.");
1590 return 0;
1591 }
1592
1593 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001594 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001595 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1596 fp->enabled = false;
1597 } else {
1598 fp->enabled = true;
1599 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001600 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001601 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001602 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001603 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001604 }
1605
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001606 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001607}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001609#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1610 FIF_ALLMULTI | \
1611 FIF_FCSFAIL | \
1612 FIF_BCN_PRBRESP_PROMISC | \
1613 FIF_CONTROL | \
1614 FIF_OTHER_BSS)
1615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1617 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001618 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001620 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001621 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001622 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001623
Arik Nemtsov7d057862010-10-16 19:25:35 +02001624 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1625 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001626
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001627 mutex_lock(&wl->mutex);
1628
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001629 *total &= WL1271_SUPPORTED_FILTERS;
1630 changed &= WL1271_SUPPORTED_FILTERS;
1631
1632 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001633 goto out;
1634
1635 ret = wl1271_ps_elp_wakeup(wl, false);
1636 if (ret < 0)
1637 goto out;
1638
Arik Nemtsov7d057862010-10-16 19:25:35 +02001639 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1640 if (*total & FIF_ALLMULTI)
1641 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1642 else if (fp)
1643 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1644 fp->mc_list,
1645 fp->mc_list_length);
1646 if (ret < 0)
1647 goto out_sleep;
1648 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001650 /* determine, whether supported filter values have changed */
1651 if (changed == 0)
1652 goto out_sleep;
1653
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001654 /* configure filters */
1655 wl->filters = *total;
1656 wl1271_configure_filters(wl, 0);
1657
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001658 /* apply configured filters */
1659 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1660 if (ret < 0)
1661 goto out_sleep;
1662
1663out_sleep:
1664 wl1271_ps_elp_sleep(wl);
1665
1666out:
1667 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001668 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001669}
1670
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001671static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1672 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1673 u16 tx_seq_16)
1674{
1675 struct wl1271_ap_key *ap_key;
1676 int i;
1677
1678 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1679
1680 if (key_size > MAX_KEY_SIZE)
1681 return -EINVAL;
1682
1683 /*
1684 * Find next free entry in ap_keys. Also check we are not replacing
1685 * an existing key.
1686 */
1687 for (i = 0; i < MAX_NUM_KEYS; i++) {
1688 if (wl->recorded_ap_keys[i] == NULL)
1689 break;
1690
1691 if (wl->recorded_ap_keys[i]->id == id) {
1692 wl1271_warning("trying to record key replacement");
1693 return -EINVAL;
1694 }
1695 }
1696
1697 if (i == MAX_NUM_KEYS)
1698 return -EBUSY;
1699
1700 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1701 if (!ap_key)
1702 return -ENOMEM;
1703
1704 ap_key->id = id;
1705 ap_key->key_type = key_type;
1706 ap_key->key_size = key_size;
1707 memcpy(ap_key->key, key, key_size);
1708 ap_key->hlid = hlid;
1709 ap_key->tx_seq_32 = tx_seq_32;
1710 ap_key->tx_seq_16 = tx_seq_16;
1711
1712 wl->recorded_ap_keys[i] = ap_key;
1713 return 0;
1714}
1715
1716static void wl1271_free_ap_keys(struct wl1271 *wl)
1717{
1718 int i;
1719
1720 for (i = 0; i < MAX_NUM_KEYS; i++) {
1721 kfree(wl->recorded_ap_keys[i]);
1722 wl->recorded_ap_keys[i] = NULL;
1723 }
1724}
1725
1726static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1727{
1728 int i, ret = 0;
1729 struct wl1271_ap_key *key;
1730 bool wep_key_added = false;
1731
1732 for (i = 0; i < MAX_NUM_KEYS; i++) {
1733 if (wl->recorded_ap_keys[i] == NULL)
1734 break;
1735
1736 key = wl->recorded_ap_keys[i];
1737 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1738 key->id, key->key_type,
1739 key->key_size, key->key,
1740 key->hlid, key->tx_seq_32,
1741 key->tx_seq_16);
1742 if (ret < 0)
1743 goto out;
1744
1745 if (key->key_type == KEY_WEP)
1746 wep_key_added = true;
1747 }
1748
1749 if (wep_key_added) {
1750 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1751 if (ret < 0)
1752 goto out;
1753 }
1754
1755out:
1756 wl1271_free_ap_keys(wl);
1757 return ret;
1758}
1759
1760static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1761 u8 key_size, const u8 *key, u32 tx_seq_32,
1762 u16 tx_seq_16, struct ieee80211_sta *sta)
1763{
1764 int ret;
1765 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1766
1767 if (is_ap) {
1768 struct wl1271_station *wl_sta;
1769 u8 hlid;
1770
1771 if (sta) {
1772 wl_sta = (struct wl1271_station *)sta->drv_priv;
1773 hlid = wl_sta->hlid;
1774 } else {
1775 hlid = WL1271_AP_BROADCAST_HLID;
1776 }
1777
1778 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1779 /*
1780 * We do not support removing keys after AP shutdown.
1781 * Pretend we do to make mac80211 happy.
1782 */
1783 if (action != KEY_ADD_OR_REPLACE)
1784 return 0;
1785
1786 ret = wl1271_record_ap_key(wl, id,
1787 key_type, key_size,
1788 key, hlid, tx_seq_32,
1789 tx_seq_16);
1790 } else {
1791 ret = wl1271_cmd_set_ap_key(wl, action,
1792 id, key_type, key_size,
1793 key, hlid, tx_seq_32,
1794 tx_seq_16);
1795 }
1796
1797 if (ret < 0)
1798 return ret;
1799 } else {
1800 const u8 *addr;
1801 static const u8 bcast_addr[ETH_ALEN] = {
1802 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1803 };
1804
1805 addr = sta ? sta->addr : bcast_addr;
1806
1807 if (is_zero_ether_addr(addr)) {
1808 /* We dont support TX only encryption */
1809 return -EOPNOTSUPP;
1810 }
1811
1812 /* The wl1271 does not allow to remove unicast keys - they
1813 will be cleared automatically on next CMD_JOIN. Ignore the
1814 request silently, as we dont want the mac80211 to emit
1815 an error message. */
1816 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1817 return 0;
1818
1819 ret = wl1271_cmd_set_sta_key(wl, action,
1820 id, key_type, key_size,
1821 key, addr, tx_seq_32,
1822 tx_seq_16);
1823 if (ret < 0)
1824 return ret;
1825
1826 /* the default WEP key needs to be configured at least once */
1827 if (key_type == KEY_WEP) {
1828 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1829 wl->default_key);
1830 if (ret < 0)
1831 return ret;
1832 }
1833 }
1834
1835 return 0;
1836}
1837
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001838static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1839 struct ieee80211_vif *vif,
1840 struct ieee80211_sta *sta,
1841 struct ieee80211_key_conf *key_conf)
1842{
1843 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001845 u32 tx_seq_32 = 0;
1846 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 u8 key_type;
1848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1850
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001851 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001853 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854 key_conf->keylen, key_conf->flags);
1855 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1856
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001857 mutex_lock(&wl->mutex);
1858
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001859 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1860 ret = -EAGAIN;
1861 goto out_unlock;
1862 }
1863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001864 ret = wl1271_ps_elp_wakeup(wl, false);
1865 if (ret < 0)
1866 goto out_unlock;
1867
Johannes Berg97359d12010-08-10 09:46:38 +02001868 switch (key_conf->cipher) {
1869 case WLAN_CIPHER_SUITE_WEP40:
1870 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 key_type = KEY_WEP;
1872
1873 key_conf->hw_key_idx = key_conf->keyidx;
1874 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001875 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001876 key_type = KEY_TKIP;
1877
1878 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001879 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1880 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001881 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001882 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 key_type = KEY_AES;
1884
1885 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001886 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1887 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001889 case WL1271_CIPHER_SUITE_GEM:
1890 key_type = KEY_GEM;
1891 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1892 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1893 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001894 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001895 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896
1897 ret = -EOPNOTSUPP;
1898 goto out_sleep;
1899 }
1900
1901 switch (cmd) {
1902 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001903 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1904 key_conf->keyidx, key_type,
1905 key_conf->keylen, key_conf->key,
1906 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001907 if (ret < 0) {
1908 wl1271_error("Could not add or replace key");
1909 goto out_sleep;
1910 }
1911 break;
1912
1913 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001914 ret = wl1271_set_key(wl, KEY_REMOVE,
1915 key_conf->keyidx, key_type,
1916 key_conf->keylen, key_conf->key,
1917 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001918 if (ret < 0) {
1919 wl1271_error("Could not remove key");
1920 goto out_sleep;
1921 }
1922 break;
1923
1924 default:
1925 wl1271_error("Unsupported key cmd 0x%x", cmd);
1926 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927 break;
1928 }
1929
1930out_sleep:
1931 wl1271_ps_elp_sleep(wl);
1932
1933out_unlock:
1934 mutex_unlock(&wl->mutex);
1935
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 return ret;
1937}
1938
1939static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001940 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 struct cfg80211_scan_request *req)
1942{
1943 struct wl1271 *wl = hw->priv;
1944 int ret;
1945 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001946 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947
1948 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1949
1950 if (req->n_ssids) {
1951 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001952 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 }
1954
1955 mutex_lock(&wl->mutex);
1956
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001957 if (wl->state == WL1271_STATE_OFF) {
1958 /*
1959 * We cannot return -EBUSY here because cfg80211 will expect
1960 * a call to ieee80211_scan_completed if we do - in this case
1961 * there won't be any call.
1962 */
1963 ret = -EAGAIN;
1964 goto out;
1965 }
1966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 ret = wl1271_ps_elp_wakeup(wl, false);
1968 if (ret < 0)
1969 goto out;
1970
Luciano Coelho5924f892010-08-04 03:46:22 +03001971 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972
1973 wl1271_ps_elp_sleep(wl);
1974
1975out:
1976 mutex_unlock(&wl->mutex);
1977
1978 return ret;
1979}
1980
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001981static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1982{
1983 struct wl1271 *wl = hw->priv;
1984 int ret = 0;
1985
1986 mutex_lock(&wl->mutex);
1987
1988 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1989 ret = -EAGAIN;
1990 goto out;
1991 }
1992
1993 ret = wl1271_ps_elp_wakeup(wl, false);
1994 if (ret < 0)
1995 goto out;
1996
1997 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1998 if (ret < 0)
1999 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2000
2001 wl1271_ps_elp_sleep(wl);
2002
2003out:
2004 mutex_unlock(&wl->mutex);
2005
2006 return ret;
2007}
2008
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2010{
2011 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002012 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013
2014 mutex_lock(&wl->mutex);
2015
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002016 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2017 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002018 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002019 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021 ret = wl1271_ps_elp_wakeup(wl, false);
2022 if (ret < 0)
2023 goto out;
2024
2025 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2026 if (ret < 0)
2027 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2028
2029 wl1271_ps_elp_sleep(wl);
2030
2031out:
2032 mutex_unlock(&wl->mutex);
2033
2034 return ret;
2035}
2036
Arik Nemtsove78a2872010-10-16 19:07:21 +02002037static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002038 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002039{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002040 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002041
2042 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002043 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002044 if (ptr[0] == WLAN_EID_SSID) {
2045 wl->ssid_len = ptr[1];
2046 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002047 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002048 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002049 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002050 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002051
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002052 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002053 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002054}
2055
Arik Nemtsove78a2872010-10-16 19:07:21 +02002056static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2057 struct ieee80211_bss_conf *bss_conf,
2058 u32 changed)
2059{
2060 int ret = 0;
2061
2062 if (changed & BSS_CHANGED_ERP_SLOT) {
2063 if (bss_conf->use_short_slot)
2064 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2065 else
2066 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2067 if (ret < 0) {
2068 wl1271_warning("Set slot time failed %d", ret);
2069 goto out;
2070 }
2071 }
2072
2073 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2074 if (bss_conf->use_short_preamble)
2075 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2076 else
2077 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2078 }
2079
2080 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2081 if (bss_conf->use_cts_prot)
2082 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2083 else
2084 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2085 if (ret < 0) {
2086 wl1271_warning("Set ctsprotect failed %d", ret);
2087 goto out;
2088 }
2089 }
2090
2091out:
2092 return ret;
2093}
2094
2095static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2096 struct ieee80211_vif *vif,
2097 struct ieee80211_bss_conf *bss_conf,
2098 u32 changed)
2099{
2100 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2101 int ret = 0;
2102
2103 if ((changed & BSS_CHANGED_BEACON_INT)) {
2104 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2105 bss_conf->beacon_int);
2106
2107 wl->beacon_int = bss_conf->beacon_int;
2108 }
2109
2110 if ((changed & BSS_CHANGED_BEACON)) {
2111 struct ieee80211_hdr *hdr;
2112 int ieoffset = offsetof(struct ieee80211_mgmt,
2113 u.beacon.variable);
2114 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2115 u16 tmpl_id;
2116
2117 if (!beacon)
2118 goto out;
2119
2120 wl1271_debug(DEBUG_MASTER, "beacon updated");
2121
2122 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2123 if (ret < 0) {
2124 dev_kfree_skb(beacon);
2125 goto out;
2126 }
2127 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2128 CMD_TEMPL_BEACON;
2129 ret = wl1271_cmd_template_set(wl, tmpl_id,
2130 beacon->data,
2131 beacon->len, 0,
2132 wl1271_tx_min_rate_get(wl));
2133 if (ret < 0) {
2134 dev_kfree_skb(beacon);
2135 goto out;
2136 }
2137
2138 hdr = (struct ieee80211_hdr *) beacon->data;
2139 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2140 IEEE80211_STYPE_PROBE_RESP);
2141
2142 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2143 CMD_TEMPL_PROBE_RESPONSE;
2144 ret = wl1271_cmd_template_set(wl,
2145 tmpl_id,
2146 beacon->data,
2147 beacon->len, 0,
2148 wl1271_tx_min_rate_get(wl));
2149 dev_kfree_skb(beacon);
2150 if (ret < 0)
2151 goto out;
2152 }
2153
2154out:
2155 return ret;
2156}
2157
2158/* AP mode changes */
2159static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 struct ieee80211_vif *vif,
2161 struct ieee80211_bss_conf *bss_conf,
2162 u32 changed)
2163{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002164 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165
Arik Nemtsove78a2872010-10-16 19:07:21 +02002166 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2167 u32 rates = bss_conf->basic_rates;
2168 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169
Arik Nemtsove78a2872010-10-16 19:07:21 +02002170 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2171 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2172 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2173 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002174
Arik Nemtsove78a2872010-10-16 19:07:21 +02002175 /* update the AP management rate policy with the new rates */
2176 mgmt_rc.enabled_rates = wl->basic_rate_set;
2177 mgmt_rc.long_retry_limit = 10;
2178 mgmt_rc.short_retry_limit = 10;
2179 mgmt_rc.aflags = 0;
2180 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2181 ACX_TX_AP_MODE_MGMT_RATE);
2182 if (ret < 0) {
2183 wl1271_error("AP mgmt policy change failed %d", ret);
2184 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002185 }
2186 }
2187
Arik Nemtsove78a2872010-10-16 19:07:21 +02002188 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2189 if (ret < 0)
2190 goto out;
2191
2192 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2193 if (bss_conf->enable_beacon) {
2194 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2195 ret = wl1271_cmd_start_bss(wl);
2196 if (ret < 0)
2197 goto out;
2198
2199 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2200 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002201
2202 ret = wl1271_ap_init_hwenc(wl);
2203 if (ret < 0)
2204 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002205 }
2206 } else {
2207 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2208 ret = wl1271_cmd_stop_bss(wl);
2209 if (ret < 0)
2210 goto out;
2211
2212 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2213 wl1271_debug(DEBUG_AP, "stopped AP");
2214 }
2215 }
2216 }
2217
2218 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2219 if (ret < 0)
2220 goto out;
2221out:
2222 return;
2223}
2224
2225/* STA/IBSS mode changes */
2226static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2227 struct ieee80211_vif *vif,
2228 struct ieee80211_bss_conf *bss_conf,
2229 u32 changed)
2230{
2231 bool do_join = false, set_assoc = false;
2232 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2233 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002234 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002235
2236 if (is_ibss) {
2237 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2238 changed);
2239 if (ret < 0)
2240 goto out;
2241 }
2242
2243 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2244 do_join = true;
2245
2246 /* Need to update the SSID (for filtering etc) */
2247 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2248 do_join = true;
2249
2250 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002251 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2252 bss_conf->enable_beacon ? "enabled" : "disabled");
2253
2254 if (bss_conf->enable_beacon)
2255 wl->set_bss_type = BSS_TYPE_IBSS;
2256 else
2257 wl->set_bss_type = BSS_TYPE_STA_BSS;
2258 do_join = true;
2259 }
2260
Arik Nemtsove78a2872010-10-16 19:07:21 +02002261 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002262 bool enable = false;
2263 if (bss_conf->cqm_rssi_thold)
2264 enable = true;
2265 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2266 bss_conf->cqm_rssi_thold,
2267 bss_conf->cqm_rssi_hyst);
2268 if (ret < 0)
2269 goto out;
2270 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2271 }
2272
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002273 if ((changed & BSS_CHANGED_BSSID) &&
2274 /*
2275 * Now we know the correct bssid, so we send a new join command
2276 * and enable the BSSID filter
2277 */
2278 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002279 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002280
Eliad Pellerfa287b82010-12-26 09:27:50 +01002281 if (!is_zero_ether_addr(wl->bssid)) {
2282 ret = wl1271_cmd_build_null_data(wl);
2283 if (ret < 0)
2284 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002285
Eliad Pellerfa287b82010-12-26 09:27:50 +01002286 ret = wl1271_build_qos_null_data(wl);
2287 if (ret < 0)
2288 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002289
Eliad Pellerfa287b82010-12-26 09:27:50 +01002290 /* filter out all packets not from this BSSID */
2291 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002292
Eliad Pellerfa287b82010-12-26 09:27:50 +01002293 /* Need to update the BSSID (for filtering etc) */
2294 do_join = true;
2295 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002296 }
2297
Arik Nemtsove78a2872010-10-16 19:07:21 +02002298 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002300 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002301 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002303 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002305 wl->ps_poll_failures = 0;
2306
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002307 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002308 * use basic rates from AP, and determine lowest rate
2309 * to use with control frames.
2310 */
2311 rates = bss_conf->basic_rates;
2312 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2313 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002314 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002315 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002316 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002317 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002318
2319 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002320 * with wl1271, we don't need to update the
2321 * beacon_int and dtim_period, because the firmware
2322 * updates it by itself when the first beacon is
2323 * received after a join.
2324 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002325 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2326 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002329 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002330 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002331 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002332 dev_kfree_skb(wl->probereq);
2333 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2334 ieoffset = offsetof(struct ieee80211_mgmt,
2335 u.probe_req.variable);
2336 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002337
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002338 /* enable the connection monitoring feature */
2339 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342
2343 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002344 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2345 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002346 enum wl1271_cmd_ps_mode mode;
2347
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002348 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002349 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002350 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002351 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002353 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002354 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002355 } else {
2356 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002357 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002358 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002359 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002360
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002361 /* free probe-request template */
2362 dev_kfree_skb(wl->probereq);
2363 wl->probereq = NULL;
2364
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002365 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002366 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002367
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002368 /* revert back to minimum rates for the current band */
2369 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002370 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002371 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002372 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002373 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002374
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002375 /* disable connection monitor features */
2376 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002377
2378 /* Disable the keep-alive feature */
2379 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002380 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002381 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002382
2383 /* restore the bssid filter and go to dummy bssid */
2384 wl1271_unjoin(wl);
2385 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386 }
2387 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002388
Arik Nemtsove78a2872010-10-16 19:07:21 +02002389 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2390 if (ret < 0)
2391 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002392
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002393 rcu_read_lock();
2394 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2395 if (sta) {
2396 /* handle new association with HT and HT information change */
2397 if ((changed & BSS_CHANGED_HT) &&
2398 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2399 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2400 true);
2401 if (ret < 0) {
2402 wl1271_warning("Set ht cap true failed %d",
2403 ret);
2404 rcu_read_unlock();
2405 goto out;
2406 }
Shahar Levi18357852010-10-13 16:09:41 +02002407 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002408 bss_conf->ht_operation_mode);
2409 if (ret < 0) {
2410 wl1271_warning("Set ht information failed %d",
2411 ret);
2412 rcu_read_unlock();
2413 goto out;
2414 }
2415 }
2416 /* handle new association without HT and disassociation */
2417 else if (changed & BSS_CHANGED_ASSOC) {
2418 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2419 false);
2420 if (ret < 0) {
2421 wl1271_warning("Set ht cap false failed %d",
2422 ret);
2423 rcu_read_unlock();
2424 goto out;
2425 }
Shahar Levi18357852010-10-13 16:09:41 +02002426 }
2427 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002428 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002429
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002430 if (changed & BSS_CHANGED_ARP_FILTER) {
2431 __be32 addr = bss_conf->arp_addr_list[0];
2432 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2433
Eliad Pellerc5312772010-12-09 11:31:27 +02002434 if (bss_conf->arp_addr_cnt == 1 &&
2435 bss_conf->arp_filter_enabled) {
2436 /*
2437 * The template should have been configured only upon
2438 * association. however, it seems that the correct ip
2439 * isn't being set (when sending), so we have to
2440 * reconfigure the template upon every ip change.
2441 */
2442 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2443 if (ret < 0) {
2444 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002445 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002446 }
2447
2448 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002449 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002450 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,
Luciano Coelho7c3ee9e2011-01-31 09:41:52 +02002728 enum ieee80211_ampdu_mlme_action action,
2729 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
2730 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01002731{
2732 struct wl1271 *wl = hw->priv;
2733 int ret;
2734
2735 mutex_lock(&wl->mutex);
2736
2737 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2738 ret = -EAGAIN;
2739 goto out;
2740 }
2741
2742 ret = wl1271_ps_elp_wakeup(wl, false);
2743 if (ret < 0)
2744 goto out;
2745
2746 switch (action) {
2747 case IEEE80211_AMPDU_RX_START:
2748 if (wl->ba_support) {
2749 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
2750 true);
2751 if (!ret)
2752 wl->ba_rx_bitmap |= BIT(tid);
2753 } else {
2754 ret = -ENOTSUPP;
2755 }
2756 break;
2757
2758 case IEEE80211_AMPDU_RX_STOP:
2759 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
2760 if (!ret)
2761 wl->ba_rx_bitmap &= ~BIT(tid);
2762 break;
2763
2764 /*
2765 * The BA initiator session management in FW independently.
2766 * Falling break here on purpose for all TX APDU commands.
2767 */
2768 case IEEE80211_AMPDU_TX_START:
2769 case IEEE80211_AMPDU_TX_STOP:
2770 case IEEE80211_AMPDU_TX_OPERATIONAL:
2771 ret = -EINVAL;
2772 break;
2773
2774 default:
2775 wl1271_error("Incorrect ampdu action id=%x\n", action);
2776 ret = -EINVAL;
2777 }
2778
2779 wl1271_ps_elp_sleep(wl);
2780
2781out:
2782 mutex_unlock(&wl->mutex);
2783
2784 return ret;
2785}
2786
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787/* can't be const, mac80211 writes to this */
2788static struct ieee80211_rate wl1271_rates[] = {
2789 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002790 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2791 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002792 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002793 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2794 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002795 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2796 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002797 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2798 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2800 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002801 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2802 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002803 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2804 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002805 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2806 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002807 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002808 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2809 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002810 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002811 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2812 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002813 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002814 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2815 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002816 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002817 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2818 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002819 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002820 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2821 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002822 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002823 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2824 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002826 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2827 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828};
2829
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002830/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002832 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002833 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002834 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2835 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2836 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002837 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002838 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2839 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2840 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002841 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002842 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2843 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2844 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002845 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002846};
2847
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002848/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002849static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002850 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002851 7, /* CONF_HW_RXTX_RATE_MCS7 */
2852 6, /* CONF_HW_RXTX_RATE_MCS6 */
2853 5, /* CONF_HW_RXTX_RATE_MCS5 */
2854 4, /* CONF_HW_RXTX_RATE_MCS4 */
2855 3, /* CONF_HW_RXTX_RATE_MCS3 */
2856 2, /* CONF_HW_RXTX_RATE_MCS2 */
2857 1, /* CONF_HW_RXTX_RATE_MCS1 */
2858 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002859
2860 11, /* CONF_HW_RXTX_RATE_54 */
2861 10, /* CONF_HW_RXTX_RATE_48 */
2862 9, /* CONF_HW_RXTX_RATE_36 */
2863 8, /* CONF_HW_RXTX_RATE_24 */
2864
2865 /* TI-specific rate */
2866 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2867
2868 7, /* CONF_HW_RXTX_RATE_18 */
2869 6, /* CONF_HW_RXTX_RATE_12 */
2870 3, /* CONF_HW_RXTX_RATE_11 */
2871 5, /* CONF_HW_RXTX_RATE_9 */
2872 4, /* CONF_HW_RXTX_RATE_6 */
2873 2, /* CONF_HW_RXTX_RATE_5_5 */
2874 1, /* CONF_HW_RXTX_RATE_2 */
2875 0 /* CONF_HW_RXTX_RATE_1 */
2876};
2877
Shahar Levie8b03a22010-10-13 16:09:39 +02002878/* 11n STA capabilities */
2879#define HW_RX_HIGHEST_RATE 72
2880
Shahar Levi00d20102010-11-08 11:20:10 +00002881#ifdef CONFIG_WL12XX_HT
2882#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002883 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2884 .ht_supported = true, \
2885 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2886 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2887 .mcs = { \
2888 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2889 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2890 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2891 }, \
2892}
Shahar Levi18357852010-10-13 16:09:41 +02002893#else
Shahar Levi00d20102010-11-08 11:20:10 +00002894#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002895 .ht_supported = false, \
2896}
2897#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899/* can't be const, mac80211 writes to this */
2900static struct ieee80211_supported_band wl1271_band_2ghz = {
2901 .channels = wl1271_channels,
2902 .n_channels = ARRAY_SIZE(wl1271_channels),
2903 .bitrates = wl1271_rates,
2904 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002905 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906};
2907
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002908/* 5 GHz data rates for WL1273 */
2909static struct ieee80211_rate wl1271_rates_5ghz[] = {
2910 { .bitrate = 60,
2911 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2912 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2913 { .bitrate = 90,
2914 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2915 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2916 { .bitrate = 120,
2917 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2918 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2919 { .bitrate = 180,
2920 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2921 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2922 { .bitrate = 240,
2923 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2924 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2925 { .bitrate = 360,
2926 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2927 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2928 { .bitrate = 480,
2929 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2930 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2931 { .bitrate = 540,
2932 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2933 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2934};
2935
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002936/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002937static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002938 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002939 { .hw_value = 8, .center_freq = 5040},
2940 { .hw_value = 9, .center_freq = 5045},
2941 { .hw_value = 11, .center_freq = 5055},
2942 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002943 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002944 { .hw_value = 34, .center_freq = 5170},
2945 { .hw_value = 36, .center_freq = 5180},
2946 { .hw_value = 38, .center_freq = 5190},
2947 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002948 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002949 { .hw_value = 44, .center_freq = 5220},
2950 { .hw_value = 46, .center_freq = 5230},
2951 { .hw_value = 48, .center_freq = 5240},
2952 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002953 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002954 { .hw_value = 60, .center_freq = 5300},
2955 { .hw_value = 64, .center_freq = 5320},
2956 { .hw_value = 100, .center_freq = 5500},
2957 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002958 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002959 { .hw_value = 112, .center_freq = 5560},
2960 { .hw_value = 116, .center_freq = 5580},
2961 { .hw_value = 120, .center_freq = 5600},
2962 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002963 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002964 { .hw_value = 132, .center_freq = 5660},
2965 { .hw_value = 136, .center_freq = 5680},
2966 { .hw_value = 140, .center_freq = 5700},
2967 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002968 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002969 { .hw_value = 157, .center_freq = 5785},
2970 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002971 { .hw_value = 165, .center_freq = 5825},
2972};
2973
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002974/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002975static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002976 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002977 7, /* CONF_HW_RXTX_RATE_MCS7 */
2978 6, /* CONF_HW_RXTX_RATE_MCS6 */
2979 5, /* CONF_HW_RXTX_RATE_MCS5 */
2980 4, /* CONF_HW_RXTX_RATE_MCS4 */
2981 3, /* CONF_HW_RXTX_RATE_MCS3 */
2982 2, /* CONF_HW_RXTX_RATE_MCS2 */
2983 1, /* CONF_HW_RXTX_RATE_MCS1 */
2984 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002985
2986 7, /* CONF_HW_RXTX_RATE_54 */
2987 6, /* CONF_HW_RXTX_RATE_48 */
2988 5, /* CONF_HW_RXTX_RATE_36 */
2989 4, /* CONF_HW_RXTX_RATE_24 */
2990
2991 /* TI-specific rate */
2992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2993
2994 3, /* CONF_HW_RXTX_RATE_18 */
2995 2, /* CONF_HW_RXTX_RATE_12 */
2996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2997 1, /* CONF_HW_RXTX_RATE_9 */
2998 0, /* CONF_HW_RXTX_RATE_6 */
2999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3000 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3001 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3002};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003003
3004static struct ieee80211_supported_band wl1271_band_5ghz = {
3005 .channels = wl1271_channels_5ghz,
3006 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3007 .bitrates = wl1271_rates_5ghz,
3008 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003009 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003010};
3011
Tobias Klausera0ea9492010-05-20 10:38:11 +02003012static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003013 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3014 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3015};
3016
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003017static const struct ieee80211_ops wl1271_ops = {
3018 .start = wl1271_op_start,
3019 .stop = wl1271_op_stop,
3020 .add_interface = wl1271_op_add_interface,
3021 .remove_interface = wl1271_op_remove_interface,
3022 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003023 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003024 .configure_filter = wl1271_op_configure_filter,
3025 .tx = wl1271_op_tx,
3026 .set_key = wl1271_op_set_key,
3027 .hw_scan = wl1271_op_hw_scan,
3028 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003029 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003031 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003032 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003033 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003034 .sta_add = wl1271_op_sta_add,
3035 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003036 .ampdu_action = wl1271_op_ampdu_action,
Kalle Valoc8c90872010-02-18 13:25:53 +02003037 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038};
3039
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003040
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003041u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003042{
3043 u8 idx;
3044
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003045 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003046
3047 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3048 wl1271_error("Illegal RX rate from HW: %d", rate);
3049 return 0;
3050 }
3051
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003052 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003053 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3054 wl1271_error("Unsupported RX rate from HW: %d", rate);
3055 return 0;
3056 }
3057
3058 return idx;
3059}
3060
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003061static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3062 struct device_attribute *attr,
3063 char *buf)
3064{
3065 struct wl1271 *wl = dev_get_drvdata(dev);
3066 ssize_t len;
3067
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003068 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003069
3070 mutex_lock(&wl->mutex);
3071 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3072 wl->sg_enabled);
3073 mutex_unlock(&wl->mutex);
3074
3075 return len;
3076
3077}
3078
3079static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3080 struct device_attribute *attr,
3081 const char *buf, size_t count)
3082{
3083 struct wl1271 *wl = dev_get_drvdata(dev);
3084 unsigned long res;
3085 int ret;
3086
3087 ret = strict_strtoul(buf, 10, &res);
3088
3089 if (ret < 0) {
3090 wl1271_warning("incorrect value written to bt_coex_mode");
3091 return count;
3092 }
3093
3094 mutex_lock(&wl->mutex);
3095
3096 res = !!res;
3097
3098 if (res == wl->sg_enabled)
3099 goto out;
3100
3101 wl->sg_enabled = res;
3102
3103 if (wl->state == WL1271_STATE_OFF)
3104 goto out;
3105
3106 ret = wl1271_ps_elp_wakeup(wl, false);
3107 if (ret < 0)
3108 goto out;
3109
3110 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3111 wl1271_ps_elp_sleep(wl);
3112
3113 out:
3114 mutex_unlock(&wl->mutex);
3115 return count;
3116}
3117
3118static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3119 wl1271_sysfs_show_bt_coex_state,
3120 wl1271_sysfs_store_bt_coex_state);
3121
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003122static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3123 struct device_attribute *attr,
3124 char *buf)
3125{
3126 struct wl1271 *wl = dev_get_drvdata(dev);
3127 ssize_t len;
3128
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003129 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003130
3131 mutex_lock(&wl->mutex);
3132 if (wl->hw_pg_ver >= 0)
3133 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3134 else
3135 len = snprintf(buf, len, "n/a\n");
3136 mutex_unlock(&wl->mutex);
3137
3138 return len;
3139}
3140
3141static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3142 wl1271_sysfs_show_hw_pg_ver, NULL);
3143
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003144int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003145{
3146 int ret;
3147
3148 if (wl->mac80211_registered)
3149 return 0;
3150
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003151 ret = wl1271_fetch_nvs(wl);
3152 if (ret == 0) {
3153 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3154
3155 wl->mac_addr[0] = nvs_ptr[11];
3156 wl->mac_addr[1] = nvs_ptr[10];
3157 wl->mac_addr[2] = nvs_ptr[6];
3158 wl->mac_addr[3] = nvs_ptr[5];
3159 wl->mac_addr[4] = nvs_ptr[4];
3160 wl->mac_addr[5] = nvs_ptr[3];
3161 }
3162
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3164
3165 ret = ieee80211_register_hw(wl->hw);
3166 if (ret < 0) {
3167 wl1271_error("unable to register mac80211 hw: %d", ret);
3168 return ret;
3169 }
3170
3171 wl->mac80211_registered = true;
3172
Eliad Pellerd60080a2010-11-24 12:53:16 +02003173 wl1271_debugfs_init(wl);
3174
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003175 register_netdevice_notifier(&wl1271_dev_notifier);
3176
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177 wl1271_notice("loaded");
3178
3179 return 0;
3180}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003181EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003182
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003183void wl1271_unregister_hw(struct wl1271 *wl)
3184{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003185 if (wl->state == WL1271_STATE_PLT)
3186 __wl1271_plt_stop(wl);
3187
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003188 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003189 ieee80211_unregister_hw(wl->hw);
3190 wl->mac80211_registered = false;
3191
3192}
3193EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3194
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003195int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003197 static const u32 cipher_suites[] = {
3198 WLAN_CIPHER_SUITE_WEP40,
3199 WLAN_CIPHER_SUITE_WEP104,
3200 WLAN_CIPHER_SUITE_TKIP,
3201 WLAN_CIPHER_SUITE_CCMP,
3202 WL1271_CIPHER_SUITE_GEM,
3203 };
3204
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003205 /* The tx descriptor buffer and the TKIP space. */
3206 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3207 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208
3209 /* unit us */
3210 /* FIXME: find a proper value */
3211 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003212 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213
3214 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003215 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003216 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003217 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003218 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003219 IEEE80211_HW_CONNECTION_MONITOR |
3220 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003221
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003222 wl->hw->wiphy->cipher_suites = cipher_suites;
3223 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3224
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003225 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003226 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003227 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003228 /*
3229 * Maximum length of elements in scanning probe request templates
3230 * should be the maximum length possible for a template, without
3231 * the IEEE80211 header of the template
3232 */
3233 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3234 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003235
3236 /*
3237 * We keep local copies of the band structs because we need to
3238 * modify them on a per-device basis.
3239 */
3240 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3241 sizeof(wl1271_band_2ghz));
3242 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3243 sizeof(wl1271_band_5ghz));
3244
3245 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3246 &wl->bands[IEEE80211_BAND_2GHZ];
3247 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3248 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003249
Kalle Valo12bd8942010-03-18 12:26:33 +02003250 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003251 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003252
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003253 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3254
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003255 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003256
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003257 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3258
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003259 wl->hw->max_rx_aggregation_subframes = 8;
3260
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003261 return 0;
3262}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003263EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003266
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003267struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003269 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003270 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003271 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003272 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003273 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003274
3275 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3276 if (!hw) {
3277 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003278 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003279 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003280 }
3281
Julia Lawall929ebd32010-05-15 23:16:39 +02003282 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003283 if (!plat_dev) {
3284 wl1271_error("could not allocate platform_device");
3285 ret = -ENOMEM;
3286 goto err_plat_alloc;
3287 }
3288
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003289 wl = hw->priv;
3290 memset(wl, 0, sizeof(*wl));
3291
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003292 INIT_LIST_HEAD(&wl->list);
3293
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003295 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003296
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003297 for (i = 0; i < NUM_TX_QUEUES; i++)
3298 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003299
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003300 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003301 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003302 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3303 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3304 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3305 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003307 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003310 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3311 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003312 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003313 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003314 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003315 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003316 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3317 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003318 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003319 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003320 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003321 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003322 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003323 wl->bss_type = MAX_BSS_TYPE;
3324 wl->set_bss_type = MAX_BSS_TYPE;
3325 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003326
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003327 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003328 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003329 wl->tx_frames[i] = NULL;
3330
3331 spin_lock_init(&wl->wl_lock);
3332
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003333 wl->state = WL1271_STATE_OFF;
3334 mutex_init(&wl->mutex);
3335
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003336 /* Apply default driver configuration. */
3337 wl1271_conf_init(wl);
3338
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003339 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3340 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3341 if (!wl->aggr_buf) {
3342 ret = -ENOMEM;
3343 goto err_hw;
3344 }
3345
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003346 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003347 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003348 if (ret) {
3349 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003350 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003351 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003352 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003353
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003354 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003355 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003356 if (ret < 0) {
3357 wl1271_error("failed to create sysfs file bt_coex_state");
3358 goto err_platform;
3359 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003360
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003361 /* Create sysfs file to get HW PG version */
3362 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3363 if (ret < 0) {
3364 wl1271_error("failed to create sysfs file hw_pg_ver");
3365 goto err_bt_coex_state;
3366 }
3367
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003368 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003369
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003370err_bt_coex_state:
3371 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3372
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003373err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003374 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003375
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003376err_aggr:
3377 free_pages((unsigned long)wl->aggr_buf, order);
3378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003379err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003380 wl1271_debugfs_exit(wl);
3381 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003382
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003383err_plat_alloc:
3384 ieee80211_free_hw(hw);
3385
3386err_hw_alloc:
3387
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003388 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003389}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003390EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003391
3392int wl1271_free_hw(struct wl1271 *wl)
3393{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003394 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003395 free_pages((unsigned long)wl->aggr_buf,
3396 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003397 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003398
3399 wl1271_debugfs_exit(wl);
3400
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003401 vfree(wl->fw);
3402 wl->fw = NULL;
3403 kfree(wl->nvs);
3404 wl->nvs = NULL;
3405
3406 kfree(wl->fw_status);
3407 kfree(wl->tx_res_if);
3408
3409 ieee80211_free_hw(wl->hw);
3410
3411 return 0;
3412}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003413EXPORT_SYMBOL_GPL(wl1271_free_hw);
3414
Guy Eilam491bbd62011-01-12 10:33:29 +01003415u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003416EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003417module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003418MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3419
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003420MODULE_LICENSE("GPL");
3421MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3422MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");