blob: 81f92a0100d97a18d710f5acb66d3626e33296ab [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
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_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,
119 .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,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
127 [0] = {
128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
134 [1] = {
135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
141 [2] = {
142 .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 },
148 [3] = {
149 .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 },
156 .tid_conf_count = 7,
157 .tid_conf = {
158 [0] = {
159 .queue_id = 0,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
166 [1] = {
167 .queue_id = 1,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
174 [2] = {
175 .queue_id = 2,
176 .channel_type = CONF_CHANNEL_TYPE_DCF,
177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
182 [3] = {
183 .queue_id = 3,
184 .channel_type = CONF_CHANNEL_TYPE_DCF,
185 .tsid = CONF_TX_AC_BE,
186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
190 [4] = {
191 .queue_id = 4,
192 .channel_type = CONF_CHANNEL_TYPE_DCF,
193 .tsid = CONF_TX_AC_BE,
194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
198 [5] = {
199 .queue_id = 5,
200 .channel_type = CONF_CHANNEL_TYPE_DCF,
201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
206 [6] = {
207 .queue_id = 6,
208 .channel_type = CONF_CHANNEL_TYPE_DCF,
209 .tsid = CONF_TX_AC_BE,
210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 }
214 },
215 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200216 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300217 .tx_compl_threshold = 4,
218 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
219 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300224 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
225 .bcn_filt_ie_count = 1,
226 .bcn_filt_ie = {
227 [0] = {
228 .ie = WLAN_EID_CHANNEL_SWITCH,
229 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
230 }
231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200240 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200241 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 .trigger_pacing = 1,
255 .avg_weight_rssi_beacon = 20,
256 .avg_weight_rssi_data = 10,
257 .avg_weight_snr_beacon = 20,
258 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 }
260};
261
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200262static void wl1271_device_release(struct device *dev)
263{
264
265}
266
267static struct platform_device wl1271_device = {
268 .name = "wl1271",
269 .id = -1,
270
271 /* device model insists to have a release function */
272 .dev = {
273 .release = wl1271_device_release,
274 },
275};
276
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300277static LIST_HEAD(wl_list);
278
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300279static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
280 void *arg)
281{
282 struct net_device *dev = arg;
283 struct wireless_dev *wdev;
284 struct wiphy *wiphy;
285 struct ieee80211_hw *hw;
286 struct wl1271 *wl;
287 struct wl1271 *wl_temp;
288 int ret = 0;
289
290 /* Check that this notification is for us. */
291 if (what != NETDEV_CHANGE)
292 return NOTIFY_DONE;
293
294 wdev = dev->ieee80211_ptr;
295 if (wdev == NULL)
296 return NOTIFY_DONE;
297
298 wiphy = wdev->wiphy;
299 if (wiphy == NULL)
300 return NOTIFY_DONE;
301
302 hw = wiphy_priv(wiphy);
303 if (hw == NULL)
304 return NOTIFY_DONE;
305
306 wl_temp = hw->priv;
307 list_for_each_entry(wl, &wl_list, list) {
308 if (wl == wl_temp)
309 break;
310 }
311 if (wl != wl_temp)
312 return NOTIFY_DONE;
313
314 mutex_lock(&wl->mutex);
315
316 if (wl->state == WL1271_STATE_OFF)
317 goto out;
318
319 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
320 goto out;
321
322 ret = wl1271_ps_elp_wakeup(wl, false);
323 if (ret < 0)
324 goto out;
325
326 if ((dev->operstate == IF_OPER_UP) &&
327 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
328 wl1271_cmd_set_sta_state(wl);
329 wl1271_info("Association completed.");
330 }
331
332 wl1271_ps_elp_sleep(wl);
333
334out:
335 mutex_unlock(&wl->mutex);
336
337 return NOTIFY_OK;
338}
339
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300340static void wl1271_conf_init(struct wl1271 *wl)
341{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300342
343 /*
344 * This function applies the default configuration to the driver. This
345 * function is invoked upon driver load (spi probe.)
346 *
347 * The configuration is stored in a run-time structure in order to
348 * facilitate for run-time adjustment of any of the parameters. Making
349 * changes to the configuration structure will apply the new values on
350 * the next interface up (wl1271_op_start.)
351 */
352
353 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300354 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300355}
356
357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300358static int wl1271_plt_init(struct wl1271 *wl)
359{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200360 struct conf_tx_ac_category *conf_ac;
361 struct conf_tx_tid *conf_tid;
362 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300363
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200364 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200365 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200366 return ret;
367
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200368 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200369 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200370 return ret;
371
Luciano Coelho12419cc2010-02-18 13:25:44 +0200372 ret = wl1271_init_templates_config(wl);
373 if (ret < 0)
374 return ret;
375
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300376 ret = wl1271_acx_init_mem_config(wl);
377 if (ret < 0)
378 return ret;
379
Luciano Coelho12419cc2010-02-18 13:25:44 +0200380 /* PHY layer config */
381 ret = wl1271_init_phy_config(wl);
382 if (ret < 0)
383 goto out_free_memmap;
384
385 ret = wl1271_acx_dco_itrim_params(wl);
386 if (ret < 0)
387 goto out_free_memmap;
388
389 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200390 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200391 if (ret < 0)
392 goto out_free_memmap;
393
394 /* Bluetooth WLAN coexistence */
395 ret = wl1271_init_pta(wl);
396 if (ret < 0)
397 goto out_free_memmap;
398
399 /* Energy detection */
400 ret = wl1271_init_energy_detection(wl);
401 if (ret < 0)
402 goto out_free_memmap;
403
404 /* Default fragmentation threshold */
405 ret = wl1271_acx_frag_threshold(wl);
406 if (ret < 0)
407 goto out_free_memmap;
408
409 /* Default TID configuration */
410 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
411 conf_tid = &wl->conf.tx.tid_conf[i];
412 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
413 conf_tid->channel_type,
414 conf_tid->tsid,
415 conf_tid->ps_scheme,
416 conf_tid->ack_policy,
417 conf_tid->apsd_conf[0],
418 conf_tid->apsd_conf[1]);
419 if (ret < 0)
420 goto out_free_memmap;
421 }
422
423 /* Default AC configuration */
424 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
425 conf_ac = &wl->conf.tx.ac_conf[i];
426 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
427 conf_ac->cw_max, conf_ac->aifsn,
428 conf_ac->tx_op_limit);
429 if (ret < 0)
430 goto out_free_memmap;
431 }
432
433 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200434 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200436 goto out_free_memmap;
437
438 /* Configure for CAM power saving (ie. always active) */
439 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
440 if (ret < 0)
441 goto out_free_memmap;
442
443 /* configure PM */
444 ret = wl1271_acx_pm_config(wl);
445 if (ret < 0)
446 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300447
448 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200449
450 out_free_memmap:
451 kfree(wl->target_mem_map);
452 wl->target_mem_map = NULL;
453
454 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300455}
456
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300457static void wl1271_fw_status(struct wl1271 *wl,
458 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200460 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300461 u32 total = 0;
462 int i;
463
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200464 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300465
466 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
467 "drv_rx_counter = %d, tx_results_counter = %d)",
468 status->intr,
469 status->fw_rx_counter,
470 status->drv_rx_counter,
471 status->tx_results_counter);
472
473 /* update number of available TX blocks */
474 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300475 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
476 wl->tx_blocks_freed[i];
477
478 wl->tx_blocks_freed[i] =
479 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300480 wl->tx_blocks_available += cnt;
481 total += cnt;
482 }
483
484 /* if more blocks are available now, schedule some tx work */
485 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300486 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300487
488 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200489 getnstimeofday(&ts);
490 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
491 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300492}
493
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200494#define WL1271_IRQ_MAX_LOOPS 10
495
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300496static void wl1271_irq_work(struct work_struct *work)
497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300499 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200500 int loopcount = WL1271_IRQ_MAX_LOOPS;
501 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300502 struct wl1271 *wl =
503 container_of(work, struct wl1271, irq_work);
504
505 mutex_lock(&wl->mutex);
506
507 wl1271_debug(DEBUG_IRQ, "IRQ work");
508
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200509 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510 goto out;
511
512 ret = wl1271_ps_elp_wakeup(wl, true);
513 if (ret < 0)
514 goto out;
515
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200516 spin_lock_irqsave(&wl->wl_lock, flags);
517 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
518 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
519 spin_unlock_irqrestore(&wl->wl_lock, flags);
520 loopcount--;
521
522 wl1271_fw_status(wl, wl->fw_status);
523 intr = le32_to_cpu(wl->fw_status->intr);
524 if (!intr) {
525 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200526 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200527 continue;
528 }
529
530 intr &= WL1271_INTR_MASK;
531
532 if (intr & WL1271_ACX_INTR_DATA) {
533 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
534
535 /* check for tx results */
536 if (wl->fw_status->tx_results_counter !=
537 (wl->tx_results_count & 0xff))
538 wl1271_tx_complete(wl);
539
540 wl1271_rx(wl, wl->fw_status);
541 }
542
543 if (intr & WL1271_ACX_INTR_EVENT_A) {
544 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
545 wl1271_event_handle(wl, 0);
546 }
547
548 if (intr & WL1271_ACX_INTR_EVENT_B) {
549 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
550 wl1271_event_handle(wl, 1);
551 }
552
553 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
554 wl1271_debug(DEBUG_IRQ,
555 "WL1271_ACX_INTR_INIT_COMPLETE");
556
557 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
558 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
559
560 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561 }
562
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200563 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
564 ieee80211_queue_work(wl->hw, &wl->irq_work);
565 else
566 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
567 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300568
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300569 wl1271_ps_elp_sleep(wl);
570
571out:
572 mutex_unlock(&wl->mutex);
573}
574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575static int wl1271_fetch_firmware(struct wl1271 *wl)
576{
577 const struct firmware *fw;
578 int ret;
579
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200580 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300581
582 if (ret < 0) {
583 wl1271_error("could not get firmware: %d", ret);
584 return ret;
585 }
586
587 if (fw->size % 4) {
588 wl1271_error("firmware size is not multiple of 32 bits: %zu",
589 fw->size);
590 ret = -EILSEQ;
591 goto out;
592 }
593
594 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300595 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596
597 if (!wl->fw) {
598 wl1271_error("could not allocate memory for the firmware");
599 ret = -ENOMEM;
600 goto out;
601 }
602
603 memcpy(wl->fw, fw->data, wl->fw_len);
604
605 ret = 0;
606
607out:
608 release_firmware(fw);
609
610 return ret;
611}
612
613static int wl1271_fetch_nvs(struct wl1271 *wl)
614{
615 const struct firmware *fw;
616 int ret;
617
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200618 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619
620 if (ret < 0) {
621 wl1271_error("could not get nvs file: %d", ret);
622 return ret;
623 }
624
Julia Lawall929ebd32010-05-15 23:16:39 +0200625 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 if (!wl->nvs) {
628 wl1271_error("could not allocate memory for the nvs file");
629 ret = -ENOMEM;
630 goto out;
631 }
632
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200633 wl->nvs_len = fw->size;
634
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635out:
636 release_firmware(fw);
637
638 return ret;
639}
640
641static void wl1271_fw_wakeup(struct wl1271 *wl)
642{
643 u32 elp_reg;
644
645 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300646 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300647}
648
649static int wl1271_setup(struct wl1271 *wl)
650{
651 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
652 if (!wl->fw_status)
653 return -ENOMEM;
654
655 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
656 if (!wl->tx_res_if) {
657 kfree(wl->fw_status);
658 return -ENOMEM;
659 }
660
661 INIT_WORK(&wl->irq_work, wl1271_irq_work);
662 INIT_WORK(&wl->tx_work, wl1271_tx_work);
663 return 0;
664}
665
666static int wl1271_chip_wakeup(struct wl1271 *wl)
667{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300668 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 int ret = 0;
670
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200671 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +0200672 ret = wl1271_power_on(wl);
673 if (ret < 0)
674 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200676 wl1271_io_reset(wl);
677 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678
679 /* We don't need a real memory partition here, because we only want
680 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300681 memset(&partition, 0, sizeof(partition));
682 partition.reg.start = REGISTERS_BASE;
683 partition.reg.size = REGISTERS_DOWN_SIZE;
684 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685
686 /* ELP module wake up */
687 wl1271_fw_wakeup(wl);
688
689 /* whal_FwCtrl_BootSm() */
690
691 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200692 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693
694 /* 1. check if chip id is valid */
695
696 switch (wl->chip.id) {
697 case CHIP_ID_1271_PG10:
698 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
699 wl->chip.id);
700
701 ret = wl1271_setup(wl);
702 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200703 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704 break;
705 case CHIP_ID_1271_PG20:
706 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
707 wl->chip.id);
708
709 ret = wl1271_setup(wl);
710 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200711 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 break;
713 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300715 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200716 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717 }
718
719 if (wl->fw == NULL) {
720 ret = wl1271_fetch_firmware(wl);
721 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200722 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723 }
724
725 /* No NVS from netlink, try to get it from the filesystem */
726 if (wl->nvs == NULL) {
727 ret = wl1271_fetch_nvs(wl);
728 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200729 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300730 }
731
732out:
733 return ret;
734}
735
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736int wl1271_plt_start(struct wl1271 *wl)
737{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200738 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739 int ret;
740
741 mutex_lock(&wl->mutex);
742
743 wl1271_notice("power up");
744
745 if (wl->state != WL1271_STATE_OFF) {
746 wl1271_error("cannot go into PLT state because not "
747 "in off state: %d", wl->state);
748 ret = -EBUSY;
749 goto out;
750 }
751
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200752 while (retries) {
753 retries--;
754 ret = wl1271_chip_wakeup(wl);
755 if (ret < 0)
756 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300757
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200758 ret = wl1271_boot(wl);
759 if (ret < 0)
760 goto power_off;
761
762 ret = wl1271_plt_init(wl);
763 if (ret < 0)
764 goto irq_disable;
765
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200766 wl->state = WL1271_STATE_PLT;
767 wl1271_notice("firmware booted in PLT mode (%s)",
768 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300769 goto out;
770
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200771irq_disable:
772 wl1271_disable_interrupts(wl);
773 mutex_unlock(&wl->mutex);
774 /* Unlocking the mutex in the middle of handling is
775 inherently unsafe. In this case we deem it safe to do,
776 because we need to let any possibly pending IRQ out of
777 the system (and while we are WL1271_STATE_OFF the IRQ
778 work function will not do anything.) Also, any other
779 possible concurrent operations will fail due to the
780 current state, hence the wl1271 struct should be safe. */
781 cancel_work_sync(&wl->irq_work);
782 mutex_lock(&wl->mutex);
783power_off:
784 wl1271_power_off(wl);
785 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200787 wl1271_error("firmware boot in PLT mode failed despite %d retries",
788 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789out:
790 mutex_unlock(&wl->mutex);
791
792 return ret;
793}
794
795int wl1271_plt_stop(struct wl1271 *wl)
796{
797 int ret = 0;
798
799 mutex_lock(&wl->mutex);
800
801 wl1271_notice("power down");
802
803 if (wl->state != WL1271_STATE_PLT) {
804 wl1271_error("cannot power down because not in PLT "
805 "state: %d", wl->state);
806 ret = -EBUSY;
807 goto out;
808 }
809
810 wl1271_disable_interrupts(wl);
811 wl1271_power_off(wl);
812
813 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300814 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815
816out:
817 mutex_unlock(&wl->mutex);
818
819 return ret;
820}
821
822
823static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
824{
825 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200826 struct ieee80211_conf *conf = &hw->conf;
827 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
828 struct ieee80211_sta *sta = txinfo->control.sta;
829 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200831 /* peek into the rates configured in the STA entry */
832 spin_lock_irqsave(&wl->wl_lock, flags);
833 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
834 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
835 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
836 }
837 spin_unlock_irqrestore(&wl->wl_lock, flags);
838
839 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840 skb_queue_tail(&wl->tx_queue, skb);
841
842 /*
843 * The chip specific setup must run before the first TX packet -
844 * before that, the tx_work will not be initialized!
845 */
846
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300847 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848
849 /*
850 * The workqueue is slow to process the tx_queue and we need stop
851 * the queue here, otherwise the queue will get too long.
852 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200853 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
854 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300855
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200856 spin_lock_irqsave(&wl->wl_lock, flags);
857 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200858 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200859 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300860 }
861
862 return NETDEV_TX_OK;
863}
864
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300865static struct notifier_block wl1271_dev_notifier = {
866 .notifier_call = wl1271_dev_notify,
867};
868
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869static int wl1271_op_start(struct ieee80211_hw *hw)
870{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200871 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
872
873 /*
874 * We have to delay the booting of the hardware because
875 * we need to know the local MAC address before downloading and
876 * initializing the firmware. The MAC address cannot be changed
877 * after boot, and without the proper MAC address, the firmware
878 * will not function properly.
879 *
880 * The MAC address is first known when the corresponding interface
881 * is added. That is where we will initialize the hardware.
882 */
883
884 return 0;
885}
886
887static void wl1271_op_stop(struct ieee80211_hw *hw)
888{
889 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
890}
891
892static int wl1271_op_add_interface(struct ieee80211_hw *hw,
893 struct ieee80211_vif *vif)
894{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -0400896 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200897 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 int ret = 0;
899
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200900 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
901 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200904 if (wl->vif) {
905 ret = -EBUSY;
906 goto out;
907 }
908
909 wl->vif = vif;
910
911 switch (vif->type) {
912 case NL80211_IFTYPE_STATION:
913 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200914 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200915 break;
916 case NL80211_IFTYPE_ADHOC:
917 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200918 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200919 break;
920 default:
921 ret = -EOPNOTSUPP;
922 goto out;
923 }
924
925 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926
927 if (wl->state != WL1271_STATE_OFF) {
928 wl1271_error("cannot start because not in off state: %d",
929 wl->state);
930 ret = -EBUSY;
931 goto out;
932 }
933
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200934 while (retries) {
935 retries--;
936 ret = wl1271_chip_wakeup(wl);
937 if (ret < 0)
938 goto power_off;
939
940 ret = wl1271_boot(wl);
941 if (ret < 0)
942 goto power_off;
943
944 ret = wl1271_hw_init(wl);
945 if (ret < 0)
946 goto irq_disable;
947
948 wl->state = WL1271_STATE_ON;
949 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
John W. Linvilleac01e942010-07-28 17:09:41 -0400950
951 /* update hw/fw version info in wiphy struct */
952 wiphy->hw_version = wl->chip.id;
953 strncpy(wiphy->fw_version, wl->chip.fw_ver,
954 sizeof(wiphy->fw_version));
955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 goto out;
957
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200958irq_disable:
959 wl1271_disable_interrupts(wl);
960 mutex_unlock(&wl->mutex);
961 /* Unlocking the mutex in the middle of handling is
962 inherently unsafe. In this case we deem it safe to do,
963 because we need to let any possibly pending IRQ out of
964 the system (and while we are WL1271_STATE_OFF the IRQ
965 work function will not do anything.) Also, any other
966 possible concurrent operations will fail due to the
967 current state, hence the wl1271 struct should be safe. */
968 cancel_work_sync(&wl->irq_work);
969 mutex_lock(&wl->mutex);
970power_off:
971 wl1271_power_off(wl);
972 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200974 wl1271_error("firmware boot failed despite %d retries",
975 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300976out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 mutex_unlock(&wl->mutex);
978
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300979 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300980 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 return ret;
983}
984
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200985static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
986 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300987{
988 struct wl1271 *wl = hw->priv;
989 int i;
990
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200991 mutex_lock(&wl->mutex);
992 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200994 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300996 list_del(&wl->list);
997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 WARN_ON(wl->state != WL1271_STATE_ON);
999
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001000 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001001 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001002 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001003
Luciano Coelho08688d62010-07-08 17:50:07 +03001004 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001005 wl->scan.state = WL1271_SCAN_STATE_IDLE;
1006 kfree(wl->scan.scanned_ch);
1007 wl->scan.scanned_ch = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001008 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 }
1010
1011 wl->state = WL1271_STATE_OFF;
1012
1013 wl1271_disable_interrupts(wl);
1014
1015 mutex_unlock(&wl->mutex);
1016
1017 cancel_work_sync(&wl->irq_work);
1018 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001019 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020
1021 mutex_lock(&wl->mutex);
1022
1023 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001024 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 wl1271_power_off(wl);
1026
1027 memset(wl->bssid, 0, ETH_ALEN);
1028 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1029 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001031 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001032 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033
1034 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001035 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1037 wl->tx_blocks_available = 0;
1038 wl->tx_results_count = 0;
1039 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001040 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001041 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 wl->time_offset = 0;
1043 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001044 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1045 wl->sta_rate_set = 0;
1046 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001047 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001048 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001049
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 for (i = 0; i < NUM_TX_QUEUES; i++)
1051 wl->tx_blocks_freed[i] = 0;
1052
1053 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001054
1055 kfree(wl->fw_status);
1056 wl->fw_status = NULL;
1057 kfree(wl->tx_res_if);
1058 wl->tx_res_if = NULL;
1059 kfree(wl->target_mem_map);
1060 wl->target_mem_map = NULL;
1061
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 mutex_unlock(&wl->mutex);
1063}
1064
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001065static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1066{
1067 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1068 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1069
1070 /* combine requested filters with current filter config */
1071 filters = wl->filters | filters;
1072
1073 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1074
1075 if (filters & FIF_PROMISC_IN_BSS) {
1076 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1077 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1078 wl->rx_config |= CFG_BSSID_FILTER_EN;
1079 }
1080 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1081 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1082 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1083 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1084 }
1085 if (filters & FIF_OTHER_BSS) {
1086 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1087 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1088 }
1089 if (filters & FIF_CONTROL) {
1090 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1091 wl->rx_filter |= CFG_RX_CTL_EN;
1092 }
1093 if (filters & FIF_FCSFAIL) {
1094 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1095 wl->rx_filter |= CFG_RX_FCS_ERROR;
1096 }
1097}
1098
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001099static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001100{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001101 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001102 /* we need to use a dummy BSSID for now */
1103 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1104 0xad, 0xbe, 0xef };
1105
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001106 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1107
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001108 /* pass through frames from all BSS */
1109 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1110
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001111 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001112 if (ret < 0)
1113 goto out;
1114
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001115 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001116
1117out:
1118 return ret;
1119}
1120
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001121static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001122{
1123 int ret;
1124
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001125 /*
1126 * One of the side effects of the JOIN command is that is clears
1127 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1128 * to a WPA/WPA2 access point will therefore kill the data-path.
1129 * Currently there is no supported scenario for JOIN during
1130 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1131 * must be handled somehow.
1132 *
1133 */
1134 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1135 wl1271_info("JOIN while associated.");
1136
1137 if (set_assoc)
1138 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1139
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001140 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1141 if (ret < 0)
1142 goto out;
1143
1144 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1145
1146 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1147 goto out;
1148
1149 /*
1150 * The join command disable the keep-alive mode, shut down its process,
1151 * and also clear the template config, so we need to reset it all after
1152 * the join. The acx_aid starts the keep-alive process, and the order
1153 * of the commands below is relevant.
1154 */
1155 ret = wl1271_acx_keep_alive_mode(wl, true);
1156 if (ret < 0)
1157 goto out;
1158
1159 ret = wl1271_acx_aid(wl, wl->aid);
1160 if (ret < 0)
1161 goto out;
1162
1163 ret = wl1271_cmd_build_klv_null_data(wl);
1164 if (ret < 0)
1165 goto out;
1166
1167 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1168 ACX_KEEP_ALIVE_TPL_VALID);
1169 if (ret < 0)
1170 goto out;
1171
1172out:
1173 return ret;
1174}
1175
1176static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001177{
1178 int ret;
1179
1180 /* to stop listening to a channel, we disconnect */
1181 ret = wl1271_cmd_disconnect(wl);
1182 if (ret < 0)
1183 goto out;
1184
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001185 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001186 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001187
1188 /* stop filterting packets based on bssid */
1189 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001190
1191out:
1192 return ret;
1193}
1194
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001195static void wl1271_set_band_rate(struct wl1271 *wl)
1196{
1197 if (wl->band == IEEE80211_BAND_2GHZ)
1198 wl->basic_rate_set = wl->conf.tx.basic_rate;
1199 else
1200 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1201}
1202
1203static u32 wl1271_min_rate_get(struct wl1271 *wl)
1204{
1205 int i;
1206 u32 rate = 0;
1207
1208 if (!wl->basic_rate_set) {
1209 WARN_ON(1);
1210 wl->basic_rate_set = wl->conf.tx.basic_rate;
1211 }
1212
1213 for (i = 0; !rate; i++) {
1214 if ((wl->basic_rate_set >> i) & 0x1)
1215 rate = 1 << i;
1216 }
1217
1218 return rate;
1219}
1220
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001221static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1222{
1223 int ret;
1224
1225 if (idle) {
1226 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1227 ret = wl1271_unjoin(wl);
1228 if (ret < 0)
1229 goto out;
1230 }
1231 wl->rate_set = wl1271_min_rate_get(wl);
1232 wl->sta_rate_set = 0;
1233 ret = wl1271_acx_rate_policies(wl);
1234 if (ret < 0)
1235 goto out;
1236 ret = wl1271_acx_keep_alive_config(
1237 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1238 ACX_KEEP_ALIVE_TPL_INVALID);
1239 if (ret < 0)
1240 goto out;
1241 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1242 } else {
1243 /* increment the session counter */
1244 wl->session_counter++;
1245 if (wl->session_counter >= SESSION_COUNTER_MAX)
1246 wl->session_counter = 0;
1247 ret = wl1271_dummy_join(wl);
1248 if (ret < 0)
1249 goto out;
1250 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1251 }
1252
1253out:
1254 return ret;
1255}
1256
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1258{
1259 struct wl1271 *wl = hw->priv;
1260 struct ieee80211_conf *conf = &hw->conf;
1261 int channel, ret = 0;
1262
1263 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1264
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001265 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 channel,
1267 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001268 conf->power_level,
1269 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001271 /*
1272 * mac80211 will go to idle nearly immediately after transmitting some
1273 * frames, such as the deauth. To make sure those frames reach the air,
1274 * wait here until the TX queue is fully flushed.
1275 */
1276 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1277 (conf->flags & IEEE80211_CONF_IDLE))
1278 wl1271_tx_flush(wl);
1279
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280 mutex_lock(&wl->mutex);
1281
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001282 if (unlikely(wl->state == WL1271_STATE_OFF))
1283 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 ret = wl1271_ps_elp_wakeup(wl, false);
1286 if (ret < 0)
1287 goto out;
1288
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001289 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001290 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1291 ((wl->band != conf->channel->band) ||
1292 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001293 wl->band = conf->channel->band;
1294 wl->channel = channel;
1295
1296 /*
1297 * FIXME: the mac80211 should really provide a fixed rate
1298 * to use here. for now, just use the smallest possible rate
1299 * for the band as a fixed rate for association frames and
1300 * other control messages.
1301 */
1302 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1303 wl1271_set_band_rate(wl);
1304
1305 wl->basic_rate = wl1271_min_rate_get(wl);
1306 ret = wl1271_acx_rate_policies(wl);
1307 if (ret < 0)
1308 wl1271_warning("rate policy for update channel "
1309 "failed %d", ret);
1310
1311 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001312 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001313 if (ret < 0)
1314 wl1271_warning("cmd join to update channel "
1315 "failed %d", ret);
1316 }
1317 }
1318
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001319 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001320 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1321 if (ret < 0)
1322 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323 }
1324
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001325 /*
1326 * if mac80211 changes the PSM mode, make sure the mode is not
1327 * incorrectly changed after the pspoll failure active window.
1328 */
1329 if (changed & IEEE80211_CONF_CHANGE_PS)
1330 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1331
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001332 if (conf->flags & IEEE80211_CONF_PS &&
1333 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1334 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335
1336 /*
1337 * We enter PSM only if we're already associated.
1338 * If we're not, we'll enter it when joining an SSID,
1339 * through the bss_info_changed() hook.
1340 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001341 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001342 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001343 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001344 wl->basic_rate_set, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001345 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001347 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001348 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001350 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001352 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001353 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001354 wl->basic_rate_set, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 }
1356
1357 if (conf->power_level != wl->power_level) {
1358 ret = wl1271_acx_tx_power(wl, conf->power_level);
1359 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001360 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361
1362 wl->power_level = conf->power_level;
1363 }
1364
1365out_sleep:
1366 wl1271_ps_elp_sleep(wl);
1367
1368out:
1369 mutex_unlock(&wl->mutex);
1370
1371 return ret;
1372}
1373
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001374struct wl1271_filter_params {
1375 bool enabled;
1376 int mc_list_length;
1377 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1378};
1379
Jiri Pirko22bedad32010-04-01 21:22:57 +00001380static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1381 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001382{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001383 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001384 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001385 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001386
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001387 if (unlikely(wl->state == WL1271_STATE_OFF))
1388 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001389
Juuso Oikarinen74441132009-10-13 12:47:53 +03001390 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001391 if (!fp) {
1392 wl1271_error("Out of memory setting filters.");
1393 return 0;
1394 }
1395
1396 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001397 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001398 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1399 fp->enabled = false;
1400 } else {
1401 fp->enabled = true;
1402 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001403 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001404 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001405 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001406 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001407 }
1408
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001409 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001410}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001412#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1413 FIF_ALLMULTI | \
1414 FIF_FCSFAIL | \
1415 FIF_BCN_PRBRESP_PROMISC | \
1416 FIF_CONTROL | \
1417 FIF_OTHER_BSS)
1418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1420 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001421 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001423 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001425 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426
1427 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1428
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001429 mutex_lock(&wl->mutex);
1430
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001431 *total &= WL1271_SUPPORTED_FILTERS;
1432 changed &= WL1271_SUPPORTED_FILTERS;
1433
1434 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001435 goto out;
1436
1437 ret = wl1271_ps_elp_wakeup(wl, false);
1438 if (ret < 0)
1439 goto out;
1440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001442 if (*total & FIF_ALLMULTI)
1443 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1444 else if (fp)
1445 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1446 fp->mc_list,
1447 fp->mc_list_length);
1448 if (ret < 0)
1449 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001451 /* determine, whether supported filter values have changed */
1452 if (changed == 0)
1453 goto out_sleep;
1454
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001455 /* configure filters */
1456 wl->filters = *total;
1457 wl1271_configure_filters(wl, 0);
1458
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001459 /* apply configured filters */
1460 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1461 if (ret < 0)
1462 goto out_sleep;
1463
1464out_sleep:
1465 wl1271_ps_elp_sleep(wl);
1466
1467out:
1468 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001469 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470}
1471
1472static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1473 struct ieee80211_vif *vif,
1474 struct ieee80211_sta *sta,
1475 struct ieee80211_key_conf *key_conf)
1476{
1477 struct wl1271 *wl = hw->priv;
1478 const u8 *addr;
1479 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001480 u32 tx_seq_32 = 0;
1481 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 u8 key_type;
1483
1484 static const u8 bcast_addr[ETH_ALEN] =
1485 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1486
1487 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1488
1489 addr = sta ? sta->addr : bcast_addr;
1490
1491 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1492 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1493 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02001494 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 key_conf->keylen, key_conf->flags);
1496 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1497
1498 if (is_zero_ether_addr(addr)) {
1499 /* We dont support TX only encryption */
1500 ret = -EOPNOTSUPP;
1501 goto out;
1502 }
1503
1504 mutex_lock(&wl->mutex);
1505
1506 ret = wl1271_ps_elp_wakeup(wl, false);
1507 if (ret < 0)
1508 goto out_unlock;
1509
Johannes Berg97359d12010-08-10 09:46:38 +02001510 switch (key_conf->cipher) {
1511 case WLAN_CIPHER_SUITE_WEP40:
1512 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001513 key_type = KEY_WEP;
1514
1515 key_conf->hw_key_idx = key_conf->keyidx;
1516 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001517 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 key_type = KEY_TKIP;
1519
1520 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001521 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1522 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 break;
Johannes Berg97359d12010-08-10 09:46:38 +02001524 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001525 key_type = KEY_AES;
1526
1527 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001528 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1529 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 break;
1531 default:
Johannes Berg97359d12010-08-10 09:46:38 +02001532 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
1534 ret = -EOPNOTSUPP;
1535 goto out_sleep;
1536 }
1537
1538 switch (cmd) {
1539 case SET_KEY:
1540 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1541 key_conf->keyidx, key_type,
1542 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001543 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 if (ret < 0) {
1545 wl1271_error("Could not add or replace key");
1546 goto out_sleep;
1547 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001548
1549 /* the default WEP key needs to be configured at least once */
1550 if (key_type == KEY_WEP) {
1551 ret = wl1271_cmd_set_default_wep_key(wl,
1552 wl->default_key);
1553 if (ret < 0)
1554 goto out_sleep;
1555 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556 break;
1557
1558 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001559 /* The wl1271 does not allow to remove unicast keys - they
1560 will be cleared automatically on next CMD_JOIN. Ignore the
1561 request silently, as we dont want the mac80211 to emit
1562 an error message. */
1563 if (!is_broadcast_ether_addr(addr))
1564 break;
1565
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1567 key_conf->keyidx, key_type,
1568 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001569 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 if (ret < 0) {
1571 wl1271_error("Could not remove key");
1572 goto out_sleep;
1573 }
1574 break;
1575
1576 default:
1577 wl1271_error("Unsupported key cmd 0x%x", cmd);
1578 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 break;
1580 }
1581
1582out_sleep:
1583 wl1271_ps_elp_sleep(wl);
1584
1585out_unlock:
1586 mutex_unlock(&wl->mutex);
1587
1588out:
1589 return ret;
1590}
1591
1592static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001593 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594 struct cfg80211_scan_request *req)
1595{
1596 struct wl1271 *wl = hw->priv;
1597 int ret;
1598 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001599 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001600
1601 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1602
1603 if (req->n_ssids) {
1604 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001605 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606 }
1607
1608 mutex_lock(&wl->mutex);
1609
1610 ret = wl1271_ps_elp_wakeup(wl, false);
1611 if (ret < 0)
1612 goto out;
1613
Luciano Coelho5924f892010-08-04 03:46:22 +03001614 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615
1616 wl1271_ps_elp_sleep(wl);
1617
1618out:
1619 mutex_unlock(&wl->mutex);
1620
1621 return ret;
1622}
1623
1624static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1625{
1626 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001627 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628
1629 mutex_lock(&wl->mutex);
1630
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001631 if (unlikely(wl->state == WL1271_STATE_OFF))
1632 goto out;
1633
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001634 ret = wl1271_ps_elp_wakeup(wl, false);
1635 if (ret < 0)
1636 goto out;
1637
1638 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1639 if (ret < 0)
1640 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1641
1642 wl1271_ps_elp_sleep(wl);
1643
1644out:
1645 mutex_unlock(&wl->mutex);
1646
1647 return ret;
1648}
1649
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001650static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1651{
1652 u8 *ptr = beacon->data +
1653 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1654
1655 /* find the location of the ssid in the beacon */
1656 while (ptr < beacon->data + beacon->len) {
1657 if (ptr[0] == WLAN_EID_SSID) {
1658 wl->ssid_len = ptr[1];
1659 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1660 return;
1661 }
1662 ptr += ptr[1];
1663 }
1664 wl1271_error("ad-hoc beacon template has no SSID!\n");
1665}
1666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1668 struct ieee80211_vif *vif,
1669 struct ieee80211_bss_conf *bss_conf,
1670 u32 changed)
1671{
1672 enum wl1271_cmd_ps_mode mode;
1673 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001674 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001675 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001676 int ret;
1677
1678 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1679
1680 mutex_lock(&wl->mutex);
1681
1682 ret = wl1271_ps_elp_wakeup(wl, false);
1683 if (ret < 0)
1684 goto out;
1685
Eliad Peller9ee82d52010-09-19 18:55:09 +02001686 if ((changed & BSS_CHANGED_BEACON_INT) &&
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001687 (wl->bss_type == BSS_TYPE_IBSS)) {
1688 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1689 bss_conf->beacon_int);
1690
1691 wl->beacon_int = bss_conf->beacon_int;
1692 do_join = true;
1693 }
1694
Eliad Peller9ee82d52010-09-19 18:55:09 +02001695 if ((changed & BSS_CHANGED_BEACON) &&
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001696 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001697 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1698
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001699 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1700
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001701 if (beacon) {
1702 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001703
1704 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001705 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1706 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001707 beacon->len, 0,
1708 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001709
1710 if (ret < 0) {
1711 dev_kfree_skb(beacon);
1712 goto out_sleep;
1713 }
1714
1715 hdr = (struct ieee80211_hdr *) beacon->data;
1716 hdr->frame_control = cpu_to_le16(
1717 IEEE80211_FTYPE_MGMT |
1718 IEEE80211_STYPE_PROBE_RESP);
1719
1720 ret = wl1271_cmd_template_set(wl,
1721 CMD_TEMPL_PROBE_RESPONSE,
1722 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001723 beacon->len, 0,
1724 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001725 dev_kfree_skb(beacon);
1726 if (ret < 0)
1727 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001728
1729 /* Need to update the SSID (for filtering etc) */
1730 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001731 }
1732 }
1733
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001734 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1735 (wl->bss_type == BSS_TYPE_IBSS)) {
1736 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1737 bss_conf->enable_beacon ? "enabled" : "disabled");
1738
1739 if (bss_conf->enable_beacon)
1740 wl->set_bss_type = BSS_TYPE_IBSS;
1741 else
1742 wl->set_bss_type = BSS_TYPE_STA_BSS;
1743 do_join = true;
1744 }
1745
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001746 if (changed & BSS_CHANGED_CQM) {
1747 bool enable = false;
1748 if (bss_conf->cqm_rssi_thold)
1749 enable = true;
1750 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1751 bss_conf->cqm_rssi_thold,
1752 bss_conf->cqm_rssi_hyst);
1753 if (ret < 0)
1754 goto out;
1755 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1756 }
1757
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001758 if ((changed & BSS_CHANGED_BSSID) &&
1759 /*
1760 * Now we know the correct bssid, so we send a new join command
1761 * and enable the BSSID filter
1762 */
1763 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001764 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001765
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001766 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001767 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001768 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001769
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001770 ret = wl1271_build_qos_null_data(wl);
1771 if (ret < 0)
1772 goto out_sleep;
1773
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001774 /* filter out all packets not from this BSSID */
1775 wl1271_configure_filters(wl, 0);
1776
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001777 /* Need to update the BSSID (for filtering etc) */
1778 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001779 }
1780
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001781 if (changed & BSS_CHANGED_ASSOC) {
1782 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001783 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001784 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001785 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001787 wl->ps_poll_failures = 0;
1788
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001789 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001790 * use basic rates from AP, and determine lowest rate
1791 * to use with control frames.
1792 */
1793 rates = bss_conf->basic_rates;
1794 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1795 rates);
1796 wl->basic_rate = wl1271_min_rate_get(wl);
1797 ret = wl1271_acx_rate_policies(wl);
1798 if (ret < 0)
1799 goto out_sleep;
1800
1801 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001802 * with wl1271, we don't need to update the
1803 * beacon_int and dtim_period, because the firmware
1804 * updates it by itself when the first beacon is
1805 * received after a join.
1806 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1808 if (ret < 0)
1809 goto out_sleep;
1810
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001811 /*
1812 * The SSID is intentionally set to NULL here - the
1813 * firmware will set the probe request with a
1814 * broadcast SSID regardless of what we set in the
1815 * template.
1816 */
1817 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1818 NULL, 0, wl->band);
1819
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001820 /* enable the connection monitoring feature */
1821 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 if (ret < 0)
1823 goto out_sleep;
1824
1825 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001826 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1827 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03001829 ret = wl1271_ps_set_mode(wl, mode,
1830 wl->basic_rate_set,
1831 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 if (ret < 0)
1833 goto out_sleep;
1834 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001835 } else {
1836 /* use defaults when not associated */
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001837 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001838 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001839 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001840
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001841 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001842 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001843
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001844 /* revert back to minimum rates for the current band */
1845 wl1271_set_band_rate(wl);
1846 wl->basic_rate = wl1271_min_rate_get(wl);
1847 ret = wl1271_acx_rate_policies(wl);
1848 if (ret < 0)
1849 goto out_sleep;
1850
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001851 /* disable connection monitor features */
1852 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001853
1854 /* Disable the keep-alive feature */
1855 ret = wl1271_acx_keep_alive_mode(wl, false);
1856
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001857 if (ret < 0)
1858 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001860
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001862
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 if (changed & BSS_CHANGED_ERP_SLOT) {
1864 if (bss_conf->use_short_slot)
1865 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1866 else
1867 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1868 if (ret < 0) {
1869 wl1271_warning("Set slot time failed %d", ret);
1870 goto out_sleep;
1871 }
1872 }
1873
1874 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1875 if (bss_conf->use_short_preamble)
1876 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1877 else
1878 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1879 }
1880
1881 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1882 if (bss_conf->use_cts_prot)
1883 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1884 else
1885 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1886 if (ret < 0) {
1887 wl1271_warning("Set ctsprotect failed %d", ret);
1888 goto out_sleep;
1889 }
1890 }
1891
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001892 if (changed & BSS_CHANGED_ARP_FILTER) {
1893 __be32 addr = bss_conf->arp_addr_list[0];
1894 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1895
1896 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1897 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1898 else
1899 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1900
1901 if (ret < 0)
1902 goto out_sleep;
1903 }
1904
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001905 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001906 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001907 if (ret < 0) {
1908 wl1271_warning("cmd join failed %d", ret);
1909 goto out_sleep;
1910 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001911 }
1912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913out_sleep:
1914 wl1271_ps_elp_sleep(wl);
1915
1916out:
1917 mutex_unlock(&wl->mutex);
1918}
1919
Kalle Valoc6999d82010-02-18 13:25:41 +02001920static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1921 const struct ieee80211_tx_queue_params *params)
1922{
1923 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001924 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001925 int ret;
1926
1927 mutex_lock(&wl->mutex);
1928
1929 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1930
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001931 ret = wl1271_ps_elp_wakeup(wl, false);
1932 if (ret < 0)
1933 goto out;
1934
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001935 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001936 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1937 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001938 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001939 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001940 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001941
Kalle Valo4695dc92010-03-18 12:26:38 +02001942 if (params->uapsd)
1943 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1944 else
1945 ps_scheme = CONF_PS_SCHEME_LEGACY;
1946
Kalle Valoc6999d82010-02-18 13:25:41 +02001947 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1948 CONF_CHANNEL_TYPE_EDCF,
1949 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001950 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001951 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001952 goto out_sleep;
1953
1954out_sleep:
1955 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001956
1957out:
1958 mutex_unlock(&wl->mutex);
1959
1960 return ret;
1961}
1962
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001963static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1964{
1965
1966 struct wl1271 *wl = hw->priv;
1967 u64 mactime = ULLONG_MAX;
1968 int ret;
1969
1970 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1971
1972 mutex_lock(&wl->mutex);
1973
1974 ret = wl1271_ps_elp_wakeup(wl, false);
1975 if (ret < 0)
1976 goto out;
1977
1978 ret = wl1271_acx_tsf_info(wl, &mactime);
1979 if (ret < 0)
1980 goto out_sleep;
1981
1982out_sleep:
1983 wl1271_ps_elp_sleep(wl);
1984
1985out:
1986 mutex_unlock(&wl->mutex);
1987 return mactime;
1988}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
John W. Linvilleece550d2010-07-28 16:41:06 -04001990static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
1991 struct survey_info *survey)
1992{
1993 struct wl1271 *wl = hw->priv;
1994 struct ieee80211_conf *conf = &hw->conf;
1995
1996 if (idx != 0)
1997 return -ENOENT;
1998
1999 survey->channel = conf->channel;
2000 survey->filled = SURVEY_INFO_NOISE_DBM;
2001 survey->noise = wl->noise;
2002
2003 return 0;
2004}
2005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006/* can't be const, mac80211 writes to this */
2007static struct ieee80211_rate wl1271_rates[] = {
2008 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002009 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2010 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002012 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2013 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002014 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2015 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002016 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2017 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2019 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002020 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2021 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2023 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002024 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2025 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002026 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002027 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2028 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002030 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002033 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002036 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2037 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002038 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002039 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2040 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002042 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2043 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002045 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2046 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047};
2048
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002049/*
2050 * Can't be const, mac80211 writes to this. The order of the channels here
2051 * is designed to improve scanning.
2052 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002054 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002055 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002056 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002057 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002058 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2059 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2060 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2061 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2062 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2063 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2064 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2065 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2066 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067};
2068
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002069/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002070static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002071 /* MCS rates are used only with 11n */
2072 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2073 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2074 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2075 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2076 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2077 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2078 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2079 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2080
2081 11, /* CONF_HW_RXTX_RATE_54 */
2082 10, /* CONF_HW_RXTX_RATE_48 */
2083 9, /* CONF_HW_RXTX_RATE_36 */
2084 8, /* CONF_HW_RXTX_RATE_24 */
2085
2086 /* TI-specific rate */
2087 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2088
2089 7, /* CONF_HW_RXTX_RATE_18 */
2090 6, /* CONF_HW_RXTX_RATE_12 */
2091 3, /* CONF_HW_RXTX_RATE_11 */
2092 5, /* CONF_HW_RXTX_RATE_9 */
2093 4, /* CONF_HW_RXTX_RATE_6 */
2094 2, /* CONF_HW_RXTX_RATE_5_5 */
2095 1, /* CONF_HW_RXTX_RATE_2 */
2096 0 /* CONF_HW_RXTX_RATE_1 */
2097};
2098
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099/* can't be const, mac80211 writes to this */
2100static struct ieee80211_supported_band wl1271_band_2ghz = {
2101 .channels = wl1271_channels,
2102 .n_channels = ARRAY_SIZE(wl1271_channels),
2103 .bitrates = wl1271_rates,
2104 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2105};
2106
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002107/* 5 GHz data rates for WL1273 */
2108static struct ieee80211_rate wl1271_rates_5ghz[] = {
2109 { .bitrate = 60,
2110 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2111 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2112 { .bitrate = 90,
2113 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2114 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2115 { .bitrate = 120,
2116 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2117 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2118 { .bitrate = 180,
2119 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2120 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2121 { .bitrate = 240,
2122 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2123 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2124 { .bitrate = 360,
2125 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2126 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2127 { .bitrate = 480,
2128 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2129 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2130 { .bitrate = 540,
2131 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2132 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2133};
2134
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002135/*
2136 * 5 GHz band channels for WL1273 - can't be const, mac80211 writes to this.
2137 * The order of the channels here is designed to improve scanning.
2138 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002139static struct ieee80211_channel wl1271_channels_5ghz[] = {
2140 { .hw_value = 183, .center_freq = 4915},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002141 { .hw_value = 188, .center_freq = 4940},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002142 { .hw_value = 8, .center_freq = 5040},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002143 { .hw_value = 34, .center_freq = 5170},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002144 { .hw_value = 44, .center_freq = 5220},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002145 { .hw_value = 60, .center_freq = 5300},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002146 { .hw_value = 112, .center_freq = 5560},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002147 { .hw_value = 132, .center_freq = 5660},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002148 { .hw_value = 157, .center_freq = 5785},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002149 { .hw_value = 184, .center_freq = 4920},
2150 { .hw_value = 189, .center_freq = 4945},
2151 { .hw_value = 9, .center_freq = 5045},
2152 { .hw_value = 36, .center_freq = 5180},
2153 { .hw_value = 46, .center_freq = 5230},
2154 { .hw_value = 64, .center_freq = 5320},
2155 { .hw_value = 116, .center_freq = 5580},
2156 { .hw_value = 136, .center_freq = 5680},
2157 { .hw_value = 192, .center_freq = 4960},
2158 { .hw_value = 11, .center_freq = 5055},
2159 { .hw_value = 38, .center_freq = 5190},
2160 { .hw_value = 48, .center_freq = 5240},
2161 { .hw_value = 100, .center_freq = 5500},
2162 { .hw_value = 120, .center_freq = 5600},
2163 { .hw_value = 140, .center_freq = 5700},
2164 { .hw_value = 185, .center_freq = 4925},
2165 { .hw_value = 196, .center_freq = 4980},
2166 { .hw_value = 12, .center_freq = 5060},
2167 { .hw_value = 40, .center_freq = 5200},
2168 { .hw_value = 52, .center_freq = 5260},
2169 { .hw_value = 104, .center_freq = 5520},
2170 { .hw_value = 124, .center_freq = 5620},
2171 { .hw_value = 149, .center_freq = 5745},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002172 { .hw_value = 161, .center_freq = 5805},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02002173 { .hw_value = 187, .center_freq = 4935},
2174 { .hw_value = 7, .center_freq = 5035},
2175 { .hw_value = 16, .center_freq = 5080},
2176 { .hw_value = 42, .center_freq = 5210},
2177 { .hw_value = 56, .center_freq = 5280},
2178 { .hw_value = 108, .center_freq = 5540},
2179 { .hw_value = 128, .center_freq = 5640},
2180 { .hw_value = 153, .center_freq = 5765},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002181 { .hw_value = 165, .center_freq = 5825},
2182};
2183
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002184/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002185static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002186 /* MCS rates are used only with 11n */
2187 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2188 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2189 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2190 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2191 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2192 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2193 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2194 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2195
2196 7, /* CONF_HW_RXTX_RATE_54 */
2197 6, /* CONF_HW_RXTX_RATE_48 */
2198 5, /* CONF_HW_RXTX_RATE_36 */
2199 4, /* CONF_HW_RXTX_RATE_24 */
2200
2201 /* TI-specific rate */
2202 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2203
2204 3, /* CONF_HW_RXTX_RATE_18 */
2205 2, /* CONF_HW_RXTX_RATE_12 */
2206 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2207 1, /* CONF_HW_RXTX_RATE_9 */
2208 0, /* CONF_HW_RXTX_RATE_6 */
2209 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2210 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2211 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2212};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002213
2214static struct ieee80211_supported_band wl1271_band_5ghz = {
2215 .channels = wl1271_channels_5ghz,
2216 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2217 .bitrates = wl1271_rates_5ghz,
2218 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2219};
2220
Tobias Klausera0ea9492010-05-20 10:38:11 +02002221static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002222 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2223 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2224};
2225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226static const struct ieee80211_ops wl1271_ops = {
2227 .start = wl1271_op_start,
2228 .stop = wl1271_op_stop,
2229 .add_interface = wl1271_op_add_interface,
2230 .remove_interface = wl1271_op_remove_interface,
2231 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002232 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002233 .configure_filter = wl1271_op_configure_filter,
2234 .tx = wl1271_op_tx,
2235 .set_key = wl1271_op_set_key,
2236 .hw_scan = wl1271_op_hw_scan,
2237 .bss_info_changed = wl1271_op_bss_info_changed,
2238 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002239 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002240 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002241 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002242 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002243};
2244
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002245
2246u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2247{
2248 u8 idx;
2249
2250 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2251
2252 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2253 wl1271_error("Illegal RX rate from HW: %d", rate);
2254 return 0;
2255 }
2256
2257 idx = wl1271_band_rate_to_idx[wl->band][rate];
2258 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2259 wl1271_error("Unsupported RX rate from HW: %d", rate);
2260 return 0;
2261 }
2262
2263 return idx;
2264}
2265
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002266static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2267 struct device_attribute *attr,
2268 char *buf)
2269{
2270 struct wl1271 *wl = dev_get_drvdata(dev);
2271 ssize_t len;
2272
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002273 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002274
2275 mutex_lock(&wl->mutex);
2276 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2277 wl->sg_enabled);
2278 mutex_unlock(&wl->mutex);
2279
2280 return len;
2281
2282}
2283
2284static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2285 struct device_attribute *attr,
2286 const char *buf, size_t count)
2287{
2288 struct wl1271 *wl = dev_get_drvdata(dev);
2289 unsigned long res;
2290 int ret;
2291
2292 ret = strict_strtoul(buf, 10, &res);
2293
2294 if (ret < 0) {
2295 wl1271_warning("incorrect value written to bt_coex_mode");
2296 return count;
2297 }
2298
2299 mutex_lock(&wl->mutex);
2300
2301 res = !!res;
2302
2303 if (res == wl->sg_enabled)
2304 goto out;
2305
2306 wl->sg_enabled = res;
2307
2308 if (wl->state == WL1271_STATE_OFF)
2309 goto out;
2310
2311 ret = wl1271_ps_elp_wakeup(wl, false);
2312 if (ret < 0)
2313 goto out;
2314
2315 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2316 wl1271_ps_elp_sleep(wl);
2317
2318 out:
2319 mutex_unlock(&wl->mutex);
2320 return count;
2321}
2322
2323static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2324 wl1271_sysfs_show_bt_coex_state,
2325 wl1271_sysfs_store_bt_coex_state);
2326
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002327static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2328 struct device_attribute *attr,
2329 char *buf)
2330{
2331 struct wl1271 *wl = dev_get_drvdata(dev);
2332 ssize_t len;
2333
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02002334 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002335
2336 mutex_lock(&wl->mutex);
2337 if (wl->hw_pg_ver >= 0)
2338 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2339 else
2340 len = snprintf(buf, len, "n/a\n");
2341 mutex_unlock(&wl->mutex);
2342
2343 return len;
2344}
2345
2346static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2347 wl1271_sysfs_show_hw_pg_ver, NULL);
2348
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002349int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350{
2351 int ret;
2352
2353 if (wl->mac80211_registered)
2354 return 0;
2355
2356 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2357
2358 ret = ieee80211_register_hw(wl->hw);
2359 if (ret < 0) {
2360 wl1271_error("unable to register mac80211 hw: %d", ret);
2361 return ret;
2362 }
2363
2364 wl->mac80211_registered = true;
2365
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002366 register_netdevice_notifier(&wl1271_dev_notifier);
2367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 wl1271_notice("loaded");
2369
2370 return 0;
2371}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002372EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002374void wl1271_unregister_hw(struct wl1271 *wl)
2375{
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002376 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002377 ieee80211_unregister_hw(wl->hw);
2378 wl->mac80211_registered = false;
2379
2380}
2381EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2382
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002383int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002385 /* The tx descriptor buffer and the TKIP space. */
2386 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2387 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388
2389 /* unit us */
2390 /* FIXME: find a proper value */
2391 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002392 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393
2394 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002395 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002396 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002397 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002398 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002399 IEEE80211_HW_CONNECTION_MONITOR |
2400 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002401
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002402 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2403 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404 wl->hw->wiphy->max_scan_ssids = 1;
2405 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2406
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02002407 if (wl->enable_11a)
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002408 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2409
Kalle Valo12bd8942010-03-18 12:26:33 +02002410 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002411 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002412
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002413 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002414
2415 return 0;
2416}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002417EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002419#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002420
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002421struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002422{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002424 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002425 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002426 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427
2428 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2429 if (!hw) {
2430 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002431 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002432 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433 }
2434
Julia Lawall929ebd32010-05-15 23:16:39 +02002435 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002436 if (!plat_dev) {
2437 wl1271_error("could not allocate platform_device");
2438 ret = -ENOMEM;
2439 goto err_plat_alloc;
2440 }
2441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002442 wl = hw->priv;
2443 memset(wl, 0, sizeof(*wl));
2444
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002445 INIT_LIST_HEAD(&wl->list);
2446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002448 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449
2450 skb_queue_head_init(&wl->tx_queue);
2451
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002452 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002453 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002455 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002457 wl->rx_counter = 0;
2458 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2459 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002460 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002462 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002463 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002464 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2465 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002466 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002467 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002468 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002469 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002470 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002472 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002473 wl->tx_frames[i] = NULL;
2474
2475 spin_lock_init(&wl->wl_lock);
2476
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477 wl->state = WL1271_STATE_OFF;
2478 mutex_init(&wl->mutex);
2479
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002480 /* Apply default driver configuration. */
2481 wl1271_conf_init(wl);
2482
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002483 wl1271_debugfs_init(wl);
2484
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002485 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002486 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002487 if (ret) {
2488 wl1271_error("couldn't register platform device");
2489 goto err_hw;
2490 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002491 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002492
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002493 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002494 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002495 if (ret < 0) {
2496 wl1271_error("failed to create sysfs file bt_coex_state");
2497 goto err_platform;
2498 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002499
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002500 /* Create sysfs file to get HW PG version */
2501 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2502 if (ret < 0) {
2503 wl1271_error("failed to create sysfs file hw_pg_ver");
2504 goto err_bt_coex_state;
2505 }
2506
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002507 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002508
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002509err_bt_coex_state:
2510 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2511
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002512err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002513 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002514
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002515err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002516 wl1271_debugfs_exit(wl);
2517 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002518
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002519err_plat_alloc:
2520 ieee80211_free_hw(hw);
2521
2522err_hw_alloc:
2523
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002524 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002525}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002526EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002527
2528int wl1271_free_hw(struct wl1271 *wl)
2529{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002530 platform_device_unregister(wl->plat_dev);
2531 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002532
2533 wl1271_debugfs_exit(wl);
2534
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002535 vfree(wl->fw);
2536 wl->fw = NULL;
2537 kfree(wl->nvs);
2538 wl->nvs = NULL;
2539
2540 kfree(wl->fw_status);
2541 kfree(wl->tx_res_if);
2542
2543 ieee80211_free_hw(wl->hw);
2544
2545 return 0;
2546}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002547EXPORT_SYMBOL_GPL(wl1271_free_hw);
2548
2549MODULE_LICENSE("GPL");
2550MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2551MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");