blob: 48194629c00b9aa98ffe0d3a92413b92a0de12d4 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
Shahar Levi00d20102010-11-08 11:20:10 +000034#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "reg.h"
37#include "io.h"
38#include "event.h"
39#include "tx.h"
40#include "rx.h"
41#include "ps.h"
42#include "init.h"
43#include "debugfs.h"
44#include "cmd.h"
45#include "boot.h"
46#include "testmode.h"
47#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200119 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200123 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200127 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200134 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200141 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200148 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200156 .ap_rc_conf = {
157 [0] = {
158 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
159 .short_retry_limit = 10,
160 .long_retry_limit = 10,
161 .aflags = 0,
162 },
163 [1] = {
164 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
165 .short_retry_limit = 10,
166 .long_retry_limit = 10,
167 .aflags = 0,
168 },
169 [2] = {
170 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
171 .short_retry_limit = 10,
172 .long_retry_limit = 10,
173 .aflags = 0,
174 },
175 [3] = {
176 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
179 .aflags = 0,
180 },
181 },
182 .ap_mgmt_conf = {
183 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
184 .short_retry_limit = 10,
185 .long_retry_limit = 10,
186 .aflags = 0,
187 },
188 .ap_bcst_conf = {
189 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
190 .short_retry_limit = 10,
191 .long_retry_limit = 10,
192 .aflags = 0,
193 },
Arik Nemtsov79b223f2010-10-16 17:52:59 +0200194 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200195 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_BE] = {
198 .queue_id = CONF_TX_AC_BE,
199 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_BK] = {
206 .queue_id = CONF_TX_AC_BK,
207 .channel_type = CONF_CHANNEL_TYPE_EDCF,
208 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 [CONF_TX_AC_VI] = {
214 .queue_id = CONF_TX_AC_VI,
215 .channel_type = CONF_CHANNEL_TYPE_EDCF,
216 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300217 .ps_scheme = CONF_PS_SCHEME_LEGACY,
218 .ack_policy = CONF_ACK_POLICY_LEGACY,
219 .apsd_conf = {0, 0},
220 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200221 [CONF_TX_AC_VO] = {
222 .queue_id = CONF_TX_AC_VO,
223 .channel_type = CONF_CHANNEL_TYPE_EDCF,
224 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300225 .ps_scheme = CONF_PS_SCHEME_LEGACY,
226 .ack_policy = CONF_ACK_POLICY_LEGACY,
227 .apsd_conf = {0, 0},
228 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 },
230 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300232 .tx_compl_threshold = 4,
233 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
234 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200235 .tmpl_short_retry_limit = 10,
236 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
238 .conn = {
239 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300241 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
242 .bcn_filt_ie_count = 1,
243 .bcn_filt_ie = {
244 [0] = {
245 .ie = WLAN_EID_CHANNEL_SWITCH,
246 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
247 }
248 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300250 .bss_lose_timeout = 100,
251 .beacon_rx_timeout = 10000,
252 .broadcast_timeout = 20000,
253 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300254 .ps_poll_threshold = 10,
255 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300256 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200257 .bet_max_consecutive = 10,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200258 .psm_entry_retries = 5,
259 .psm_entry_nullfunc_retries = 3,
260 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300261 .keep_alive_interval = 55000,
262 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200264 .itrim = {
265 .enable = false,
266 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200267 },
268 .pm_config = {
269 .host_clk_settling_time = 5000,
270 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300271 },
272 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300273 .trigger_pacing = 1,
274 .avg_weight_rssi_beacon = 20,
275 .avg_weight_rssi_data = 10,
276 .avg_weight_snr_beacon = 20,
277 .avg_weight_snr_data = 10
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200278 },
279 .scan = {
280 .min_dwell_time_active = 7500,
281 .max_dwell_time_active = 30000,
282 .min_dwell_time_passive = 30000,
283 .max_dwell_time_passive = 60000,
284 .num_probe_reqs = 2,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300296};
297
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200298static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200299static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200300
301
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200302static void wl1271_device_release(struct device *dev)
303{
304
305}
306
307static struct platform_device wl1271_device = {
308 .name = "wl1271",
309 .id = -1,
310
311 /* device model insists to have a release function */
312 .dev = {
313 .release = wl1271_device_release,
314 },
315};
316
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300317static LIST_HEAD(wl_list);
318
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300319static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
320 void *arg)
321{
322 struct net_device *dev = arg;
323 struct wireless_dev *wdev;
324 struct wiphy *wiphy;
325 struct ieee80211_hw *hw;
326 struct wl1271 *wl;
327 struct wl1271 *wl_temp;
328 int ret = 0;
329
330 /* Check that this notification is for us. */
331 if (what != NETDEV_CHANGE)
332 return NOTIFY_DONE;
333
334 wdev = dev->ieee80211_ptr;
335 if (wdev == NULL)
336 return NOTIFY_DONE;
337
338 wiphy = wdev->wiphy;
339 if (wiphy == NULL)
340 return NOTIFY_DONE;
341
342 hw = wiphy_priv(wiphy);
343 if (hw == NULL)
344 return NOTIFY_DONE;
345
346 wl_temp = hw->priv;
347 list_for_each_entry(wl, &wl_list, list) {
348 if (wl == wl_temp)
349 break;
350 }
351 if (wl != wl_temp)
352 return NOTIFY_DONE;
353
354 mutex_lock(&wl->mutex);
355
356 if (wl->state == WL1271_STATE_OFF)
357 goto out;
358
359 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
360 goto out;
361
362 ret = wl1271_ps_elp_wakeup(wl, false);
363 if (ret < 0)
364 goto out;
365
366 if ((dev->operstate == IF_OPER_UP) &&
367 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
368 wl1271_cmd_set_sta_state(wl);
369 wl1271_info("Association completed.");
370 }
371
372 wl1271_ps_elp_sleep(wl);
373
374out:
375 mutex_unlock(&wl->mutex);
376
377 return NOTIFY_OK;
378}
379
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100380static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200381 struct regulatory_request *request)
382{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100383 struct ieee80211_supported_band *band;
384 struct ieee80211_channel *ch;
385 int i;
386
387 band = wiphy->bands[IEEE80211_BAND_5GHZ];
388 for (i = 0; i < band->n_channels; i++) {
389 ch = &band->channels[i];
390 if (ch->flags & IEEE80211_CHAN_DISABLED)
391 continue;
392
393 if (ch->flags & IEEE80211_CHAN_RADAR)
394 ch->flags |= IEEE80211_CHAN_NO_IBSS |
395 IEEE80211_CHAN_PASSIVE_SCAN;
396
397 }
398
399 return 0;
400}
401
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300402static void wl1271_conf_init(struct wl1271 *wl)
403{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300404
405 /*
406 * This function applies the default configuration to the driver. This
407 * function is invoked upon driver load (spi probe.)
408 *
409 * The configuration is stored in a run-time structure in order to
410 * facilitate for run-time adjustment of any of the parameters. Making
411 * changes to the configuration structure will apply the new values on
412 * the next interface up (wl1271_op_start.)
413 */
414
415 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300416 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300417}
418
419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420static int wl1271_plt_init(struct wl1271 *wl)
421{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200422 struct conf_tx_ac_category *conf_ac;
423 struct conf_tx_tid *conf_tid;
424 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300425
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200426 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200427 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200428 return ret;
429
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200430 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200431 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200432 return ret;
433
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200434 ret = wl1271_cmd_ext_radio_parms(wl);
435 if (ret < 0)
436 return ret;
437
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200438 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200439 if (ret < 0)
440 return ret;
441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 ret = wl1271_acx_init_mem_config(wl);
443 if (ret < 0)
444 return ret;
445
Luciano Coelho12419cce2010-02-18 13:25:44 +0200446 /* PHY layer config */
447 ret = wl1271_init_phy_config(wl);
448 if (ret < 0)
449 goto out_free_memmap;
450
451 ret = wl1271_acx_dco_itrim_params(wl);
452 if (ret < 0)
453 goto out_free_memmap;
454
455 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200456 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200457 if (ret < 0)
458 goto out_free_memmap;
459
460 /* Bluetooth WLAN coexistence */
461 ret = wl1271_init_pta(wl);
462 if (ret < 0)
463 goto out_free_memmap;
464
465 /* Energy detection */
466 ret = wl1271_init_energy_detection(wl);
467 if (ret < 0)
468 goto out_free_memmap;
469
470 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100471 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200472 if (ret < 0)
473 goto out_free_memmap;
474
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200475 /* Default TID/AC configuration */
476 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200477 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200478 conf_ac = &wl->conf.tx.ac_conf[i];
479 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
480 conf_ac->cw_max, conf_ac->aifsn,
481 conf_ac->tx_op_limit);
482 if (ret < 0)
483 goto out_free_memmap;
484
Luciano Coelho12419cce2010-02-18 13:25:44 +0200485 conf_tid = &wl->conf.tx.tid_conf[i];
486 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
487 conf_tid->channel_type,
488 conf_tid->tsid,
489 conf_tid->ps_scheme,
490 conf_tid->ack_policy,
491 conf_tid->apsd_conf[0],
492 conf_tid->apsd_conf[1]);
493 if (ret < 0)
494 goto out_free_memmap;
495 }
496
Luciano Coelho12419cce2010-02-18 13:25:44 +0200497 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200498 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200500 goto out_free_memmap;
501
502 /* Configure for CAM power saving (ie. always active) */
503 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
504 if (ret < 0)
505 goto out_free_memmap;
506
507 /* configure PM */
508 ret = wl1271_acx_pm_config(wl);
509 if (ret < 0)
510 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511
512 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200513
514 out_free_memmap:
515 kfree(wl->target_mem_map);
516 wl->target_mem_map = NULL;
517
518 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519}
520
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300521static void wl1271_fw_status(struct wl1271 *wl,
522 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200524 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525 u32 total = 0;
526 int i;
527
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200528 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529
530 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
531 "drv_rx_counter = %d, tx_results_counter = %d)",
532 status->intr,
533 status->fw_rx_counter,
534 status->drv_rx_counter,
535 status->tx_results_counter);
536
537 /* update number of available TX blocks */
538 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300539 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
540 wl->tx_blocks_freed[i];
541
542 wl->tx_blocks_freed[i] =
543 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300544 wl->tx_blocks_available += cnt;
545 total += cnt;
546 }
547
Ido Yariva5225502010-10-12 14:49:10 +0200548 /* if more blocks are available now, tx work can be scheduled */
549 if (total)
550 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300551
552 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200553 getnstimeofday(&ts);
554 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
555 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556}
557
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200558#define WL1271_IRQ_MAX_LOOPS 10
559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300560static void wl1271_irq_work(struct work_struct *work)
561{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300563 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200564 int loopcount = WL1271_IRQ_MAX_LOOPS;
565 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300566 struct wl1271 *wl =
567 container_of(work, struct wl1271, irq_work);
568
569 mutex_lock(&wl->mutex);
570
571 wl1271_debug(DEBUG_IRQ, "IRQ work");
572
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200573 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300574 goto out;
575
576 ret = wl1271_ps_elp_wakeup(wl, true);
577 if (ret < 0)
578 goto out;
579
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200580 spin_lock_irqsave(&wl->wl_lock, flags);
581 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
582 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
583 spin_unlock_irqrestore(&wl->wl_lock, flags);
584 loopcount--;
585
586 wl1271_fw_status(wl, wl->fw_status);
587 intr = le32_to_cpu(wl->fw_status->intr);
588 if (!intr) {
589 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200590 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200591 continue;
592 }
593
594 intr &= WL1271_INTR_MASK;
595
Eliad Pellerccc83b02010-10-27 14:09:57 +0200596 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
597 wl1271_error("watchdog interrupt received! "
598 "starting recovery.");
599 ieee80211_queue_work(wl->hw, &wl->recovery_work);
600
601 /* restarting the chip. ignore any other interrupt. */
602 goto out;
603 }
604
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200605 if (intr & WL1271_ACX_INTR_DATA) {
606 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
607
608 /* check for tx results */
609 if (wl->fw_status->tx_results_counter !=
610 (wl->tx_results_count & 0xff))
611 wl1271_tx_complete(wl);
612
Ido Yariva5225502010-10-12 14:49:10 +0200613 /* Check if any tx blocks were freed */
614 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200615 wl->tx_queue_count) {
Ido Yariva5225502010-10-12 14:49:10 +0200616 /*
617 * In order to avoid starvation of the TX path,
618 * call the work function directly.
619 */
620 wl1271_tx_work_locked(wl);
621 }
622
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200623 wl1271_rx(wl, wl->fw_status);
624 }
625
626 if (intr & WL1271_ACX_INTR_EVENT_A) {
627 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
628 wl1271_event_handle(wl, 0);
629 }
630
631 if (intr & WL1271_ACX_INTR_EVENT_B) {
632 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
633 wl1271_event_handle(wl, 1);
634 }
635
636 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
637 wl1271_debug(DEBUG_IRQ,
638 "WL1271_ACX_INTR_INIT_COMPLETE");
639
640 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
641 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
642
643 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644 }
645
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200646 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
647 ieee80211_queue_work(wl->hw, &wl->irq_work);
648 else
649 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
650 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652 wl1271_ps_elp_sleep(wl);
653
654out:
655 mutex_unlock(&wl->mutex);
656}
657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658static int wl1271_fetch_firmware(struct wl1271 *wl)
659{
660 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200661 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 int ret;
663
Arik Nemtsov166d5042010-10-16 21:44:57 +0200664 switch (wl->bss_type) {
665 case BSS_TYPE_AP_BSS:
666 fw_name = WL1271_AP_FW_NAME;
667 break;
668 case BSS_TYPE_IBSS:
669 case BSS_TYPE_STA_BSS:
670 fw_name = WL1271_FW_NAME;
671 break;
672 default:
673 wl1271_error("no compatible firmware for bss_type %d",
674 wl->bss_type);
675 return -EINVAL;
676 }
677
678 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
679
680 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681
682 if (ret < 0) {
683 wl1271_error("could not get firmware: %d", ret);
684 return ret;
685 }
686
687 if (fw->size % 4) {
688 wl1271_error("firmware size is not multiple of 32 bits: %zu",
689 fw->size);
690 ret = -EILSEQ;
691 goto out;
692 }
693
Arik Nemtsov166d5042010-10-16 21:44:57 +0200694 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300696 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300697
698 if (!wl->fw) {
699 wl1271_error("could not allocate memory for the firmware");
700 ret = -ENOMEM;
701 goto out;
702 }
703
704 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200705 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300706 ret = 0;
707
708out:
709 release_firmware(fw);
710
711 return ret;
712}
713
714static int wl1271_fetch_nvs(struct wl1271 *wl)
715{
716 const struct firmware *fw;
717 int ret;
718
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200719 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720
721 if (ret < 0) {
722 wl1271_error("could not get nvs file: %d", ret);
723 return ret;
724 }
725
Julia Lawall929ebd32010-05-15 23:16:39 +0200726 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727
728 if (!wl->nvs) {
729 wl1271_error("could not allocate memory for the nvs file");
730 ret = -ENOMEM;
731 goto out;
732 }
733
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200734 wl->nvs_len = fw->size;
735
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736out:
737 release_firmware(fw);
738
739 return ret;
740}
741
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200742static void wl1271_recovery_work(struct work_struct *work)
743{
744 struct wl1271 *wl =
745 container_of(work, struct wl1271, recovery_work);
746
747 mutex_lock(&wl->mutex);
748
749 if (wl->state != WL1271_STATE_ON)
750 goto out;
751
752 wl1271_info("Hardware recovery in progress.");
753
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200754 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
755 ieee80211_connection_loss(wl->vif);
756
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200757 /* reboot the chipset */
758 __wl1271_op_remove_interface(wl);
759 ieee80211_restart_hw(wl->hw);
760
761out:
762 mutex_unlock(&wl->mutex);
763}
764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765static void wl1271_fw_wakeup(struct wl1271 *wl)
766{
767 u32 elp_reg;
768
769 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300770 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771}
772
773static int wl1271_setup(struct wl1271 *wl)
774{
775 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
776 if (!wl->fw_status)
777 return -ENOMEM;
778
779 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
780 if (!wl->tx_res_if) {
781 kfree(wl->fw_status);
782 return -ENOMEM;
783 }
784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 return 0;
786}
787
788static int wl1271_chip_wakeup(struct wl1271 *wl)
789{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300790 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 int ret = 0;
792
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200793 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200794 ret = wl1271_power_on(wl);
795 if (ret < 0)
796 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200798 wl1271_io_reset(wl);
799 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 /* We don't need a real memory partition here, because we only want
802 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300803 memset(&partition, 0, sizeof(partition));
804 partition.reg.start = REGISTERS_BASE;
805 partition.reg.size = REGISTERS_DOWN_SIZE;
806 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
808 /* ELP module wake up */
809 wl1271_fw_wakeup(wl);
810
811 /* whal_FwCtrl_BootSm() */
812
813 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200814 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815
816 /* 1. check if chip id is valid */
817
818 switch (wl->chip.id) {
819 case CHIP_ID_1271_PG10:
820 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
821 wl->chip.id);
822
823 ret = wl1271_setup(wl);
824 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200825 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 break;
827 case CHIP_ID_1271_PG20:
828 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
829 wl->chip.id);
830
831 ret = wl1271_setup(wl);
832 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200833 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 break;
835 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200836 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300837 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200838 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 }
840
Arik Nemtsov166d5042010-10-16 21:44:57 +0200841 /* Make sure the firmware type matches the BSS type */
842 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 ret = wl1271_fetch_firmware(wl);
844 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200845 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 }
847
848 /* No NVS from netlink, try to get it from the filesystem */
849 if (wl->nvs == NULL) {
850 ret = wl1271_fetch_nvs(wl);
851 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200852 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 }
854
855out:
856 return ret;
857}
858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859int wl1271_plt_start(struct wl1271 *wl)
860{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200861 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300862 int ret;
863
864 mutex_lock(&wl->mutex);
865
866 wl1271_notice("power up");
867
868 if (wl->state != WL1271_STATE_OFF) {
869 wl1271_error("cannot go into PLT state because not "
870 "in off state: %d", wl->state);
871 ret = -EBUSY;
872 goto out;
873 }
874
Arik Nemtsov166d5042010-10-16 21:44:57 +0200875 wl->bss_type = BSS_TYPE_STA_BSS;
876
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200877 while (retries) {
878 retries--;
879 ret = wl1271_chip_wakeup(wl);
880 if (ret < 0)
881 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200883 ret = wl1271_boot(wl);
884 if (ret < 0)
885 goto power_off;
886
887 ret = wl1271_plt_init(wl);
888 if (ret < 0)
889 goto irq_disable;
890
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200891 wl->state = WL1271_STATE_PLT;
892 wl1271_notice("firmware booted in PLT mode (%s)",
893 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 goto out;
895
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200896irq_disable:
897 wl1271_disable_interrupts(wl);
898 mutex_unlock(&wl->mutex);
899 /* Unlocking the mutex in the middle of handling is
900 inherently unsafe. In this case we deem it safe to do,
901 because we need to let any possibly pending IRQ out of
902 the system (and while we are WL1271_STATE_OFF the IRQ
903 work function will not do anything.) Also, any other
904 possible concurrent operations will fail due to the
905 current state, hence the wl1271 struct should be safe. */
906 cancel_work_sync(&wl->irq_work);
907 mutex_lock(&wl->mutex);
908power_off:
909 wl1271_power_off(wl);
910 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200912 wl1271_error("firmware boot in PLT mode failed despite %d retries",
913 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914out:
915 mutex_unlock(&wl->mutex);
916
917 return ret;
918}
919
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100920int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921{
922 int ret = 0;
923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924 wl1271_notice("power down");
925
926 if (wl->state != WL1271_STATE_PLT) {
927 wl1271_error("cannot power down because not in PLT "
928 "state: %d", wl->state);
929 ret = -EBUSY;
930 goto out;
931 }
932
933 wl1271_disable_interrupts(wl);
934 wl1271_power_off(wl);
935
936 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300937 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 mutex_unlock(&wl->mutex);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200940 cancel_work_sync(&wl->irq_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200941 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100942 mutex_lock(&wl->mutex);
943out:
944 return ret;
945}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +0200946
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +0100947int wl1271_plt_stop(struct wl1271 *wl)
948{
949 int ret;
950
951 mutex_lock(&wl->mutex);
952 ret = __wl1271_plt_stop(wl);
953 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954 return ret;
955}
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
958{
959 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200960 struct ieee80211_conf *conf = &hw->conf;
961 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
962 struct ieee80211_sta *sta = txinfo->control.sta;
963 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200964 int q;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965
Shahar Levi18357852010-10-13 16:09:41 +0200966 /*
967 * peek into the rates configured in the STA entry.
968 * The rates set after connection stage, The first block only BG sets:
969 * the compare is for bit 0-16 of sta_rate_set. The second block add
970 * HT rates in case of HT supported.
971 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200972 spin_lock_irqsave(&wl->wl_lock, flags);
Shahar Levi18357852010-10-13 16:09:41 +0200973 if (sta &&
974 (sta->supp_rates[conf->channel->band] !=
Arik Nemtsovc6c8a652010-10-16 20:27:53 +0200975 (wl->sta_rate_set & HW_BG_RATES_MASK)) &&
976 wl->bss_type != BSS_TYPE_AP_BSS) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200977 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
978 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
979 }
Shahar Levi18357852010-10-13 16:09:41 +0200980
Shahar Levi00d20102010-11-08 11:20:10 +0000981#ifdef CONFIG_WL12XX_HT
Shahar Levi18357852010-10-13 16:09:41 +0200982 if (sta &&
983 sta->ht_cap.ht_supported &&
984 ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) !=
985 sta->ht_cap.mcs.rx_mask[0])) {
986 /* Clean MCS bits before setting them */
987 wl->sta_rate_set &= HW_BG_RATES_MASK;
988 wl->sta_rate_set |=
989 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
990 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
991 }
992#endif
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200993 wl->tx_queue_count++;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200994 spin_unlock_irqrestore(&wl->wl_lock, flags);
995
996 /* queue the packet */
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200997 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
998 skb_queue_tail(&wl->tx_queue[q], skb);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
1000 /*
1001 * The chip specific setup must run before the first TX packet -
1002 * before that, the tx_work will not be initialized!
1003 */
1004
Ido Yariva5225502010-10-12 14:49:10 +02001005 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1006 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007
1008 /*
1009 * The workqueue is slow to process the tx_queue and we need stop
1010 * the queue here, otherwise the queue will get too long.
1011 */
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001012 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001013 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001015 spin_lock_irqsave(&wl->wl_lock, flags);
1016 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001017 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +02001018 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 }
1020
1021 return NETDEV_TX_OK;
1022}
1023
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001024static struct notifier_block wl1271_dev_notifier = {
1025 .notifier_call = wl1271_dev_notify,
1026};
1027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028static int wl1271_op_start(struct ieee80211_hw *hw)
1029{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001030 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1031
1032 /*
1033 * We have to delay the booting of the hardware because
1034 * we need to know the local MAC address before downloading and
1035 * initializing the firmware. The MAC address cannot be changed
1036 * after boot, and without the proper MAC address, the firmware
1037 * will not function properly.
1038 *
1039 * The MAC address is first known when the corresponding interface
1040 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001041 *
1042 * In addition, we currently have different firmwares for AP and managed
1043 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001044 */
1045
1046 return 0;
1047}
1048
1049static void wl1271_op_stop(struct ieee80211_hw *hw)
1050{
1051 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1052}
1053
1054static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1055 struct ieee80211_vif *vif)
1056{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001058 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001059 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001061 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001063 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1064 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065
1066 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001067 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001068 wl1271_debug(DEBUG_MAC80211,
1069 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001070 ret = -EBUSY;
1071 goto out;
1072 }
1073
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001074 switch (vif->type) {
1075 case NL80211_IFTYPE_STATION:
1076 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001077 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001078 break;
1079 case NL80211_IFTYPE_ADHOC:
1080 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001081 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001082 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001083 case NL80211_IFTYPE_AP:
1084 wl->bss_type = BSS_TYPE_AP_BSS;
1085 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001086 default:
1087 ret = -EOPNOTSUPP;
1088 goto out;
1089 }
1090
1091 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092
1093 if (wl->state != WL1271_STATE_OFF) {
1094 wl1271_error("cannot start because not in off state: %d",
1095 wl->state);
1096 ret = -EBUSY;
1097 goto out;
1098 }
1099
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001100 while (retries) {
1101 retries--;
1102 ret = wl1271_chip_wakeup(wl);
1103 if (ret < 0)
1104 goto power_off;
1105
1106 ret = wl1271_boot(wl);
1107 if (ret < 0)
1108 goto power_off;
1109
1110 ret = wl1271_hw_init(wl);
1111 if (ret < 0)
1112 goto irq_disable;
1113
Eliad Peller71125ab2010-10-28 21:46:43 +02001114 booted = true;
1115 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001117irq_disable:
1118 wl1271_disable_interrupts(wl);
1119 mutex_unlock(&wl->mutex);
1120 /* Unlocking the mutex in the middle of handling is
1121 inherently unsafe. In this case we deem it safe to do,
1122 because we need to let any possibly pending IRQ out of
1123 the system (and while we are WL1271_STATE_OFF the IRQ
1124 work function will not do anything.) Also, any other
1125 possible concurrent operations will fail due to the
1126 current state, hence the wl1271 struct should be safe. */
1127 cancel_work_sync(&wl->irq_work);
1128 mutex_lock(&wl->mutex);
1129power_off:
1130 wl1271_power_off(wl);
1131 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132
Eliad Peller71125ab2010-10-28 21:46:43 +02001133 if (!booted) {
1134 wl1271_error("firmware boot failed despite %d retries",
1135 WL1271_BOOT_RETRIES);
1136 goto out;
1137 }
1138
1139 wl->vif = vif;
1140 wl->state = WL1271_STATE_ON;
1141 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
1142
1143 /* update hw/fw version info in wiphy struct */
1144 wiphy->hw_version = wl->chip.id;
1145 strncpy(wiphy->fw_version, wl->chip.fw_ver,
1146 sizeof(wiphy->fw_version));
1147
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001148 /*
1149 * Now we know if 11a is supported (info from the NVS), so disable
1150 * 11a channels if not supported
1151 */
1152 if (!wl->enable_11a)
1153 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1154
1155 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1156 wl->enable_11a ? "" : "not ");
1157
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001158out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001159 mutex_unlock(&wl->mutex);
1160
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001161 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001162 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001163
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001164 return ret;
1165}
1166
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001167static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001168{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001169 int i;
1170
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001171 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001173 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001175 list_del(&wl->list);
1176
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001177 WARN_ON(wl->state != WL1271_STATE_ON);
1178
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001179 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001180 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001181 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001182
Luciano Coelho08688d62010-07-08 17:50:07 +03001183 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001184 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1185 kfree(wl->scan.scanned_ch);
1186 wl->scan.scanned_ch = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001187 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001188 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 }
1190
1191 wl->state = WL1271_STATE_OFF;
1192
1193 wl1271_disable_interrupts(wl);
1194
1195 mutex_unlock(&wl->mutex);
1196
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001197 cancel_delayed_work_sync(&wl->scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 cancel_work_sync(&wl->irq_work);
1199 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001200 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001201 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202
1203 mutex_lock(&wl->mutex);
1204
1205 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001206 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 wl1271_power_off(wl);
1208
1209 memset(wl->bssid, 0, ETH_ALEN);
1210 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1211 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001213 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001214 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215
1216 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001217 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1219 wl->tx_blocks_available = 0;
1220 wl->tx_results_count = 0;
1221 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001222 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001223 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224 wl->time_offset = 0;
1225 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001226 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1227 wl->sta_rate_set = 0;
1228 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001229 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001230 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001231 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001232 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234 for (i = 0; i < NUM_TX_QUEUES; i++)
1235 wl->tx_blocks_freed[i] = 0;
1236
1237 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001238
1239 kfree(wl->fw_status);
1240 wl->fw_status = NULL;
1241 kfree(wl->tx_res_if);
1242 wl->tx_res_if = NULL;
1243 kfree(wl->target_mem_map);
1244 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001245}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001246
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001247static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1248 struct ieee80211_vif *vif)
1249{
1250 struct wl1271 *wl = hw->priv;
1251
1252 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001253 /*
1254 * wl->vif can be null here if someone shuts down the interface
1255 * just when hardware recovery has been started.
1256 */
1257 if (wl->vif) {
1258 WARN_ON(wl->vif != vif);
1259 __wl1271_op_remove_interface(wl);
1260 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261
Juuso Oikarinen67353292010-11-18 15:19:02 +02001262 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001263 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264}
1265
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001266static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1267{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001268 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001269
1270 /* combine requested filters with current filter config */
1271 filters = wl->filters | filters;
1272
1273 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1274
1275 if (filters & FIF_PROMISC_IN_BSS) {
1276 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1277 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1278 wl->rx_config |= CFG_BSSID_FILTER_EN;
1279 }
1280 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1281 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1282 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1283 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1284 }
1285 if (filters & FIF_OTHER_BSS) {
1286 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1287 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1288 }
1289 if (filters & FIF_CONTROL) {
1290 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1291 wl->rx_filter |= CFG_RX_CTL_EN;
1292 }
1293 if (filters & FIF_FCSFAIL) {
1294 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1295 wl->rx_filter |= CFG_RX_FCS_ERROR;
1296 }
1297}
1298
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001299static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001300{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001301 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001302 /* we need to use a dummy BSSID for now */
1303 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1304 0xad, 0xbe, 0xef };
1305
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001306 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1307
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001308 /* pass through frames from all BSS */
1309 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1310
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001311 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001312 if (ret < 0)
1313 goto out;
1314
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001315 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001316
1317out:
1318 return ret;
1319}
1320
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001321static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001322{
1323 int ret;
1324
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001325 /*
1326 * One of the side effects of the JOIN command is that is clears
1327 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1328 * to a WPA/WPA2 access point will therefore kill the data-path.
1329 * Currently there is no supported scenario for JOIN during
1330 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1331 * must be handled somehow.
1332 *
1333 */
1334 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1335 wl1271_info("JOIN while associated.");
1336
1337 if (set_assoc)
1338 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1339
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001340 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1341 if (ret < 0)
1342 goto out;
1343
1344 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1345
1346 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1347 goto out;
1348
1349 /*
1350 * The join command disable the keep-alive mode, shut down its process,
1351 * and also clear the template config, so we need to reset it all after
1352 * the join. The acx_aid starts the keep-alive process, and the order
1353 * of the commands below is relevant.
1354 */
1355 ret = wl1271_acx_keep_alive_mode(wl, true);
1356 if (ret < 0)
1357 goto out;
1358
1359 ret = wl1271_acx_aid(wl, wl->aid);
1360 if (ret < 0)
1361 goto out;
1362
1363 ret = wl1271_cmd_build_klv_null_data(wl);
1364 if (ret < 0)
1365 goto out;
1366
1367 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1368 ACX_KEEP_ALIVE_TPL_VALID);
1369 if (ret < 0)
1370 goto out;
1371
1372out:
1373 return ret;
1374}
1375
1376static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001377{
1378 int ret;
1379
1380 /* to stop listening to a channel, we disconnect */
1381 ret = wl1271_cmd_disconnect(wl);
1382 if (ret < 0)
1383 goto out;
1384
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001385 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001386 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001387
1388 /* stop filterting packets based on bssid */
1389 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001390
1391out:
1392 return ret;
1393}
1394
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001395static void wl1271_set_band_rate(struct wl1271 *wl)
1396{
1397 if (wl->band == IEEE80211_BAND_2GHZ)
1398 wl->basic_rate_set = wl->conf.tx.basic_rate;
1399 else
1400 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1401}
1402
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001403static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001404{
1405 int ret;
1406
1407 if (idle) {
1408 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1409 ret = wl1271_unjoin(wl);
1410 if (ret < 0)
1411 goto out;
1412 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001413 wl->rate_set = wl1271_tx_min_rate_get(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001414 wl->sta_rate_set = 0;
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001415 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001416 if (ret < 0)
1417 goto out;
1418 ret = wl1271_acx_keep_alive_config(
1419 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1420 ACX_KEEP_ALIVE_TPL_INVALID);
1421 if (ret < 0)
1422 goto out;
1423 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1424 } else {
1425 /* increment the session counter */
1426 wl->session_counter++;
1427 if (wl->session_counter >= SESSION_COUNTER_MAX)
1428 wl->session_counter = 0;
1429 ret = wl1271_dummy_join(wl);
1430 if (ret < 0)
1431 goto out;
1432 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1433 }
1434
1435out:
1436 return ret;
1437}
1438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1440{
1441 struct wl1271 *wl = hw->priv;
1442 struct ieee80211_conf *conf = &hw->conf;
1443 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001444 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445
1446 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1447
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001448 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1449 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450 channel,
1451 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001452 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001453 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1454 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001456 /*
1457 * mac80211 will go to idle nearly immediately after transmitting some
1458 * frames, such as the deauth. To make sure those frames reach the air,
1459 * wait here until the TX queue is fully flushed.
1460 */
1461 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1462 (conf->flags & IEEE80211_CONF_IDLE))
1463 wl1271_tx_flush(wl);
1464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 mutex_lock(&wl->mutex);
1466
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001467 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1468 ret = -EAGAIN;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001469 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001470 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001471
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001472 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1473
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001474 ret = wl1271_ps_elp_wakeup(wl, false);
1475 if (ret < 0)
1476 goto out;
1477
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001478 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001479 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1480 ((wl->band != conf->channel->band) ||
1481 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001482 wl->band = conf->channel->band;
1483 wl->channel = channel;
1484
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001485 if (!is_ap) {
1486 /*
1487 * FIXME: the mac80211 should really provide a fixed
1488 * rate to use here. for now, just use the smallest
1489 * possible rate for the band as a fixed rate for
1490 * association frames and other control messages.
1491 */
1492 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1493 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001494
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001495 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1496 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001497 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001498 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001499 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001500
1501 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1502 ret = wl1271_join(wl, false);
1503 if (ret < 0)
1504 wl1271_warning("cmd join on channel "
1505 "failed %d", ret);
1506 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001507 }
1508 }
1509
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001510 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1511 ret = wl1271_sta_handle_idle(wl,
1512 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001513 if (ret < 0)
1514 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515 }
1516
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001517 /*
1518 * if mac80211 changes the PSM mode, make sure the mode is not
1519 * incorrectly changed after the pspoll failure active window.
1520 */
1521 if (changed & IEEE80211_CONF_CHANGE_PS)
1522 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1523
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001524 if (conf->flags & IEEE80211_CONF_PS &&
1525 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1526 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527
1528 /*
1529 * We enter PSM only if we're already associated.
1530 * If we're not, we'll enter it when joining an SSID,
1531 * through the bss_info_changed() hook.
1532 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001533 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001534 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001535 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001536 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001537 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001539 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001540 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001541
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001542 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001544 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001545 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001546 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 }
1548
1549 if (conf->power_level != wl->power_level) {
1550 ret = wl1271_acx_tx_power(wl, conf->power_level);
1551 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001552 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553
1554 wl->power_level = conf->power_level;
1555 }
1556
1557out_sleep:
1558 wl1271_ps_elp_sleep(wl);
1559
1560out:
1561 mutex_unlock(&wl->mutex);
1562
1563 return ret;
1564}
1565
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001566struct wl1271_filter_params {
1567 bool enabled;
1568 int mc_list_length;
1569 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1570};
1571
Jiri Pirko22bedad32010-04-01 21:22:57 +00001572static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1573 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001574{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001575 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001576 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001577 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001578
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001579 if (unlikely(wl->state == WL1271_STATE_OFF))
1580 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001581
Juuso Oikarinen74441132009-10-13 12:47:53 +03001582 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001583 if (!fp) {
1584 wl1271_error("Out of memory setting filters.");
1585 return 0;
1586 }
1587
1588 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001589 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001590 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1591 fp->enabled = false;
1592 } else {
1593 fp->enabled = true;
1594 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001595 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001596 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001597 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001598 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001599 }
1600
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001601 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001602}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001603
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001604#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1605 FIF_ALLMULTI | \
1606 FIF_FCSFAIL | \
1607 FIF_BCN_PRBRESP_PROMISC | \
1608 FIF_CONTROL | \
1609 FIF_OTHER_BSS)
1610
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1612 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001613 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001615 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001617 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001618
Arik Nemtsov7d057862010-10-16 19:25:35 +02001619 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1620 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001621
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001622 mutex_lock(&wl->mutex);
1623
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001624 *total &= WL1271_SUPPORTED_FILTERS;
1625 changed &= WL1271_SUPPORTED_FILTERS;
1626
1627 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001628 goto out;
1629
1630 ret = wl1271_ps_elp_wakeup(wl, false);
1631 if (ret < 0)
1632 goto out;
1633
Arik Nemtsov7d057862010-10-16 19:25:35 +02001634 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1635 if (*total & FIF_ALLMULTI)
1636 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1637 else if (fp)
1638 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1639 fp->mc_list,
1640 fp->mc_list_length);
1641 if (ret < 0)
1642 goto out_sleep;
1643 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001644
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001645 /* determine, whether supported filter values have changed */
1646 if (changed == 0)
1647 goto out_sleep;
1648
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001649 /* configure filters */
1650 wl->filters = *total;
1651 wl1271_configure_filters(wl, 0);
1652
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001653 /* apply configured filters */
1654 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1655 if (ret < 0)
1656 goto out_sleep;
1657
1658out_sleep:
1659 wl1271_ps_elp_sleep(wl);
1660
1661out:
1662 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001663 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664}
1665
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001666static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
1667 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
1668 u16 tx_seq_16)
1669{
1670 struct wl1271_ap_key *ap_key;
1671 int i;
1672
1673 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
1674
1675 if (key_size > MAX_KEY_SIZE)
1676 return -EINVAL;
1677
1678 /*
1679 * Find next free entry in ap_keys. Also check we are not replacing
1680 * an existing key.
1681 */
1682 for (i = 0; i < MAX_NUM_KEYS; i++) {
1683 if (wl->recorded_ap_keys[i] == NULL)
1684 break;
1685
1686 if (wl->recorded_ap_keys[i]->id == id) {
1687 wl1271_warning("trying to record key replacement");
1688 return -EINVAL;
1689 }
1690 }
1691
1692 if (i == MAX_NUM_KEYS)
1693 return -EBUSY;
1694
1695 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
1696 if (!ap_key)
1697 return -ENOMEM;
1698
1699 ap_key->id = id;
1700 ap_key->key_type = key_type;
1701 ap_key->key_size = key_size;
1702 memcpy(ap_key->key, key, key_size);
1703 ap_key->hlid = hlid;
1704 ap_key->tx_seq_32 = tx_seq_32;
1705 ap_key->tx_seq_16 = tx_seq_16;
1706
1707 wl->recorded_ap_keys[i] = ap_key;
1708 return 0;
1709}
1710
1711static void wl1271_free_ap_keys(struct wl1271 *wl)
1712{
1713 int i;
1714
1715 for (i = 0; i < MAX_NUM_KEYS; i++) {
1716 kfree(wl->recorded_ap_keys[i]);
1717 wl->recorded_ap_keys[i] = NULL;
1718 }
1719}
1720
1721static int wl1271_ap_init_hwenc(struct wl1271 *wl)
1722{
1723 int i, ret = 0;
1724 struct wl1271_ap_key *key;
1725 bool wep_key_added = false;
1726
1727 for (i = 0; i < MAX_NUM_KEYS; i++) {
1728 if (wl->recorded_ap_keys[i] == NULL)
1729 break;
1730
1731 key = wl->recorded_ap_keys[i];
1732 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
1733 key->id, key->key_type,
1734 key->key_size, key->key,
1735 key->hlid, key->tx_seq_32,
1736 key->tx_seq_16);
1737 if (ret < 0)
1738 goto out;
1739
1740 if (key->key_type == KEY_WEP)
1741 wep_key_added = true;
1742 }
1743
1744 if (wep_key_added) {
1745 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
1746 if (ret < 0)
1747 goto out;
1748 }
1749
1750out:
1751 wl1271_free_ap_keys(wl);
1752 return ret;
1753}
1754
1755static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
1756 u8 key_size, const u8 *key, u32 tx_seq_32,
1757 u16 tx_seq_16, struct ieee80211_sta *sta)
1758{
1759 int ret;
1760 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1761
1762 if (is_ap) {
1763 struct wl1271_station *wl_sta;
1764 u8 hlid;
1765
1766 if (sta) {
1767 wl_sta = (struct wl1271_station *)sta->drv_priv;
1768 hlid = wl_sta->hlid;
1769 } else {
1770 hlid = WL1271_AP_BROADCAST_HLID;
1771 }
1772
1773 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
1774 /*
1775 * We do not support removing keys after AP shutdown.
1776 * Pretend we do to make mac80211 happy.
1777 */
1778 if (action != KEY_ADD_OR_REPLACE)
1779 return 0;
1780
1781 ret = wl1271_record_ap_key(wl, id,
1782 key_type, key_size,
1783 key, hlid, tx_seq_32,
1784 tx_seq_16);
1785 } else {
1786 ret = wl1271_cmd_set_ap_key(wl, action,
1787 id, key_type, key_size,
1788 key, hlid, tx_seq_32,
1789 tx_seq_16);
1790 }
1791
1792 if (ret < 0)
1793 return ret;
1794 } else {
1795 const u8 *addr;
1796 static const u8 bcast_addr[ETH_ALEN] = {
1797 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
1798 };
1799
1800 addr = sta ? sta->addr : bcast_addr;
1801
1802 if (is_zero_ether_addr(addr)) {
1803 /* We dont support TX only encryption */
1804 return -EOPNOTSUPP;
1805 }
1806
1807 /* The wl1271 does not allow to remove unicast keys - they
1808 will be cleared automatically on next CMD_JOIN. Ignore the
1809 request silently, as we dont want the mac80211 to emit
1810 an error message. */
1811 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
1812 return 0;
1813
1814 ret = wl1271_cmd_set_sta_key(wl, action,
1815 id, key_type, key_size,
1816 key, addr, tx_seq_32,
1817 tx_seq_16);
1818 if (ret < 0)
1819 return ret;
1820
1821 /* the default WEP key needs to be configured at least once */
1822 if (key_type == KEY_WEP) {
1823 ret = wl1271_cmd_set_sta_default_wep_key(wl,
1824 wl->default_key);
1825 if (ret < 0)
1826 return ret;
1827 }
1828 }
1829
1830 return 0;
1831}
1832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1834 struct ieee80211_vif *vif,
1835 struct ieee80211_sta *sta,
1836 struct ieee80211_key_conf *key_conf)
1837{
1838 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001840 u32 tx_seq_32 = 0;
1841 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 u8 key_type;
1843
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1845
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001846 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001848 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 key_conf->keylen, key_conf->flags);
1850 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852 mutex_lock(&wl->mutex);
1853
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001854 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1855 ret = -EAGAIN;
1856 goto out_unlock;
1857 }
1858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 ret = wl1271_ps_elp_wakeup(wl, false);
1860 if (ret < 0)
1861 goto out_unlock;
1862
Johannes Berg97359d12010-08-10 09:46:38 +02001863 switch (key_conf->cipher) {
1864 case WLAN_CIPHER_SUITE_WEP40:
1865 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 key_type = KEY_WEP;
1867
1868 key_conf->hw_key_idx = key_conf->keyidx;
1869 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001870 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 key_type = KEY_TKIP;
1872
1873 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001874 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1875 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001876 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001877 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001878 key_type = KEY_AES;
1879
1880 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001881 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1882 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02001884 case WL1271_CIPHER_SUITE_GEM:
1885 key_type = KEY_GEM;
1886 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1887 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
1888 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001889 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001890 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891
1892 ret = -EOPNOTSUPP;
1893 goto out_sleep;
1894 }
1895
1896 switch (cmd) {
1897 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001898 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
1899 key_conf->keyidx, key_type,
1900 key_conf->keylen, key_conf->key,
1901 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902 if (ret < 0) {
1903 wl1271_error("Could not add or replace key");
1904 goto out_sleep;
1905 }
1906 break;
1907
1908 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001909 ret = wl1271_set_key(wl, KEY_REMOVE,
1910 key_conf->keyidx, key_type,
1911 key_conf->keylen, key_conf->key,
1912 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913 if (ret < 0) {
1914 wl1271_error("Could not remove key");
1915 goto out_sleep;
1916 }
1917 break;
1918
1919 default:
1920 wl1271_error("Unsupported key cmd 0x%x", cmd);
1921 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922 break;
1923 }
1924
1925out_sleep:
1926 wl1271_ps_elp_sleep(wl);
1927
1928out_unlock:
1929 mutex_unlock(&wl->mutex);
1930
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 return ret;
1932}
1933
1934static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001935 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 struct cfg80211_scan_request *req)
1937{
1938 struct wl1271 *wl = hw->priv;
1939 int ret;
1940 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001941 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942
1943 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1944
1945 if (req->n_ssids) {
1946 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001947 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 }
1949
1950 mutex_lock(&wl->mutex);
1951
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001952 if (wl->state == WL1271_STATE_OFF) {
1953 /*
1954 * We cannot return -EBUSY here because cfg80211 will expect
1955 * a call to ieee80211_scan_completed if we do - in this case
1956 * there won't be any call.
1957 */
1958 ret = -EAGAIN;
1959 goto out;
1960 }
1961
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 ret = wl1271_ps_elp_wakeup(wl, false);
1963 if (ret < 0)
1964 goto out;
1965
Luciano Coelho5924f892010-08-04 03:46:22 +03001966 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
1968 wl1271_ps_elp_sleep(wl);
1969
1970out:
1971 mutex_unlock(&wl->mutex);
1972
1973 return ret;
1974}
1975
Arik Nemtsov68d069c2010-11-08 10:51:07 +01001976static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
1977{
1978 struct wl1271 *wl = hw->priv;
1979 int ret = 0;
1980
1981 mutex_lock(&wl->mutex);
1982
1983 if (unlikely(wl->state == WL1271_STATE_OFF)) {
1984 ret = -EAGAIN;
1985 goto out;
1986 }
1987
1988 ret = wl1271_ps_elp_wakeup(wl, false);
1989 if (ret < 0)
1990 goto out;
1991
1992 ret = wl1271_acx_frag_threshold(wl, (u16)value);
1993 if (ret < 0)
1994 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
1995
1996 wl1271_ps_elp_sleep(wl);
1997
1998out:
1999 mutex_unlock(&wl->mutex);
2000
2001 return ret;
2002}
2003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2005{
2006 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002007 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008
2009 mutex_lock(&wl->mutex);
2010
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002011 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2012 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002013 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002014 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 ret = wl1271_ps_elp_wakeup(wl, false);
2017 if (ret < 0)
2018 goto out;
2019
2020 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2021 if (ret < 0)
2022 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2023
2024 wl1271_ps_elp_sleep(wl);
2025
2026out:
2027 mutex_unlock(&wl->mutex);
2028
2029 return ret;
2030}
2031
Arik Nemtsove78a2872010-10-16 19:07:21 +02002032static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002033 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002034{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002035 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002036
2037 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002038 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002039 if (ptr[0] == WLAN_EID_SSID) {
2040 wl->ssid_len = ptr[1];
2041 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002042 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002043 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002044 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002045 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002046
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002047 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002048 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002049}
2050
Arik Nemtsove78a2872010-10-16 19:07:21 +02002051static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2052 struct ieee80211_bss_conf *bss_conf,
2053 u32 changed)
2054{
2055 int ret = 0;
2056
2057 if (changed & BSS_CHANGED_ERP_SLOT) {
2058 if (bss_conf->use_short_slot)
2059 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2060 else
2061 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2062 if (ret < 0) {
2063 wl1271_warning("Set slot time failed %d", ret);
2064 goto out;
2065 }
2066 }
2067
2068 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2069 if (bss_conf->use_short_preamble)
2070 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2071 else
2072 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2073 }
2074
2075 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2076 if (bss_conf->use_cts_prot)
2077 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2078 else
2079 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2080 if (ret < 0) {
2081 wl1271_warning("Set ctsprotect failed %d", ret);
2082 goto out;
2083 }
2084 }
2085
2086out:
2087 return ret;
2088}
2089
2090static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2091 struct ieee80211_vif *vif,
2092 struct ieee80211_bss_conf *bss_conf,
2093 u32 changed)
2094{
2095 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2096 int ret = 0;
2097
2098 if ((changed & BSS_CHANGED_BEACON_INT)) {
2099 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2100 bss_conf->beacon_int);
2101
2102 wl->beacon_int = bss_conf->beacon_int;
2103 }
2104
2105 if ((changed & BSS_CHANGED_BEACON)) {
2106 struct ieee80211_hdr *hdr;
2107 int ieoffset = offsetof(struct ieee80211_mgmt,
2108 u.beacon.variable);
2109 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2110 u16 tmpl_id;
2111
2112 if (!beacon)
2113 goto out;
2114
2115 wl1271_debug(DEBUG_MASTER, "beacon updated");
2116
2117 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2118 if (ret < 0) {
2119 dev_kfree_skb(beacon);
2120 goto out;
2121 }
2122 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2123 CMD_TEMPL_BEACON;
2124 ret = wl1271_cmd_template_set(wl, tmpl_id,
2125 beacon->data,
2126 beacon->len, 0,
2127 wl1271_tx_min_rate_get(wl));
2128 if (ret < 0) {
2129 dev_kfree_skb(beacon);
2130 goto out;
2131 }
2132
2133 hdr = (struct ieee80211_hdr *) beacon->data;
2134 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2135 IEEE80211_STYPE_PROBE_RESP);
2136
2137 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2138 CMD_TEMPL_PROBE_RESPONSE;
2139 ret = wl1271_cmd_template_set(wl,
2140 tmpl_id,
2141 beacon->data,
2142 beacon->len, 0,
2143 wl1271_tx_min_rate_get(wl));
2144 dev_kfree_skb(beacon);
2145 if (ret < 0)
2146 goto out;
2147 }
2148
2149out:
2150 return ret;
2151}
2152
2153/* AP mode changes */
2154static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002155 struct ieee80211_vif *vif,
2156 struct ieee80211_bss_conf *bss_conf,
2157 u32 changed)
2158{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002159 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160
Arik Nemtsove78a2872010-10-16 19:07:21 +02002161 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2162 u32 rates = bss_conf->basic_rates;
2163 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164
Arik Nemtsove78a2872010-10-16 19:07:21 +02002165 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2166 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2167 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2168 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169
Arik Nemtsove78a2872010-10-16 19:07:21 +02002170 /* update the AP management rate policy with the new rates */
2171 mgmt_rc.enabled_rates = wl->basic_rate_set;
2172 mgmt_rc.long_retry_limit = 10;
2173 mgmt_rc.short_retry_limit = 10;
2174 mgmt_rc.aflags = 0;
2175 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2176 ACX_TX_AP_MODE_MGMT_RATE);
2177 if (ret < 0) {
2178 wl1271_error("AP mgmt policy change failed %d", ret);
2179 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002180 }
2181 }
2182
Arik Nemtsove78a2872010-10-16 19:07:21 +02002183 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2184 if (ret < 0)
2185 goto out;
2186
2187 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2188 if (bss_conf->enable_beacon) {
2189 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2190 ret = wl1271_cmd_start_bss(wl);
2191 if (ret < 0)
2192 goto out;
2193
2194 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2195 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002196
2197 ret = wl1271_ap_init_hwenc(wl);
2198 if (ret < 0)
2199 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002200 }
2201 } else {
2202 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2203 ret = wl1271_cmd_stop_bss(wl);
2204 if (ret < 0)
2205 goto out;
2206
2207 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2208 wl1271_debug(DEBUG_AP, "stopped AP");
2209 }
2210 }
2211 }
2212
2213 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2214 if (ret < 0)
2215 goto out;
2216out:
2217 return;
2218}
2219
2220/* STA/IBSS mode changes */
2221static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2222 struct ieee80211_vif *vif,
2223 struct ieee80211_bss_conf *bss_conf,
2224 u32 changed)
2225{
2226 bool do_join = false, set_assoc = false;
2227 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
2228 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002229 struct ieee80211_sta *sta;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002230
2231 if (is_ibss) {
2232 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2233 changed);
2234 if (ret < 0)
2235 goto out;
2236 }
2237
2238 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2239 do_join = true;
2240
2241 /* Need to update the SSID (for filtering etc) */
2242 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2243 do_join = true;
2244
2245 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002246 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2247 bss_conf->enable_beacon ? "enabled" : "disabled");
2248
2249 if (bss_conf->enable_beacon)
2250 wl->set_bss_type = BSS_TYPE_IBSS;
2251 else
2252 wl->set_bss_type = BSS_TYPE_STA_BSS;
2253 do_join = true;
2254 }
2255
Arik Nemtsove78a2872010-10-16 19:07:21 +02002256 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002257 bool enable = false;
2258 if (bss_conf->cqm_rssi_thold)
2259 enable = true;
2260 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2261 bss_conf->cqm_rssi_thold,
2262 bss_conf->cqm_rssi_hyst);
2263 if (ret < 0)
2264 goto out;
2265 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2266 }
2267
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002268 if ((changed & BSS_CHANGED_BSSID) &&
2269 /*
2270 * Now we know the correct bssid, so we send a new join command
2271 * and enable the BSSID filter
2272 */
2273 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002274 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002275
Eliad Pellerfa287b82010-12-26 09:27:50 +01002276 if (!is_zero_ether_addr(wl->bssid)) {
2277 ret = wl1271_cmd_build_null_data(wl);
2278 if (ret < 0)
2279 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002280
Eliad Pellerfa287b82010-12-26 09:27:50 +01002281 ret = wl1271_build_qos_null_data(wl);
2282 if (ret < 0)
2283 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002284
Eliad Pellerfa287b82010-12-26 09:27:50 +01002285 /* filter out all packets not from this BSSID */
2286 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002287
Eliad Pellerfa287b82010-12-26 09:27:50 +01002288 /* Need to update the BSSID (for filtering etc) */
2289 do_join = true;
2290 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002291 }
2292
Arik Nemtsove78a2872010-10-16 19:07:21 +02002293 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002294 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002295 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002296 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002298 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002300 wl->ps_poll_failures = 0;
2301
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002302 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002303 * use basic rates from AP, and determine lowest rate
2304 * to use with control frames.
2305 */
2306 rates = bss_conf->basic_rates;
2307 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2308 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002309 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002310 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002311 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002312 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002313
2314 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002315 * with wl1271, we don't need to update the
2316 * beacon_int and dtim_period, because the firmware
2317 * updates it by itself when the first beacon is
2318 * received after a join.
2319 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2321 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002322 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002324 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002325 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002326 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002327 dev_kfree_skb(wl->probereq);
2328 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2329 ieoffset = offsetof(struct ieee80211_mgmt,
2330 u.probe_req.variable);
2331 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002332
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002333 /* enable the connection monitoring feature */
2334 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002336 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337
2338 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002339 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2340 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002341 enum wl1271_cmd_ps_mode mode;
2342
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002344 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002345 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002346 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002348 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002350 } else {
2351 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002352 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002353 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002354 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002355
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002356 /* free probe-request template */
2357 dev_kfree_skb(wl->probereq);
2358 wl->probereq = NULL;
2359
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002360 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002361 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002362
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002363 /* revert back to minimum rates for the current band */
2364 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002365 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002366 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002367 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002368 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002369
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002370 /* disable connection monitor features */
2371 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002372
2373 /* Disable the keep-alive feature */
2374 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002375 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002376 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002377
2378 /* restore the bssid filter and go to dummy bssid */
2379 wl1271_unjoin(wl);
2380 wl1271_dummy_join(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002381 }
2382 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002383
Arik Nemtsove78a2872010-10-16 19:07:21 +02002384 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2385 if (ret < 0)
2386 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002388 rcu_read_lock();
2389 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2390 if (sta) {
2391 /* handle new association with HT and HT information change */
2392 if ((changed & BSS_CHANGED_HT) &&
2393 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
2394 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2395 true);
2396 if (ret < 0) {
2397 wl1271_warning("Set ht cap true failed %d",
2398 ret);
2399 rcu_read_unlock();
2400 goto out;
2401 }
Shahar Levi18357852010-10-13 16:09:41 +02002402 ret = wl1271_acx_set_ht_information(wl,
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002403 bss_conf->ht_operation_mode);
2404 if (ret < 0) {
2405 wl1271_warning("Set ht information failed %d",
2406 ret);
2407 rcu_read_unlock();
2408 goto out;
2409 }
2410 }
2411 /* handle new association without HT and disassociation */
2412 else if (changed & BSS_CHANGED_ASSOC) {
2413 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap,
2414 false);
2415 if (ret < 0) {
2416 wl1271_warning("Set ht cap false failed %d",
2417 ret);
2418 rcu_read_unlock();
2419 goto out;
2420 }
Shahar Levi18357852010-10-13 16:09:41 +02002421 }
2422 }
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002423 rcu_read_unlock();
Shahar Levi18357852010-10-13 16:09:41 +02002424
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002425 if (changed & BSS_CHANGED_ARP_FILTER) {
2426 __be32 addr = bss_conf->arp_addr_list[0];
2427 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2428
Eliad Pellerc5312772010-12-09 11:31:27 +02002429 if (bss_conf->arp_addr_cnt == 1 &&
2430 bss_conf->arp_filter_enabled) {
2431 /*
2432 * The template should have been configured only upon
2433 * association. however, it seems that the correct ip
2434 * isn't being set (when sending), so we have to
2435 * reconfigure the template upon every ip change.
2436 */
2437 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2438 if (ret < 0) {
2439 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002440 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002441 }
2442
2443 ret = wl1271_acx_arp_ip_filter(wl,
2444 (ACX_ARP_FILTER_ARP_FILTERING |
2445 ACX_ARP_FILTER_AUTO_ARP),
2446 addr);
2447 } else
2448 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002449
2450 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002451 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002452 }
2453
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002454 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002455 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002456 if (ret < 0) {
2457 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002458 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002459 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002460 }
2461
Arik Nemtsove78a2872010-10-16 19:07:21 +02002462out:
2463 return;
2464}
2465
2466static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2467 struct ieee80211_vif *vif,
2468 struct ieee80211_bss_conf *bss_conf,
2469 u32 changed)
2470{
2471 struct wl1271 *wl = hw->priv;
2472 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2473 int ret;
2474
2475 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2476 (int)changed);
2477
2478 mutex_lock(&wl->mutex);
2479
2480 if (unlikely(wl->state == WL1271_STATE_OFF))
2481 goto out;
2482
2483 ret = wl1271_ps_elp_wakeup(wl, false);
2484 if (ret < 0)
2485 goto out;
2486
2487 if (is_ap)
2488 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2489 else
2490 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2491
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002492 wl1271_ps_elp_sleep(wl);
2493
2494out:
2495 mutex_unlock(&wl->mutex);
2496}
2497
Kalle Valoc6999d82010-02-18 13:25:41 +02002498static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2499 const struct ieee80211_tx_queue_params *params)
2500{
2501 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002502 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002503 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002504
2505 mutex_lock(&wl->mutex);
2506
2507 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2508
Kalle Valo4695dc92010-03-18 12:26:38 +02002509 if (params->uapsd)
2510 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2511 else
2512 ps_scheme = CONF_PS_SCHEME_LEGACY;
2513
Arik Nemtsov488fc542010-10-16 20:33:45 +02002514 if (wl->state == WL1271_STATE_OFF) {
2515 /*
2516 * If the state is off, the parameters will be recorded and
2517 * configured on init. This happens in AP-mode.
2518 */
2519 struct conf_tx_ac_category *conf_ac =
2520 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2521 struct conf_tx_tid *conf_tid =
2522 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2523
2524 conf_ac->ac = wl1271_tx_get_queue(queue);
2525 conf_ac->cw_min = (u8)params->cw_min;
2526 conf_ac->cw_max = params->cw_max;
2527 conf_ac->aifsn = params->aifs;
2528 conf_ac->tx_op_limit = params->txop << 5;
2529
2530 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2531 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2532 conf_tid->tsid = wl1271_tx_get_queue(queue);
2533 conf_tid->ps_scheme = ps_scheme;
2534 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2535 conf_tid->apsd_conf[0] = 0;
2536 conf_tid->apsd_conf[1] = 0;
2537 } else {
2538 ret = wl1271_ps_elp_wakeup(wl, false);
2539 if (ret < 0)
2540 goto out;
2541
2542 /*
2543 * the txop is confed in units of 32us by the mac80211,
2544 * we need us
2545 */
2546 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2547 params->cw_min, params->cw_max,
2548 params->aifs, params->txop << 5);
2549 if (ret < 0)
2550 goto out_sleep;
2551
2552 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2553 CONF_CHANNEL_TYPE_EDCF,
2554 wl1271_tx_get_queue(queue),
2555 ps_scheme, CONF_ACK_POLICY_LEGACY,
2556 0, 0);
2557 if (ret < 0)
2558 goto out_sleep;
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002559
2560out_sleep:
Arik Nemtsov488fc542010-10-16 20:33:45 +02002561 wl1271_ps_elp_sleep(wl);
2562 }
Kalle Valoc6999d82010-02-18 13:25:41 +02002563
2564out:
2565 mutex_unlock(&wl->mutex);
2566
2567 return ret;
2568}
2569
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002570static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2571{
2572
2573 struct wl1271 *wl = hw->priv;
2574 u64 mactime = ULLONG_MAX;
2575 int ret;
2576
2577 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2578
2579 mutex_lock(&wl->mutex);
2580
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002581 if (unlikely(wl->state == WL1271_STATE_OFF))
2582 goto out;
2583
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002584 ret = wl1271_ps_elp_wakeup(wl, false);
2585 if (ret < 0)
2586 goto out;
2587
2588 ret = wl1271_acx_tsf_info(wl, &mactime);
2589 if (ret < 0)
2590 goto out_sleep;
2591
2592out_sleep:
2593 wl1271_ps_elp_sleep(wl);
2594
2595out:
2596 mutex_unlock(&wl->mutex);
2597 return mactime;
2598}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002599
John W. Linvilleece550d2010-07-28 16:41:06 -04002600static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2601 struct survey_info *survey)
2602{
2603 struct wl1271 *wl = hw->priv;
2604 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002605
John W. Linvilleece550d2010-07-28 16:41:06 -04002606 if (idx != 0)
2607 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002608
John W. Linvilleece550d2010-07-28 16:41:06 -04002609 survey->channel = conf->channel;
2610 survey->filled = SURVEY_INFO_NOISE_DBM;
2611 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002612
John W. Linvilleece550d2010-07-28 16:41:06 -04002613 return 0;
2614}
2615
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002616static int wl1271_allocate_hlid(struct wl1271 *wl,
2617 struct ieee80211_sta *sta,
2618 u8 *hlid)
2619{
2620 struct wl1271_station *wl_sta;
2621 int id;
2622
2623 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2624 if (id >= AP_MAX_STATIONS) {
2625 wl1271_warning("could not allocate HLID - too much stations");
2626 return -EBUSY;
2627 }
2628
2629 wl_sta = (struct wl1271_station *)sta->drv_priv;
2630
2631 __set_bit(id, wl->ap_hlid_map);
2632 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
2633 *hlid = wl_sta->hlid;
2634 return 0;
2635}
2636
2637static void wl1271_free_hlid(struct wl1271 *wl, u8 hlid)
2638{
2639 int id = hlid - WL1271_AP_STA_HLID_START;
2640
2641 __clear_bit(id, wl->ap_hlid_map);
2642}
2643
2644static int wl1271_op_sta_add(struct ieee80211_hw *hw,
2645 struct ieee80211_vif *vif,
2646 struct ieee80211_sta *sta)
2647{
2648 struct wl1271 *wl = hw->priv;
2649 int ret = 0;
2650 u8 hlid;
2651
2652 mutex_lock(&wl->mutex);
2653
2654 if (unlikely(wl->state == WL1271_STATE_OFF))
2655 goto out;
2656
2657 if (wl->bss_type != BSS_TYPE_AP_BSS)
2658 goto out;
2659
2660 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
2661
2662 ret = wl1271_allocate_hlid(wl, sta, &hlid);
2663 if (ret < 0)
2664 goto out;
2665
2666 ret = wl1271_ps_elp_wakeup(wl, false);
2667 if (ret < 0)
2668 goto out;
2669
2670 ret = wl1271_cmd_add_sta(wl, sta, hlid);
2671 if (ret < 0)
2672 goto out_sleep;
2673
2674out_sleep:
2675 wl1271_ps_elp_sleep(wl);
2676
2677out:
2678 mutex_unlock(&wl->mutex);
2679 return ret;
2680}
2681
2682static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
2683 struct ieee80211_vif *vif,
2684 struct ieee80211_sta *sta)
2685{
2686 struct wl1271 *wl = hw->priv;
2687 struct wl1271_station *wl_sta;
2688 int ret = 0, id;
2689
2690 mutex_lock(&wl->mutex);
2691
2692 if (unlikely(wl->state == WL1271_STATE_OFF))
2693 goto out;
2694
2695 if (wl->bss_type != BSS_TYPE_AP_BSS)
2696 goto out;
2697
2698 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
2699
2700 wl_sta = (struct wl1271_station *)sta->drv_priv;
2701 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
2702 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
2703 goto out;
2704
2705 ret = wl1271_ps_elp_wakeup(wl, false);
2706 if (ret < 0)
2707 goto out;
2708
2709 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
2710 if (ret < 0)
2711 goto out_sleep;
2712
2713 wl1271_free_hlid(wl, wl_sta->hlid);
2714
2715out_sleep:
2716 wl1271_ps_elp_sleep(wl);
2717
2718out:
2719 mutex_unlock(&wl->mutex);
2720 return ret;
2721}
2722
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002723/* can't be const, mac80211 writes to this */
2724static struct ieee80211_rate wl1271_rates[] = {
2725 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002726 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2727 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002729 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2730 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2732 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002733 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2734 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2736 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002737 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2738 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002739 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2740 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002741 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2742 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002744 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2745 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002746 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002747 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2748 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002750 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2751 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002753 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2754 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002755 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002756 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2757 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002759 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2760 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002762 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2763 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002764};
2765
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002766/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002767static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002768 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002769 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002770 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2771 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2772 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002773 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002774 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2775 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2776 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002777 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002778 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2779 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2780 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01002781 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782};
2783
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002784/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002785static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002786 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002787 7, /* CONF_HW_RXTX_RATE_MCS7 */
2788 6, /* CONF_HW_RXTX_RATE_MCS6 */
2789 5, /* CONF_HW_RXTX_RATE_MCS5 */
2790 4, /* CONF_HW_RXTX_RATE_MCS4 */
2791 3, /* CONF_HW_RXTX_RATE_MCS3 */
2792 2, /* CONF_HW_RXTX_RATE_MCS2 */
2793 1, /* CONF_HW_RXTX_RATE_MCS1 */
2794 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002795
2796 11, /* CONF_HW_RXTX_RATE_54 */
2797 10, /* CONF_HW_RXTX_RATE_48 */
2798 9, /* CONF_HW_RXTX_RATE_36 */
2799 8, /* CONF_HW_RXTX_RATE_24 */
2800
2801 /* TI-specific rate */
2802 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2803
2804 7, /* CONF_HW_RXTX_RATE_18 */
2805 6, /* CONF_HW_RXTX_RATE_12 */
2806 3, /* CONF_HW_RXTX_RATE_11 */
2807 5, /* CONF_HW_RXTX_RATE_9 */
2808 4, /* CONF_HW_RXTX_RATE_6 */
2809 2, /* CONF_HW_RXTX_RATE_5_5 */
2810 1, /* CONF_HW_RXTX_RATE_2 */
2811 0 /* CONF_HW_RXTX_RATE_1 */
2812};
2813
Shahar Levie8b03a22010-10-13 16:09:39 +02002814/* 11n STA capabilities */
2815#define HW_RX_HIGHEST_RATE 72
2816
Shahar Levi00d20102010-11-08 11:20:10 +00002817#ifdef CONFIG_WL12XX_HT
2818#define WL12XX_HT_CAP { \
Shahar Levie8b03a22010-10-13 16:09:39 +02002819 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
2820 .ht_supported = true, \
2821 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
2822 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
2823 .mcs = { \
2824 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
2825 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
2826 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
2827 }, \
2828}
Shahar Levi18357852010-10-13 16:09:41 +02002829#else
Shahar Levi00d20102010-11-08 11:20:10 +00002830#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02002831 .ht_supported = false, \
2832}
2833#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02002834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002835/* can't be const, mac80211 writes to this */
2836static struct ieee80211_supported_band wl1271_band_2ghz = {
2837 .channels = wl1271_channels,
2838 .n_channels = ARRAY_SIZE(wl1271_channels),
2839 .bitrates = wl1271_rates,
2840 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00002841 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002842};
2843
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002844/* 5 GHz data rates for WL1273 */
2845static struct ieee80211_rate wl1271_rates_5ghz[] = {
2846 { .bitrate = 60,
2847 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2848 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2849 { .bitrate = 90,
2850 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2851 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2852 { .bitrate = 120,
2853 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2854 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2855 { .bitrate = 180,
2856 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2857 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2858 { .bitrate = 240,
2859 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2860 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2861 { .bitrate = 360,
2862 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2863 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2864 { .bitrate = 480,
2865 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2866 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2867 { .bitrate = 540,
2868 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2869 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2870};
2871
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002872/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002873static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002874 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002875 { .hw_value = 8, .center_freq = 5040},
2876 { .hw_value = 9, .center_freq = 5045},
2877 { .hw_value = 11, .center_freq = 5055},
2878 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002879 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002880 { .hw_value = 34, .center_freq = 5170},
2881 { .hw_value = 36, .center_freq = 5180},
2882 { .hw_value = 38, .center_freq = 5190},
2883 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002884 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002885 { .hw_value = 44, .center_freq = 5220},
2886 { .hw_value = 46, .center_freq = 5230},
2887 { .hw_value = 48, .center_freq = 5240},
2888 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002889 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002890 { .hw_value = 60, .center_freq = 5300},
2891 { .hw_value = 64, .center_freq = 5320},
2892 { .hw_value = 100, .center_freq = 5500},
2893 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002894 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002895 { .hw_value = 112, .center_freq = 5560},
2896 { .hw_value = 116, .center_freq = 5580},
2897 { .hw_value = 120, .center_freq = 5600},
2898 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002899 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002900 { .hw_value = 132, .center_freq = 5660},
2901 { .hw_value = 136, .center_freq = 5680},
2902 { .hw_value = 140, .center_freq = 5700},
2903 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002904 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01002905 { .hw_value = 157, .center_freq = 5785},
2906 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002907 { .hw_value = 165, .center_freq = 5825},
2908};
2909
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002910/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002911static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002912 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02002913 7, /* CONF_HW_RXTX_RATE_MCS7 */
2914 6, /* CONF_HW_RXTX_RATE_MCS6 */
2915 5, /* CONF_HW_RXTX_RATE_MCS5 */
2916 4, /* CONF_HW_RXTX_RATE_MCS4 */
2917 3, /* CONF_HW_RXTX_RATE_MCS3 */
2918 2, /* CONF_HW_RXTX_RATE_MCS2 */
2919 1, /* CONF_HW_RXTX_RATE_MCS1 */
2920 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002921
2922 7, /* CONF_HW_RXTX_RATE_54 */
2923 6, /* CONF_HW_RXTX_RATE_48 */
2924 5, /* CONF_HW_RXTX_RATE_36 */
2925 4, /* CONF_HW_RXTX_RATE_24 */
2926
2927 /* TI-specific rate */
2928 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2929
2930 3, /* CONF_HW_RXTX_RATE_18 */
2931 2, /* CONF_HW_RXTX_RATE_12 */
2932 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2933 1, /* CONF_HW_RXTX_RATE_9 */
2934 0, /* CONF_HW_RXTX_RATE_6 */
2935 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2936 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2937 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2938};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002939
2940static struct ieee80211_supported_band wl1271_band_5ghz = {
2941 .channels = wl1271_channels_5ghz,
2942 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2943 .bitrates = wl1271_rates_5ghz,
2944 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00002945 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002946};
2947
Tobias Klausera0ea9492010-05-20 10:38:11 +02002948static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002949 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2950 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2951};
2952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953static const struct ieee80211_ops wl1271_ops = {
2954 .start = wl1271_op_start,
2955 .stop = wl1271_op_stop,
2956 .add_interface = wl1271_op_add_interface,
2957 .remove_interface = wl1271_op_remove_interface,
2958 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002959 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 .configure_filter = wl1271_op_configure_filter,
2961 .tx = wl1271_op_tx,
2962 .set_key = wl1271_op_set_key,
2963 .hw_scan = wl1271_op_hw_scan,
2964 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002965 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002967 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002968 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002969 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002970 .sta_add = wl1271_op_sta_add,
2971 .sta_remove = wl1271_op_sta_remove,
Kalle Valoc8c90872010-02-18 13:25:53 +02002972 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973};
2974
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002975
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002976u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002977{
2978 u8 idx;
2979
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002980 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002981
2982 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2983 wl1271_error("Illegal RX rate from HW: %d", rate);
2984 return 0;
2985 }
2986
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02002987 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002988 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2989 wl1271_error("Unsupported RX rate from HW: %d", rate);
2990 return 0;
2991 }
2992
2993 return idx;
2994}
2995
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002996static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2997 struct device_attribute *attr,
2998 char *buf)
2999{
3000 struct wl1271 *wl = dev_get_drvdata(dev);
3001 ssize_t len;
3002
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003003 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003004
3005 mutex_lock(&wl->mutex);
3006 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3007 wl->sg_enabled);
3008 mutex_unlock(&wl->mutex);
3009
3010 return len;
3011
3012}
3013
3014static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3015 struct device_attribute *attr,
3016 const char *buf, size_t count)
3017{
3018 struct wl1271 *wl = dev_get_drvdata(dev);
3019 unsigned long res;
3020 int ret;
3021
3022 ret = strict_strtoul(buf, 10, &res);
3023
3024 if (ret < 0) {
3025 wl1271_warning("incorrect value written to bt_coex_mode");
3026 return count;
3027 }
3028
3029 mutex_lock(&wl->mutex);
3030
3031 res = !!res;
3032
3033 if (res == wl->sg_enabled)
3034 goto out;
3035
3036 wl->sg_enabled = res;
3037
3038 if (wl->state == WL1271_STATE_OFF)
3039 goto out;
3040
3041 ret = wl1271_ps_elp_wakeup(wl, false);
3042 if (ret < 0)
3043 goto out;
3044
3045 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3046 wl1271_ps_elp_sleep(wl);
3047
3048 out:
3049 mutex_unlock(&wl->mutex);
3050 return count;
3051}
3052
3053static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3054 wl1271_sysfs_show_bt_coex_state,
3055 wl1271_sysfs_store_bt_coex_state);
3056
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003057static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3058 struct device_attribute *attr,
3059 char *buf)
3060{
3061 struct wl1271 *wl = dev_get_drvdata(dev);
3062 ssize_t len;
3063
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003064 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003065
3066 mutex_lock(&wl->mutex);
3067 if (wl->hw_pg_ver >= 0)
3068 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3069 else
3070 len = snprintf(buf, len, "n/a\n");
3071 mutex_unlock(&wl->mutex);
3072
3073 return len;
3074}
3075
3076static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3077 wl1271_sysfs_show_hw_pg_ver, NULL);
3078
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003079int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080{
3081 int ret;
3082
3083 if (wl->mac80211_registered)
3084 return 0;
3085
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003086 ret = wl1271_fetch_nvs(wl);
3087 if (ret == 0) {
3088 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
3089
3090 wl->mac_addr[0] = nvs_ptr[11];
3091 wl->mac_addr[1] = nvs_ptr[10];
3092 wl->mac_addr[2] = nvs_ptr[6];
3093 wl->mac_addr[3] = nvs_ptr[5];
3094 wl->mac_addr[4] = nvs_ptr[4];
3095 wl->mac_addr[5] = nvs_ptr[3];
3096 }
3097
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003098 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3099
3100 ret = ieee80211_register_hw(wl->hw);
3101 if (ret < 0) {
3102 wl1271_error("unable to register mac80211 hw: %d", ret);
3103 return ret;
3104 }
3105
3106 wl->mac80211_registered = true;
3107
Eliad Pellerd60080a2010-11-24 12:53:16 +02003108 wl1271_debugfs_init(wl);
3109
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003110 register_netdevice_notifier(&wl1271_dev_notifier);
3111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112 wl1271_notice("loaded");
3113
3114 return 0;
3115}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003116EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003117
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003118void wl1271_unregister_hw(struct wl1271 *wl)
3119{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003120 if (wl->state == WL1271_STATE_PLT)
3121 __wl1271_plt_stop(wl);
3122
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003123 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003124 ieee80211_unregister_hw(wl->hw);
3125 wl->mac80211_registered = false;
3126
3127}
3128EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3129
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003130int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003132 static const u32 cipher_suites[] = {
3133 WLAN_CIPHER_SUITE_WEP40,
3134 WLAN_CIPHER_SUITE_WEP104,
3135 WLAN_CIPHER_SUITE_TKIP,
3136 WLAN_CIPHER_SUITE_CCMP,
3137 WL1271_CIPHER_SUITE_GEM,
3138 };
3139
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003140 /* The tx descriptor buffer and the TKIP space. */
3141 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3142 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003143
3144 /* unit us */
3145 /* FIXME: find a proper value */
3146 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003147 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003148
3149 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003150 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003151 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003152 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003153 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003154 IEEE80211_HW_CONNECTION_MONITOR |
3155 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003156
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003157 wl->hw->wiphy->cipher_suites = cipher_suites;
3158 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3159
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003160 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003161 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003163 /*
3164 * Maximum length of elements in scanning probe request templates
3165 * should be the maximum length possible for a template, without
3166 * the IEEE80211 header of the template
3167 */
3168 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3169 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003170
3171 /*
3172 * We keep local copies of the band structs because we need to
3173 * modify them on a per-device basis.
3174 */
3175 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3176 sizeof(wl1271_band_2ghz));
3177 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3178 sizeof(wl1271_band_5ghz));
3179
3180 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3181 &wl->bands[IEEE80211_BAND_2GHZ];
3182 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3183 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003184
Kalle Valo12bd8942010-03-18 12:26:33 +02003185 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003186 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003187
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003188 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3189
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003190 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003191
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003192 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3193
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003194 wl->hw->max_rx_aggregation_subframes = 8;
3195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196 return 0;
3197}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003198EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003200#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003201
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003202struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003203{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003204 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003205 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003207 int i, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003208 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003209
3210 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3211 if (!hw) {
3212 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003213 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003214 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003215 }
3216
Julia Lawall929ebd32010-05-15 23:16:39 +02003217 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003218 if (!plat_dev) {
3219 wl1271_error("could not allocate platform_device");
3220 ret = -ENOMEM;
3221 goto err_plat_alloc;
3222 }
3223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003224 wl = hw->priv;
3225 memset(wl, 0, sizeof(*wl));
3226
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003227 INIT_LIST_HEAD(&wl->list);
3228
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003229 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003230 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003232 for (i = 0; i < NUM_TX_QUEUES; i++)
3233 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003234
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003235 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003236 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003237 INIT_WORK(&wl->irq_work, wl1271_irq_work);
3238 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3239 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3240 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003241 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003242 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003244 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003245 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3246 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003247 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003248 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003249 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003250 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003251 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
3252 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003253 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003254 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003255 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003256 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003257 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003258 wl->bss_type = MAX_BSS_TYPE;
3259 wl->set_bss_type = MAX_BSS_TYPE;
3260 wl->fw_bss_type = MAX_BSS_TYPE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003261
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003262 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003263 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003264 wl->tx_frames[i] = NULL;
3265
3266 spin_lock_init(&wl->wl_lock);
3267
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268 wl->state = WL1271_STATE_OFF;
3269 mutex_init(&wl->mutex);
3270
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003271 /* Apply default driver configuration. */
3272 wl1271_conf_init(wl);
3273
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003274 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3275 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3276 if (!wl->aggr_buf) {
3277 ret = -ENOMEM;
3278 goto err_hw;
3279 }
3280
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003281 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003282 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003283 if (ret) {
3284 wl1271_error("couldn't register platform device");
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003285 goto err_aggr;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003286 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003287 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003288
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003289 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003290 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003291 if (ret < 0) {
3292 wl1271_error("failed to create sysfs file bt_coex_state");
3293 goto err_platform;
3294 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003295
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003296 /* Create sysfs file to get HW PG version */
3297 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3298 if (ret < 0) {
3299 wl1271_error("failed to create sysfs file hw_pg_ver");
3300 goto err_bt_coex_state;
3301 }
3302
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003303 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003304
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003305err_bt_coex_state:
3306 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3307
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003308err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003309 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003310
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003311err_aggr:
3312 free_pages((unsigned long)wl->aggr_buf, order);
3313
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003314err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003315 wl1271_debugfs_exit(wl);
3316 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003317
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003318err_plat_alloc:
3319 ieee80211_free_hw(hw);
3320
3321err_hw_alloc:
3322
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003323 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003324}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003325EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003326
3327int wl1271_free_hw(struct wl1271 *wl)
3328{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003329 platform_device_unregister(wl->plat_dev);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003330 free_pages((unsigned long)wl->aggr_buf,
3331 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003332 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003333
3334 wl1271_debugfs_exit(wl);
3335
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003336 vfree(wl->fw);
3337 wl->fw = NULL;
3338 kfree(wl->nvs);
3339 wl->nvs = NULL;
3340
3341 kfree(wl->fw_status);
3342 kfree(wl->tx_res_if);
3343
3344 ieee80211_free_hw(wl->hw);
3345
3346 return 0;
3347}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003348EXPORT_SYMBOL_GPL(wl1271_free_hw);
3349
Guy Eilam491bbd62011-01-12 10:33:29 +01003350u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003351EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003352module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003353MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3354
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003355MODULE_LICENSE("GPL");
3356MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
3357MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");