blob: 366e41518feb820bc534c65984188697dc60efbc [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 Coelhof5fc0f82009-08-06 16:25:28 +030047
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020048#define WL1271_BOOT_RETRIES 3
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020052 .params = {
53 [CONF_SG_BT_PER_THRESHOLD] = 7500,
54 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
55 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
56 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030057 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020058 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
59 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
60 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
61 [CONF_SG_BEACON_MISS_PERCENT] = 60,
62 [CONF_SG_RATE_ADAPT_THRESH] = 12,
63 [CONF_SG_RATE_ADAPT_SNR] = 0,
64 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
66 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
67 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
69 /* Note: with UPSD, this should be 4 */
70 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
71 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
74 /* Note: with UPDS, this should be 15 */
75 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
76 /* Note: with UPDS, this should be 50 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
78 /* Note: with UPDS, this should be 10 */
79 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
80 [CONF_SG_RXT] = 1200,
81 [CONF_SG_TXT] = 1000,
82 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
83 [CONF_SG_PS_POLL_TIMEOUT] = 10,
84 [CONF_SG_UPSD_TIMEOUT] = 10,
85 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
87 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
94 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
96 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
97 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
98 [CONF_SG_HV3_MAX_SERVED] = 6,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
101 },
102 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300103 },
104 .rx = {
105 .rx_msdu_life_time = 512000,
106 .packet_detection_threshold = 0,
107 .ps_poll_timeout = 15,
108 .upsd_timeout = 15,
109 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200110 .rx_cca_threshold = 0,
111 .irq_blk_threshold = 0xFFFF,
112 .irq_pkt_threshold = 0,
113 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300114 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
115 },
116 .tx = {
117 .tx_energy_detection = 0,
118 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300119 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 .short_retry_limit = 10,
121 .long_retry_limit = 10,
122 .aflags = 0
123 },
124 .ac_conf_count = 4,
125 .ac_conf = {
126 [0] = {
127 .ac = CONF_TX_AC_BE,
128 .cw_min = 15,
129 .cw_max = 63,
130 .aifsn = 3,
131 .tx_op_limit = 0,
132 },
133 [1] = {
134 .ac = CONF_TX_AC_BK,
135 .cw_min = 15,
136 .cw_max = 63,
137 .aifsn = 7,
138 .tx_op_limit = 0,
139 },
140 [2] = {
141 .ac = CONF_TX_AC_VI,
142 .cw_min = 15,
143 .cw_max = 63,
144 .aifsn = CONF_TX_AIFS_PIFS,
145 .tx_op_limit = 3008,
146 },
147 [3] = {
148 .ac = CONF_TX_AC_VO,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = CONF_TX_AIFS_PIFS,
152 .tx_op_limit = 1504,
153 },
154 },
155 .tid_conf_count = 7,
156 .tid_conf = {
157 [0] = {
158 .queue_id = 0,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [1] = {
166 .queue_id = 1,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 },
173 [2] = {
174 .queue_id = 2,
175 .channel_type = CONF_CHANNEL_TYPE_DCF,
176 .tsid = CONF_TX_AC_BE,
177 .ps_scheme = CONF_PS_SCHEME_LEGACY,
178 .ack_policy = CONF_ACK_POLICY_LEGACY,
179 .apsd_conf = {0, 0},
180 },
181 [3] = {
182 .queue_id = 3,
183 .channel_type = CONF_CHANNEL_TYPE_DCF,
184 .tsid = CONF_TX_AC_BE,
185 .ps_scheme = CONF_PS_SCHEME_LEGACY,
186 .ack_policy = CONF_ACK_POLICY_LEGACY,
187 .apsd_conf = {0, 0},
188 },
189 [4] = {
190 .queue_id = 4,
191 .channel_type = CONF_CHANNEL_TYPE_DCF,
192 .tsid = CONF_TX_AC_BE,
193 .ps_scheme = CONF_PS_SCHEME_LEGACY,
194 .ack_policy = CONF_ACK_POLICY_LEGACY,
195 .apsd_conf = {0, 0},
196 },
197 [5] = {
198 .queue_id = 5,
199 .channel_type = CONF_CHANNEL_TYPE_DCF,
200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
205 [6] = {
206 .queue_id = 6,
207 .channel_type = CONF_CHANNEL_TYPE_DCF,
208 .tsid = CONF_TX_AC_BE,
209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 }
213 },
214 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200215 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300216 .tx_compl_threshold = 4,
217 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
218 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 },
220 .conn = {
221 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300222 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300223 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
224 .bcn_filt_ie_count = 1,
225 .bcn_filt_ie = {
226 [0] = {
227 .ie = WLAN_EID_CHANNEL_SWITCH,
228 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
229 }
230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300236 .ps_poll_threshold = 10,
237 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300238 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200239 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200240 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300241 .keep_alive_interval = 55000,
242 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200244 .itrim = {
245 .enable = false,
246 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200247 },
248 .pm_config = {
249 .host_clk_settling_time = 5000,
250 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300251 },
252 .roam_trigger = {
253 /* FIXME: due to firmware bug, must use value 1 for now */
254 .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 Oikarinen2b60100b2009-10-13 12:47:39 +0300279static void wl1271_conf_init(struct wl1271 *wl)
280{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300281
282 /*
283 * This function applies the default configuration to the driver. This
284 * function is invoked upon driver load (spi probe.)
285 *
286 * The configuration is stored in a run-time structure in order to
287 * facilitate for run-time adjustment of any of the parameters. Making
288 * changes to the configuration structure will apply the new values on
289 * the next interface up (wl1271_op_start.)
290 */
291
292 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300293 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300294}
295
296
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300297static int wl1271_plt_init(struct wl1271 *wl)
298{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200299 struct conf_tx_ac_category *conf_ac;
300 struct conf_tx_tid *conf_tid;
301 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300302
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200303 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200304 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200305 return ret;
306
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200307 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200308 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200309 return ret;
310
Luciano Coelho12419cce2010-02-18 13:25:44 +0200311 ret = wl1271_init_templates_config(wl);
312 if (ret < 0)
313 return ret;
314
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300315 ret = wl1271_acx_init_mem_config(wl);
316 if (ret < 0)
317 return ret;
318
Luciano Coelho12419cce2010-02-18 13:25:44 +0200319 /* PHY layer config */
320 ret = wl1271_init_phy_config(wl);
321 if (ret < 0)
322 goto out_free_memmap;
323
324 ret = wl1271_acx_dco_itrim_params(wl);
325 if (ret < 0)
326 goto out_free_memmap;
327
328 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200329 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200330 if (ret < 0)
331 goto out_free_memmap;
332
333 /* Bluetooth WLAN coexistence */
334 ret = wl1271_init_pta(wl);
335 if (ret < 0)
336 goto out_free_memmap;
337
338 /* Energy detection */
339 ret = wl1271_init_energy_detection(wl);
340 if (ret < 0)
341 goto out_free_memmap;
342
343 /* Default fragmentation threshold */
344 ret = wl1271_acx_frag_threshold(wl);
345 if (ret < 0)
346 goto out_free_memmap;
347
348 /* Default TID configuration */
349 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
350 conf_tid = &wl->conf.tx.tid_conf[i];
351 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
352 conf_tid->channel_type,
353 conf_tid->tsid,
354 conf_tid->ps_scheme,
355 conf_tid->ack_policy,
356 conf_tid->apsd_conf[0],
357 conf_tid->apsd_conf[1]);
358 if (ret < 0)
359 goto out_free_memmap;
360 }
361
362 /* Default AC configuration */
363 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
364 conf_ac = &wl->conf.tx.ac_conf[i];
365 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
366 conf_ac->cw_max, conf_ac->aifsn,
367 conf_ac->tx_op_limit);
368 if (ret < 0)
369 goto out_free_memmap;
370 }
371
372 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200373 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300374 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200375 goto out_free_memmap;
376
377 /* Configure for CAM power saving (ie. always active) */
378 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
379 if (ret < 0)
380 goto out_free_memmap;
381
382 /* configure PM */
383 ret = wl1271_acx_pm_config(wl);
384 if (ret < 0)
385 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300386
387 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200388
389 out_free_memmap:
390 kfree(wl->target_mem_map);
391 wl->target_mem_map = NULL;
392
393 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300394}
395
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300396static void wl1271_fw_status(struct wl1271 *wl,
397 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200399 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300400 u32 total = 0;
401 int i;
402
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200403 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404
405 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
406 "drv_rx_counter = %d, tx_results_counter = %d)",
407 status->intr,
408 status->fw_rx_counter,
409 status->drv_rx_counter,
410 status->tx_results_counter);
411
412 /* update number of available TX blocks */
413 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300414 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
415 wl->tx_blocks_freed[i];
416
417 wl->tx_blocks_freed[i] =
418 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300419 wl->tx_blocks_available += cnt;
420 total += cnt;
421 }
422
423 /* if more blocks are available now, schedule some tx work */
424 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300425 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300426
427 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200428 getnstimeofday(&ts);
429 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
430 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431}
432
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200433#define WL1271_IRQ_MAX_LOOPS 10
434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435static void wl1271_irq_work(struct work_struct *work)
436{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300437 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300438 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200439 int loopcount = WL1271_IRQ_MAX_LOOPS;
440 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 struct wl1271 *wl =
442 container_of(work, struct wl1271, irq_work);
443
444 mutex_lock(&wl->mutex);
445
446 wl1271_debug(DEBUG_IRQ, "IRQ work");
447
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200448 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449 goto out;
450
451 ret = wl1271_ps_elp_wakeup(wl, true);
452 if (ret < 0)
453 goto out;
454
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200455 spin_lock_irqsave(&wl->wl_lock, flags);
456 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
457 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
458 spin_unlock_irqrestore(&wl->wl_lock, flags);
459 loopcount--;
460
461 wl1271_fw_status(wl, wl->fw_status);
462 intr = le32_to_cpu(wl->fw_status->intr);
463 if (!intr) {
464 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200465 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200466 continue;
467 }
468
469 intr &= WL1271_INTR_MASK;
470
471 if (intr & WL1271_ACX_INTR_DATA) {
472 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
473
474 /* check for tx results */
475 if (wl->fw_status->tx_results_counter !=
476 (wl->tx_results_count & 0xff))
477 wl1271_tx_complete(wl);
478
479 wl1271_rx(wl, wl->fw_status);
480 }
481
482 if (intr & WL1271_ACX_INTR_EVENT_A) {
483 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
484 wl1271_event_handle(wl, 0);
485 }
486
487 if (intr & WL1271_ACX_INTR_EVENT_B) {
488 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
489 wl1271_event_handle(wl, 1);
490 }
491
492 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
493 wl1271_debug(DEBUG_IRQ,
494 "WL1271_ACX_INTR_INIT_COMPLETE");
495
496 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
497 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
498
499 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300500 }
501
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200502 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
503 ieee80211_queue_work(wl->hw, &wl->irq_work);
504 else
505 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
506 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300508 wl1271_ps_elp_sleep(wl);
509
510out:
511 mutex_unlock(&wl->mutex);
512}
513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300514static int wl1271_fetch_firmware(struct wl1271 *wl)
515{
516 const struct firmware *fw;
517 int ret;
518
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200519 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300520
521 if (ret < 0) {
522 wl1271_error("could not get firmware: %d", ret);
523 return ret;
524 }
525
526 if (fw->size % 4) {
527 wl1271_error("firmware size is not multiple of 32 bits: %zu",
528 fw->size);
529 ret = -EILSEQ;
530 goto out;
531 }
532
533 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300534 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535
536 if (!wl->fw) {
537 wl1271_error("could not allocate memory for the firmware");
538 ret = -ENOMEM;
539 goto out;
540 }
541
542 memcpy(wl->fw, fw->data, wl->fw_len);
543
544 ret = 0;
545
546out:
547 release_firmware(fw);
548
549 return ret;
550}
551
552static int wl1271_fetch_nvs(struct wl1271 *wl)
553{
554 const struct firmware *fw;
555 int ret;
556
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200557 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300558
559 if (ret < 0) {
560 wl1271_error("could not get nvs file: %d", ret);
561 return ret;
562 }
563
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300564 /*
565 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
566 * configurations) can be removed when those NVS files stop floating
567 * around.
568 */
569 if (fw->size != sizeof(struct wl1271_nvs_file) &&
570 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
571 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200572 wl1271_error("nvs size is not as expected: %zu != %zu",
573 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300574 ret = -EILSEQ;
575 goto out;
576 }
577
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300578 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579
580 if (!wl->nvs) {
581 wl1271_error("could not allocate memory for the nvs file");
582 ret = -ENOMEM;
583 goto out;
584 }
585
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300586 memcpy(wl->nvs, fw->data, fw->size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300588out:
589 release_firmware(fw);
590
591 return ret;
592}
593
594static void wl1271_fw_wakeup(struct wl1271 *wl)
595{
596 u32 elp_reg;
597
598 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300599 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300600}
601
602static int wl1271_setup(struct wl1271 *wl)
603{
604 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
605 if (!wl->fw_status)
606 return -ENOMEM;
607
608 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
609 if (!wl->tx_res_if) {
610 kfree(wl->fw_status);
611 return -ENOMEM;
612 }
613
614 INIT_WORK(&wl->irq_work, wl1271_irq_work);
615 INIT_WORK(&wl->tx_work, wl1271_tx_work);
616 return 0;
617}
618
619static int wl1271_chip_wakeup(struct wl1271 *wl)
620{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300621 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 int ret = 0;
623
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200624 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625 wl1271_power_on(wl);
626 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200627 wl1271_io_reset(wl);
628 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629
630 /* We don't need a real memory partition here, because we only want
631 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300632 memset(&partition, 0, sizeof(partition));
633 partition.reg.start = REGISTERS_BASE;
634 partition.reg.size = REGISTERS_DOWN_SIZE;
635 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636
637 /* ELP module wake up */
638 wl1271_fw_wakeup(wl);
639
640 /* whal_FwCtrl_BootSm() */
641
642 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200643 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644
645 /* 1. check if chip id is valid */
646
647 switch (wl->chip.id) {
648 case CHIP_ID_1271_PG10:
649 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
650 wl->chip.id);
651
652 ret = wl1271_setup(wl);
653 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200654 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655 break;
656 case CHIP_ID_1271_PG20:
657 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
658 wl->chip.id);
659
660 ret = wl1271_setup(wl);
661 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200662 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663 break;
664 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200665 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300666 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200667 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668 }
669
670 if (wl->fw == NULL) {
671 ret = wl1271_fetch_firmware(wl);
672 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200673 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674 }
675
676 /* No NVS from netlink, try to get it from the filesystem */
677 if (wl->nvs == NULL) {
678 ret = wl1271_fetch_nvs(wl);
679 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200680 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681 }
682
683out:
684 return ret;
685}
686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687int wl1271_plt_start(struct wl1271 *wl)
688{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200689 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 int ret;
691
692 mutex_lock(&wl->mutex);
693
694 wl1271_notice("power up");
695
696 if (wl->state != WL1271_STATE_OFF) {
697 wl1271_error("cannot go into PLT state because not "
698 "in off state: %d", wl->state);
699 ret = -EBUSY;
700 goto out;
701 }
702
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200703 while (retries) {
704 retries--;
705 ret = wl1271_chip_wakeup(wl);
706 if (ret < 0)
707 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300708
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200709 ret = wl1271_boot(wl);
710 if (ret < 0)
711 goto power_off;
712
713 ret = wl1271_plt_init(wl);
714 if (ret < 0)
715 goto irq_disable;
716
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200717 wl->state = WL1271_STATE_PLT;
718 wl1271_notice("firmware booted in PLT mode (%s)",
719 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720 goto out;
721
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200722irq_disable:
723 wl1271_disable_interrupts(wl);
724 mutex_unlock(&wl->mutex);
725 /* Unlocking the mutex in the middle of handling is
726 inherently unsafe. In this case we deem it safe to do,
727 because we need to let any possibly pending IRQ out of
728 the system (and while we are WL1271_STATE_OFF the IRQ
729 work function will not do anything.) Also, any other
730 possible concurrent operations will fail due to the
731 current state, hence the wl1271 struct should be safe. */
732 cancel_work_sync(&wl->irq_work);
733 mutex_lock(&wl->mutex);
734power_off:
735 wl1271_power_off(wl);
736 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200738 wl1271_error("firmware boot in PLT mode failed despite %d retries",
739 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740out:
741 mutex_unlock(&wl->mutex);
742
743 return ret;
744}
745
746int wl1271_plt_stop(struct wl1271 *wl)
747{
748 int ret = 0;
749
750 mutex_lock(&wl->mutex);
751
752 wl1271_notice("power down");
753
754 if (wl->state != WL1271_STATE_PLT) {
755 wl1271_error("cannot power down because not in PLT "
756 "state: %d", wl->state);
757 ret = -EBUSY;
758 goto out;
759 }
760
761 wl1271_disable_interrupts(wl);
762 wl1271_power_off(wl);
763
764 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300765 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766
767out:
768 mutex_unlock(&wl->mutex);
769
770 return ret;
771}
772
773
774static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
775{
776 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200777 struct ieee80211_conf *conf = &hw->conf;
778 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
779 struct ieee80211_sta *sta = txinfo->control.sta;
780 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200782 /* peek into the rates configured in the STA entry */
783 spin_lock_irqsave(&wl->wl_lock, flags);
784 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
785 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
786 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
787 }
788 spin_unlock_irqrestore(&wl->wl_lock, flags);
789
790 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 skb_queue_tail(&wl->tx_queue, skb);
792
793 /*
794 * The chip specific setup must run before the first TX packet -
795 * before that, the tx_work will not be initialized!
796 */
797
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300798 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300799
800 /*
801 * The workqueue is slow to process the tx_queue and we need stop
802 * the queue here, otherwise the queue will get too long.
803 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200804 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
805 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200807 spin_lock_irqsave(&wl->wl_lock, flags);
808 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200809 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200810 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300811 }
812
813 return NETDEV_TX_OK;
814}
815
816static int wl1271_op_start(struct ieee80211_hw *hw)
817{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200818 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
819
820 /*
821 * We have to delay the booting of the hardware because
822 * we need to know the local MAC address before downloading and
823 * initializing the firmware. The MAC address cannot be changed
824 * after boot, and without the proper MAC address, the firmware
825 * will not function properly.
826 *
827 * The MAC address is first known when the corresponding interface
828 * is added. That is where we will initialize the hardware.
829 */
830
831 return 0;
832}
833
834static void wl1271_op_stop(struct ieee80211_hw *hw)
835{
836 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
837}
838
839static int wl1271_op_add_interface(struct ieee80211_hw *hw,
840 struct ieee80211_vif *vif)
841{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200843 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844 int ret = 0;
845
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200846 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
847 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848
849 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200850 if (wl->vif) {
851 ret = -EBUSY;
852 goto out;
853 }
854
855 wl->vif = vif;
856
857 switch (vif->type) {
858 case NL80211_IFTYPE_STATION:
859 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200860 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200861 break;
862 case NL80211_IFTYPE_ADHOC:
863 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200864 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200865 break;
866 default:
867 ret = -EOPNOTSUPP;
868 goto out;
869 }
870
871 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872
873 if (wl->state != WL1271_STATE_OFF) {
874 wl1271_error("cannot start because not in off state: %d",
875 wl->state);
876 ret = -EBUSY;
877 goto out;
878 }
879
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200880 while (retries) {
881 retries--;
882 ret = wl1271_chip_wakeup(wl);
883 if (ret < 0)
884 goto power_off;
885
886 ret = wl1271_boot(wl);
887 if (ret < 0)
888 goto power_off;
889
890 ret = wl1271_hw_init(wl);
891 if (ret < 0)
892 goto irq_disable;
893
894 wl->state = WL1271_STATE_ON;
895 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300896 goto out;
897
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200898irq_disable:
899 wl1271_disable_interrupts(wl);
900 mutex_unlock(&wl->mutex);
901 /* Unlocking the mutex in the middle of handling is
902 inherently unsafe. In this case we deem it safe to do,
903 because we need to let any possibly pending IRQ out of
904 the system (and while we are WL1271_STATE_OFF the IRQ
905 work function will not do anything.) Also, any other
906 possible concurrent operations will fail due to the
907 current state, hence the wl1271 struct should be safe. */
908 cancel_work_sync(&wl->irq_work);
909 mutex_lock(&wl->mutex);
910power_off:
911 wl1271_power_off(wl);
912 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200914 wl1271_error("firmware boot failed despite %d retries",
915 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300916out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917 mutex_unlock(&wl->mutex);
918
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300919 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300920 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300922 return ret;
923}
924
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200925static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
926 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927{
928 struct wl1271 *wl = hw->priv;
929 int i;
930
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200931 mutex_lock(&wl->mutex);
932 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200934 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300935
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300936 list_del(&wl->list);
937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938 WARN_ON(wl->state != WL1271_STATE_ON);
939
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300940 /* enable dyn ps just in case (if left on due to fw crash etc) */
941 ieee80211_disable_dyn_ps(wl->vif, false);
942
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200943 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 mutex_unlock(&wl->mutex);
945 ieee80211_scan_completed(wl->hw, true);
946 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300947 }
948
949 wl->state = WL1271_STATE_OFF;
950
951 wl1271_disable_interrupts(wl);
952
953 mutex_unlock(&wl->mutex);
954
955 cancel_work_sync(&wl->irq_work);
956 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300957 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
959 mutex_lock(&wl->mutex);
960
961 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c42010-05-24 11:18:17 +0300962 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 wl1271_power_off(wl);
964
965 memset(wl->bssid, 0, ETH_ALEN);
966 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
967 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200969 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300970 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971
972 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200973 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
975 wl->tx_blocks_available = 0;
976 wl->tx_results_count = 0;
977 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300978 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200979 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl->time_offset = 0;
981 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200982 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
983 wl->sta_rate_set = 0;
984 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200985 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200986 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 for (i = 0; i < NUM_TX_QUEUES; i++)
989 wl->tx_blocks_freed[i] = 0;
990
991 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300992
993 kfree(wl->fw_status);
994 wl->fw_status = NULL;
995 kfree(wl->tx_res_if);
996 wl->tx_res_if = NULL;
997 kfree(wl->target_mem_map);
998 wl->target_mem_map = NULL;
999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 mutex_unlock(&wl->mutex);
1001}
1002
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001003static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1004{
1005 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1006 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1007
1008 /* combine requested filters with current filter config */
1009 filters = wl->filters | filters;
1010
1011 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1012
1013 if (filters & FIF_PROMISC_IN_BSS) {
1014 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1015 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1016 wl->rx_config |= CFG_BSSID_FILTER_EN;
1017 }
1018 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1019 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1020 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1021 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1022 }
1023 if (filters & FIF_OTHER_BSS) {
1024 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1025 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1026 }
1027 if (filters & FIF_CONTROL) {
1028 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1029 wl->rx_filter |= CFG_RX_CTL_EN;
1030 }
1031 if (filters & FIF_FCSFAIL) {
1032 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1033 wl->rx_filter |= CFG_RX_FCS_ERROR;
1034 }
1035}
1036
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001037static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001038{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001039 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001040 /* we need to use a dummy BSSID for now */
1041 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1042 0xad, 0xbe, 0xef };
1043
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001044 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1045
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001046 /* pass through frames from all BSS */
1047 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1048
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001049 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001050 if (ret < 0)
1051 goto out;
1052
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001053 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001054
1055out:
1056 return ret;
1057}
1058
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001059static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001060{
1061 int ret;
1062
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001063 /*
1064 * One of the side effects of the JOIN command is that is clears
1065 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1066 * to a WPA/WPA2 access point will therefore kill the data-path.
1067 * Currently there is no supported scenario for JOIN during
1068 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1069 * must be handled somehow.
1070 *
1071 */
1072 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1073 wl1271_info("JOIN while associated.");
1074
1075 if (set_assoc)
1076 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1077
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001078 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1079 if (ret < 0)
1080 goto out;
1081
1082 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1083
1084 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1085 goto out;
1086
1087 /*
1088 * The join command disable the keep-alive mode, shut down its process,
1089 * and also clear the template config, so we need to reset it all after
1090 * the join. The acx_aid starts the keep-alive process, and the order
1091 * of the commands below is relevant.
1092 */
1093 ret = wl1271_acx_keep_alive_mode(wl, true);
1094 if (ret < 0)
1095 goto out;
1096
1097 ret = wl1271_acx_aid(wl, wl->aid);
1098 if (ret < 0)
1099 goto out;
1100
1101 ret = wl1271_cmd_build_klv_null_data(wl);
1102 if (ret < 0)
1103 goto out;
1104
1105 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1106 ACX_KEEP_ALIVE_TPL_VALID);
1107 if (ret < 0)
1108 goto out;
1109
1110out:
1111 return ret;
1112}
1113
1114static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001115{
1116 int ret;
1117
1118 /* to stop listening to a channel, we disconnect */
1119 ret = wl1271_cmd_disconnect(wl);
1120 if (ret < 0)
1121 goto out;
1122
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001123 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001124 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001125
1126 /* stop filterting packets based on bssid */
1127 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001128
1129out:
1130 return ret;
1131}
1132
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001133static void wl1271_set_band_rate(struct wl1271 *wl)
1134{
1135 if (wl->band == IEEE80211_BAND_2GHZ)
1136 wl->basic_rate_set = wl->conf.tx.basic_rate;
1137 else
1138 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1139}
1140
1141static u32 wl1271_min_rate_get(struct wl1271 *wl)
1142{
1143 int i;
1144 u32 rate = 0;
1145
1146 if (!wl->basic_rate_set) {
1147 WARN_ON(1);
1148 wl->basic_rate_set = wl->conf.tx.basic_rate;
1149 }
1150
1151 for (i = 0; !rate; i++) {
1152 if ((wl->basic_rate_set >> i) & 0x1)
1153 rate = 1 << i;
1154 }
1155
1156 return rate;
1157}
1158
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001159static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1160{
1161 int ret;
1162
1163 if (idle) {
1164 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1165 ret = wl1271_unjoin(wl);
1166 if (ret < 0)
1167 goto out;
1168 }
1169 wl->rate_set = wl1271_min_rate_get(wl);
1170 wl->sta_rate_set = 0;
1171 ret = wl1271_acx_rate_policies(wl);
1172 if (ret < 0)
1173 goto out;
1174 ret = wl1271_acx_keep_alive_config(
1175 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1176 ACX_KEEP_ALIVE_TPL_INVALID);
1177 if (ret < 0)
1178 goto out;
1179 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1180 } else {
1181 /* increment the session counter */
1182 wl->session_counter++;
1183 if (wl->session_counter >= SESSION_COUNTER_MAX)
1184 wl->session_counter = 0;
1185 ret = wl1271_dummy_join(wl);
1186 if (ret < 0)
1187 goto out;
1188 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1189 }
1190
1191out:
1192 return ret;
1193}
1194
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1196{
1197 struct wl1271 *wl = hw->priv;
1198 struct ieee80211_conf *conf = &hw->conf;
1199 int channel, ret = 0;
1200
1201 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 channel,
1205 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001206 conf->power_level,
1207 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208
Juuso Oikarinen781608c42010-05-24 11:18:17 +03001209 /*
1210 * mac80211 will go to idle nearly immediately after transmitting some
1211 * frames, such as the deauth. To make sure those frames reach the air,
1212 * wait here until the TX queue is fully flushed.
1213 */
1214 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1215 (conf->flags & IEEE80211_CONF_IDLE))
1216 wl1271_tx_flush(wl);
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 mutex_lock(&wl->mutex);
1219
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001220 if (unlikely(wl->state == WL1271_STATE_OFF))
1221 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 ret = wl1271_ps_elp_wakeup(wl, false);
1224 if (ret < 0)
1225 goto out;
1226
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001227 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001228 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1229 ((wl->band != conf->channel->band) ||
1230 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001231 wl->band = conf->channel->band;
1232 wl->channel = channel;
1233
1234 /*
1235 * FIXME: the mac80211 should really provide a fixed rate
1236 * to use here. for now, just use the smallest possible rate
1237 * for the band as a fixed rate for association frames and
1238 * other control messages.
1239 */
1240 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1241 wl1271_set_band_rate(wl);
1242
1243 wl->basic_rate = wl1271_min_rate_get(wl);
1244 ret = wl1271_acx_rate_policies(wl);
1245 if (ret < 0)
1246 wl1271_warning("rate policy for update channel "
1247 "failed %d", ret);
1248
1249 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001250 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001251 if (ret < 0)
1252 wl1271_warning("cmd join to update channel "
1253 "failed %d", ret);
1254 }
1255 }
1256
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001257 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001258 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1259 if (ret < 0)
1260 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261 }
1262
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001263 /*
1264 * if mac80211 changes the PSM mode, make sure the mode is not
1265 * incorrectly changed after the pspoll failure active window.
1266 */
1267 if (changed & IEEE80211_CONF_CHANGE_PS)
1268 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1269
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001270 if (conf->flags & IEEE80211_CONF_PS &&
1271 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1272 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 /*
1275 * We enter PSM only if we're already associated.
1276 * If we're not, we'll enter it when joining an SSID,
1277 * through the bss_info_changed() hook.
1278 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001279 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001280 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001281 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1282 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001283 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001285 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001286 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001288 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001290 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001291 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1292 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 }
1294
1295 if (conf->power_level != wl->power_level) {
1296 ret = wl1271_acx_tx_power(wl, conf->power_level);
1297 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001298 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299
1300 wl->power_level = conf->power_level;
1301 }
1302
1303out_sleep:
1304 wl1271_ps_elp_sleep(wl);
1305
1306out:
1307 mutex_unlock(&wl->mutex);
1308
1309 return ret;
1310}
1311
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001312struct wl1271_filter_params {
1313 bool enabled;
1314 int mc_list_length;
1315 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1316};
1317
Jiri Pirko22bedad32010-04-01 21:22:57 +00001318static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1319 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001320{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001322 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001323 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001324
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001325 if (unlikely(wl->state == WL1271_STATE_OFF))
1326 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001327
Juuso Oikarinen74441132009-10-13 12:47:53 +03001328 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329 if (!fp) {
1330 wl1271_error("Out of memory setting filters.");
1331 return 0;
1332 }
1333
1334 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001335 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001336 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1337 fp->enabled = false;
1338 } else {
1339 fp->enabled = true;
1340 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001341 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001342 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001343 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001344 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001345 }
1346
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001347 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001348}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001350#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1351 FIF_ALLMULTI | \
1352 FIF_FCSFAIL | \
1353 FIF_BCN_PRBRESP_PROMISC | \
1354 FIF_CONTROL | \
1355 FIF_OTHER_BSS)
1356
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1358 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001359 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001361 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364
1365 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1366
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001367 mutex_lock(&wl->mutex);
1368
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001369 *total &= WL1271_SUPPORTED_FILTERS;
1370 changed &= WL1271_SUPPORTED_FILTERS;
1371
1372 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001373 goto out;
1374
1375 ret = wl1271_ps_elp_wakeup(wl, false);
1376 if (ret < 0)
1377 goto out;
1378
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001379
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001380 if (*total & FIF_ALLMULTI)
1381 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1382 else if (fp)
1383 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1384 fp->mc_list,
1385 fp->mc_list_length);
1386 if (ret < 0)
1387 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001388
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001389 /* determine, whether supported filter values have changed */
1390 if (changed == 0)
1391 goto out_sleep;
1392
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001393 /* configure filters */
1394 wl->filters = *total;
1395 wl1271_configure_filters(wl, 0);
1396
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001397 /* apply configured filters */
1398 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1399 if (ret < 0)
1400 goto out_sleep;
1401
1402out_sleep:
1403 wl1271_ps_elp_sleep(wl);
1404
1405out:
1406 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001407 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408}
1409
1410static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1411 struct ieee80211_vif *vif,
1412 struct ieee80211_sta *sta,
1413 struct ieee80211_key_conf *key_conf)
1414{
1415 struct wl1271 *wl = hw->priv;
1416 const u8 *addr;
1417 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001418 u32 tx_seq_32 = 0;
1419 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 u8 key_type;
1421
1422 static const u8 bcast_addr[ETH_ALEN] =
1423 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1424
1425 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1426
1427 addr = sta ? sta->addr : bcast_addr;
1428
1429 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1430 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1431 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1432 key_conf->alg, key_conf->keyidx,
1433 key_conf->keylen, key_conf->flags);
1434 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1435
1436 if (is_zero_ether_addr(addr)) {
1437 /* We dont support TX only encryption */
1438 ret = -EOPNOTSUPP;
1439 goto out;
1440 }
1441
1442 mutex_lock(&wl->mutex);
1443
1444 ret = wl1271_ps_elp_wakeup(wl, false);
1445 if (ret < 0)
1446 goto out_unlock;
1447
1448 switch (key_conf->alg) {
1449 case ALG_WEP:
1450 key_type = KEY_WEP;
1451
1452 key_conf->hw_key_idx = key_conf->keyidx;
1453 break;
1454 case ALG_TKIP:
1455 key_type = KEY_TKIP;
1456
1457 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001458 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1459 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 break;
1461 case ALG_CCMP:
1462 key_type = KEY_AES;
1463
1464 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001465 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1466 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001467 break;
1468 default:
1469 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1470
1471 ret = -EOPNOTSUPP;
1472 goto out_sleep;
1473 }
1474
1475 switch (cmd) {
1476 case SET_KEY:
1477 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1478 key_conf->keyidx, key_type,
1479 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001480 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001481 if (ret < 0) {
1482 wl1271_error("Could not add or replace key");
1483 goto out_sleep;
1484 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001485
1486 /* the default WEP key needs to be configured at least once */
1487 if (key_type == KEY_WEP) {
1488 ret = wl1271_cmd_set_default_wep_key(wl,
1489 wl->default_key);
1490 if (ret < 0)
1491 goto out_sleep;
1492 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 break;
1494
1495 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001496 /* The wl1271 does not allow to remove unicast keys - they
1497 will be cleared automatically on next CMD_JOIN. Ignore the
1498 request silently, as we dont want the mac80211 to emit
1499 an error message. */
1500 if (!is_broadcast_ether_addr(addr))
1501 break;
1502
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1504 key_conf->keyidx, key_type,
1505 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001506 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 if (ret < 0) {
1508 wl1271_error("Could not remove key");
1509 goto out_sleep;
1510 }
1511 break;
1512
1513 default:
1514 wl1271_error("Unsupported key cmd 0x%x", cmd);
1515 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 break;
1517 }
1518
1519out_sleep:
1520 wl1271_ps_elp_sleep(wl);
1521
1522out_unlock:
1523 mutex_unlock(&wl->mutex);
1524
1525out:
1526 return ret;
1527}
1528
1529static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001530 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 struct cfg80211_scan_request *req)
1532{
1533 struct wl1271 *wl = hw->priv;
1534 int ret;
1535 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001536 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537
1538 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1539
1540 if (req->n_ssids) {
1541 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001542 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 }
1544
1545 mutex_lock(&wl->mutex);
1546
1547 ret = wl1271_ps_elp_wakeup(wl, false);
1548 if (ret < 0)
1549 goto out;
1550
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001551 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001552 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1553 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001554 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001555 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1556 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557
1558 wl1271_ps_elp_sleep(wl);
1559
1560out:
1561 mutex_unlock(&wl->mutex);
1562
1563 return ret;
1564}
1565
1566static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1567{
1568 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001569 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570
1571 mutex_lock(&wl->mutex);
1572
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001573 if (unlikely(wl->state == WL1271_STATE_OFF))
1574 goto out;
1575
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001576 ret = wl1271_ps_elp_wakeup(wl, false);
1577 if (ret < 0)
1578 goto out;
1579
1580 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1581 if (ret < 0)
1582 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1583
1584 wl1271_ps_elp_sleep(wl);
1585
1586out:
1587 mutex_unlock(&wl->mutex);
1588
1589 return ret;
1590}
1591
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001592static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1593{
1594 u8 *ptr = beacon->data +
1595 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1596
1597 /* find the location of the ssid in the beacon */
1598 while (ptr < beacon->data + beacon->len) {
1599 if (ptr[0] == WLAN_EID_SSID) {
1600 wl->ssid_len = ptr[1];
1601 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1602 return;
1603 }
1604 ptr += ptr[1];
1605 }
1606 wl1271_error("ad-hoc beacon template has no SSID!\n");
1607}
1608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001609static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1610 struct ieee80211_vif *vif,
1611 struct ieee80211_bss_conf *bss_conf,
1612 u32 changed)
1613{
1614 enum wl1271_cmd_ps_mode mode;
1615 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001616 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001617 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001618 int ret;
1619
1620 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1621
1622 mutex_lock(&wl->mutex);
1623
1624 ret = wl1271_ps_elp_wakeup(wl, false);
1625 if (ret < 0)
1626 goto out;
1627
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001628 if ((changed && BSS_CHANGED_BEACON_INT) &&
1629 (wl->bss_type == BSS_TYPE_IBSS)) {
1630 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1631 bss_conf->beacon_int);
1632
1633 wl->beacon_int = bss_conf->beacon_int;
1634 do_join = true;
1635 }
1636
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001637 if ((changed && BSS_CHANGED_BEACON) &&
1638 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001639 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1640
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001641 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1642
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001643 if (beacon) {
1644 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001645
1646 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001647 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1648 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001649 beacon->len, 0,
1650 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001651
1652 if (ret < 0) {
1653 dev_kfree_skb(beacon);
1654 goto out_sleep;
1655 }
1656
1657 hdr = (struct ieee80211_hdr *) beacon->data;
1658 hdr->frame_control = cpu_to_le16(
1659 IEEE80211_FTYPE_MGMT |
1660 IEEE80211_STYPE_PROBE_RESP);
1661
1662 ret = wl1271_cmd_template_set(wl,
1663 CMD_TEMPL_PROBE_RESPONSE,
1664 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001665 beacon->len, 0,
1666 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001667 dev_kfree_skb(beacon);
1668 if (ret < 0)
1669 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001670
1671 /* Need to update the SSID (for filtering etc) */
1672 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001673 }
1674 }
1675
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001676 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1677 (wl->bss_type == BSS_TYPE_IBSS)) {
1678 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1679 bss_conf->enable_beacon ? "enabled" : "disabled");
1680
1681 if (bss_conf->enable_beacon)
1682 wl->set_bss_type = BSS_TYPE_IBSS;
1683 else
1684 wl->set_bss_type = BSS_TYPE_STA_BSS;
1685 do_join = true;
1686 }
1687
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001688 if (changed & BSS_CHANGED_CQM) {
1689 bool enable = false;
1690 if (bss_conf->cqm_rssi_thold)
1691 enable = true;
1692 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1693 bss_conf->cqm_rssi_thold,
1694 bss_conf->cqm_rssi_hyst);
1695 if (ret < 0)
1696 goto out;
1697 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1698 }
1699
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001700 if ((changed & BSS_CHANGED_BSSID) &&
1701 /*
1702 * Now we know the correct bssid, so we send a new join command
1703 * and enable the BSSID filter
1704 */
1705 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001706 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001707
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001708 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001709 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001710 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001711
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001712 ret = wl1271_build_qos_null_data(wl);
1713 if (ret < 0)
1714 goto out_sleep;
1715
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001716 /* filter out all packets not from this BSSID */
1717 wl1271_configure_filters(wl, 0);
1718
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001719 /* Need to update the BSSID (for filtering etc) */
1720 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001721 }
1722
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 if (changed & BSS_CHANGED_ASSOC) {
1724 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001725 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001727 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001729 wl->ps_poll_failures = 0;
1730
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001731 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001732 * use basic rates from AP, and determine lowest rate
1733 * to use with control frames.
1734 */
1735 rates = bss_conf->basic_rates;
1736 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1737 rates);
1738 wl->basic_rate = wl1271_min_rate_get(wl);
1739 ret = wl1271_acx_rate_policies(wl);
1740 if (ret < 0)
1741 goto out_sleep;
1742
1743 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001744 * with wl1271, we don't need to update the
1745 * beacon_int and dtim_period, because the firmware
1746 * updates it by itself when the first beacon is
1747 * received after a join.
1748 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001749 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1750 if (ret < 0)
1751 goto out_sleep;
1752
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001753 /*
1754 * The SSID is intentionally set to NULL here - the
1755 * firmware will set the probe request with a
1756 * broadcast SSID regardless of what we set in the
1757 * template.
1758 */
1759 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1760 NULL, 0, wl->band);
1761
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001762 /* enable the connection monitoring feature */
1763 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764 if (ret < 0)
1765 goto out_sleep;
1766
1767 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001768 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1769 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001771 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 if (ret < 0)
1773 goto out_sleep;
1774 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001775 } else {
1776 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001777 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001778 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001779
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001780 /* re-enable dynamic ps - just in case */
1781 ieee80211_disable_dyn_ps(wl->vif, false);
1782
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001783 /* revert back to minimum rates for the current band */
1784 wl1271_set_band_rate(wl);
1785 wl->basic_rate = wl1271_min_rate_get(wl);
1786 ret = wl1271_acx_rate_policies(wl);
1787 if (ret < 0)
1788 goto out_sleep;
1789
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001790 /* disable connection monitor features */
1791 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001792
1793 /* Disable the keep-alive feature */
1794 ret = wl1271_acx_keep_alive_mode(wl, false);
1795
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001796 if (ret < 0)
1797 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001799
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 if (changed & BSS_CHANGED_ERP_SLOT) {
1803 if (bss_conf->use_short_slot)
1804 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1805 else
1806 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1807 if (ret < 0) {
1808 wl1271_warning("Set slot time failed %d", ret);
1809 goto out_sleep;
1810 }
1811 }
1812
1813 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1814 if (bss_conf->use_short_preamble)
1815 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1816 else
1817 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1818 }
1819
1820 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1821 if (bss_conf->use_cts_prot)
1822 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1823 else
1824 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1825 if (ret < 0) {
1826 wl1271_warning("Set ctsprotect failed %d", ret);
1827 goto out_sleep;
1828 }
1829 }
1830
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001831 if (changed & BSS_CHANGED_ARP_FILTER) {
1832 __be32 addr = bss_conf->arp_addr_list[0];
1833 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1834
1835 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1836 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1837 else
1838 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1839
1840 if (ret < 0)
1841 goto out_sleep;
1842 }
1843
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001844 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001845 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001846 if (ret < 0) {
1847 wl1271_warning("cmd join failed %d", ret);
1848 goto out_sleep;
1849 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001850 }
1851
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852out_sleep:
1853 wl1271_ps_elp_sleep(wl);
1854
1855out:
1856 mutex_unlock(&wl->mutex);
1857}
1858
Kalle Valoc6999d82010-02-18 13:25:41 +02001859static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1860 const struct ieee80211_tx_queue_params *params)
1861{
1862 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001863 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001864 int ret;
1865
1866 mutex_lock(&wl->mutex);
1867
1868 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1869
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001870 ret = wl1271_ps_elp_wakeup(wl, false);
1871 if (ret < 0)
1872 goto out;
1873
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001874 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001875 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1876 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001877 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001878 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001879 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001880
Kalle Valo4695dc92010-03-18 12:26:38 +02001881 if (params->uapsd)
1882 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1883 else
1884 ps_scheme = CONF_PS_SCHEME_LEGACY;
1885
Kalle Valoc6999d82010-02-18 13:25:41 +02001886 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1887 CONF_CHANNEL_TYPE_EDCF,
1888 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001889 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001890 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001891 goto out_sleep;
1892
1893out_sleep:
1894 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001895
1896out:
1897 mutex_unlock(&wl->mutex);
1898
1899 return ret;
1900}
1901
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001902static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1903{
1904
1905 struct wl1271 *wl = hw->priv;
1906 u64 mactime = ULLONG_MAX;
1907 int ret;
1908
1909 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1910
1911 mutex_lock(&wl->mutex);
1912
1913 ret = wl1271_ps_elp_wakeup(wl, false);
1914 if (ret < 0)
1915 goto out;
1916
1917 ret = wl1271_acx_tsf_info(wl, &mactime);
1918 if (ret < 0)
1919 goto out_sleep;
1920
1921out_sleep:
1922 wl1271_ps_elp_sleep(wl);
1923
1924out:
1925 mutex_unlock(&wl->mutex);
1926 return mactime;
1927}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928
1929/* can't be const, mac80211 writes to this */
1930static struct ieee80211_rate wl1271_rates[] = {
1931 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001932 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1933 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001935 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1936 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1938 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001939 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1940 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1942 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001943 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1944 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1946 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001947 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1948 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001950 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1951 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001953 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1954 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001956 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1957 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001959 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1960 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001962 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1963 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001965 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1966 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001968 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1969 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970};
1971
1972/* can't be const, mac80211 writes to this */
1973static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001974 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1975 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1976 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1977 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1978 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1979 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1980 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1981 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1982 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1983 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1984 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1985 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1986 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987};
1988
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001989/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02001990static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001991 /* MCS rates are used only with 11n */
1992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1993 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2000
2001 11, /* CONF_HW_RXTX_RATE_54 */
2002 10, /* CONF_HW_RXTX_RATE_48 */
2003 9, /* CONF_HW_RXTX_RATE_36 */
2004 8, /* CONF_HW_RXTX_RATE_24 */
2005
2006 /* TI-specific rate */
2007 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2008
2009 7, /* CONF_HW_RXTX_RATE_18 */
2010 6, /* CONF_HW_RXTX_RATE_12 */
2011 3, /* CONF_HW_RXTX_RATE_11 */
2012 5, /* CONF_HW_RXTX_RATE_9 */
2013 4, /* CONF_HW_RXTX_RATE_6 */
2014 2, /* CONF_HW_RXTX_RATE_5_5 */
2015 1, /* CONF_HW_RXTX_RATE_2 */
2016 0 /* CONF_HW_RXTX_RATE_1 */
2017};
2018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019/* can't be const, mac80211 writes to this */
2020static struct ieee80211_supported_band wl1271_band_2ghz = {
2021 .channels = wl1271_channels,
2022 .n_channels = ARRAY_SIZE(wl1271_channels),
2023 .bitrates = wl1271_rates,
2024 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2025};
2026
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002027/* 5 GHz data rates for WL1273 */
2028static struct ieee80211_rate wl1271_rates_5ghz[] = {
2029 { .bitrate = 60,
2030 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2032 { .bitrate = 90,
2033 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2035 { .bitrate = 120,
2036 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2037 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2038 { .bitrate = 180,
2039 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2040 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2041 { .bitrate = 240,
2042 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2043 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2044 { .bitrate = 360,
2045 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2046 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2047 { .bitrate = 480,
2048 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2049 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2050 { .bitrate = 540,
2051 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2052 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2053};
2054
2055/* 5 GHz band channels for WL1273 */
2056static struct ieee80211_channel wl1271_channels_5ghz[] = {
2057 { .hw_value = 183, .center_freq = 4915},
2058 { .hw_value = 184, .center_freq = 4920},
2059 { .hw_value = 185, .center_freq = 4925},
2060 { .hw_value = 187, .center_freq = 4935},
2061 { .hw_value = 188, .center_freq = 4940},
2062 { .hw_value = 189, .center_freq = 4945},
2063 { .hw_value = 192, .center_freq = 4960},
2064 { .hw_value = 196, .center_freq = 4980},
2065 { .hw_value = 7, .center_freq = 5035},
2066 { .hw_value = 8, .center_freq = 5040},
2067 { .hw_value = 9, .center_freq = 5045},
2068 { .hw_value = 11, .center_freq = 5055},
2069 { .hw_value = 12, .center_freq = 5060},
2070 { .hw_value = 16, .center_freq = 5080},
2071 { .hw_value = 34, .center_freq = 5170},
2072 { .hw_value = 36, .center_freq = 5180},
2073 { .hw_value = 38, .center_freq = 5190},
2074 { .hw_value = 40, .center_freq = 5200},
2075 { .hw_value = 42, .center_freq = 5210},
2076 { .hw_value = 44, .center_freq = 5220},
2077 { .hw_value = 46, .center_freq = 5230},
2078 { .hw_value = 48, .center_freq = 5240},
2079 { .hw_value = 52, .center_freq = 5260},
2080 { .hw_value = 56, .center_freq = 5280},
2081 { .hw_value = 60, .center_freq = 5300},
2082 { .hw_value = 64, .center_freq = 5320},
2083 { .hw_value = 100, .center_freq = 5500},
2084 { .hw_value = 104, .center_freq = 5520},
2085 { .hw_value = 108, .center_freq = 5540},
2086 { .hw_value = 112, .center_freq = 5560},
2087 { .hw_value = 116, .center_freq = 5580},
2088 { .hw_value = 120, .center_freq = 5600},
2089 { .hw_value = 124, .center_freq = 5620},
2090 { .hw_value = 128, .center_freq = 5640},
2091 { .hw_value = 132, .center_freq = 5660},
2092 { .hw_value = 136, .center_freq = 5680},
2093 { .hw_value = 140, .center_freq = 5700},
2094 { .hw_value = 149, .center_freq = 5745},
2095 { .hw_value = 153, .center_freq = 5765},
2096 { .hw_value = 157, .center_freq = 5785},
2097 { .hw_value = 161, .center_freq = 5805},
2098 { .hw_value = 165, .center_freq = 5825},
2099};
2100
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002101/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002102static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002103 /* MCS rates are used only with 11n */
2104 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2106 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2107 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2112
2113 7, /* CONF_HW_RXTX_RATE_54 */
2114 6, /* CONF_HW_RXTX_RATE_48 */
2115 5, /* CONF_HW_RXTX_RATE_36 */
2116 4, /* CONF_HW_RXTX_RATE_24 */
2117
2118 /* TI-specific rate */
2119 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2120
2121 3, /* CONF_HW_RXTX_RATE_18 */
2122 2, /* CONF_HW_RXTX_RATE_12 */
2123 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2124 1, /* CONF_HW_RXTX_RATE_9 */
2125 0, /* CONF_HW_RXTX_RATE_6 */
2126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2129};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002130
2131static struct ieee80211_supported_band wl1271_band_5ghz = {
2132 .channels = wl1271_channels_5ghz,
2133 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2134 .bitrates = wl1271_rates_5ghz,
2135 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2136};
2137
Tobias Klausera0ea9492010-05-20 10:38:11 +02002138static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002139 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2140 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2141};
2142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143static const struct ieee80211_ops wl1271_ops = {
2144 .start = wl1271_op_start,
2145 .stop = wl1271_op_stop,
2146 .add_interface = wl1271_op_add_interface,
2147 .remove_interface = wl1271_op_remove_interface,
2148 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002149 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150 .configure_filter = wl1271_op_configure_filter,
2151 .tx = wl1271_op_tx,
2152 .set_key = wl1271_op_set_key,
2153 .hw_scan = wl1271_op_hw_scan,
2154 .bss_info_changed = wl1271_op_bss_info_changed,
2155 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002156 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002157 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002158 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002159};
2160
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002161
2162u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2163{
2164 u8 idx;
2165
2166 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2167
2168 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2169 wl1271_error("Illegal RX rate from HW: %d", rate);
2170 return 0;
2171 }
2172
2173 idx = wl1271_band_rate_to_idx[wl->band][rate];
2174 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2175 wl1271_error("Unsupported RX rate from HW: %d", rate);
2176 return 0;
2177 }
2178
2179 return idx;
2180}
2181
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002182static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2183 struct device_attribute *attr,
2184 char *buf)
2185{
2186 struct wl1271 *wl = dev_get_drvdata(dev);
2187 ssize_t len;
2188
2189 /* FIXME: what's the maximum length of buf? page size?*/
2190 len = 500;
2191
2192 mutex_lock(&wl->mutex);
2193 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2194 wl->sg_enabled);
2195 mutex_unlock(&wl->mutex);
2196
2197 return len;
2198
2199}
2200
2201static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2202 struct device_attribute *attr,
2203 const char *buf, size_t count)
2204{
2205 struct wl1271 *wl = dev_get_drvdata(dev);
2206 unsigned long res;
2207 int ret;
2208
2209 ret = strict_strtoul(buf, 10, &res);
2210
2211 if (ret < 0) {
2212 wl1271_warning("incorrect value written to bt_coex_mode");
2213 return count;
2214 }
2215
2216 mutex_lock(&wl->mutex);
2217
2218 res = !!res;
2219
2220 if (res == wl->sg_enabled)
2221 goto out;
2222
2223 wl->sg_enabled = res;
2224
2225 if (wl->state == WL1271_STATE_OFF)
2226 goto out;
2227
2228 ret = wl1271_ps_elp_wakeup(wl, false);
2229 if (ret < 0)
2230 goto out;
2231
2232 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2233 wl1271_ps_elp_sleep(wl);
2234
2235 out:
2236 mutex_unlock(&wl->mutex);
2237 return count;
2238}
2239
2240static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2241 wl1271_sysfs_show_bt_coex_state,
2242 wl1271_sysfs_store_bt_coex_state);
2243
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002244static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2245 struct device_attribute *attr,
2246 char *buf)
2247{
2248 struct wl1271 *wl = dev_get_drvdata(dev);
2249 ssize_t len;
2250
2251 /* FIXME: what's the maximum length of buf? page size?*/
2252 len = 500;
2253
2254 mutex_lock(&wl->mutex);
2255 if (wl->hw_pg_ver >= 0)
2256 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2257 else
2258 len = snprintf(buf, len, "n/a\n");
2259 mutex_unlock(&wl->mutex);
2260
2261 return len;
2262}
2263
2264static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2265 wl1271_sysfs_show_hw_pg_ver, NULL);
2266
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002267int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002268{
2269 int ret;
2270
2271 if (wl->mac80211_registered)
2272 return 0;
2273
2274 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2275
2276 ret = ieee80211_register_hw(wl->hw);
2277 if (ret < 0) {
2278 wl1271_error("unable to register mac80211 hw: %d", ret);
2279 return ret;
2280 }
2281
2282 wl->mac80211_registered = true;
2283
2284 wl1271_notice("loaded");
2285
2286 return 0;
2287}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002288EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002290void wl1271_unregister_hw(struct wl1271 *wl)
2291{
2292 ieee80211_unregister_hw(wl->hw);
2293 wl->mac80211_registered = false;
2294
2295}
2296EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2297
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002298int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002300 /* The tx descriptor buffer and the TKIP space. */
2301 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2302 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303
2304 /* unit us */
2305 /* FIXME: find a proper value */
2306 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002307 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308
2309 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002310 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002311 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002312 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002313 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002314 IEEE80211_HW_CONNECTION_MONITOR |
2315 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002317 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2318 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319 wl->hw->wiphy->max_scan_ssids = 1;
2320 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2321
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002322 if (wl1271_11a_enabled())
2323 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2324
Kalle Valo12bd8942010-03-18 12:26:33 +02002325 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002326 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002327
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002328 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329
2330 return 0;
2331}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002332EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002335
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002336struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002339 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002341 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342
2343 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2344 if (!hw) {
2345 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002346 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002347 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002348 }
2349
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002350 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2351 if (!plat_dev) {
2352 wl1271_error("could not allocate platform_device");
2353 ret = -ENOMEM;
2354 goto err_plat_alloc;
2355 }
2356
2357 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002359 wl = hw->priv;
2360 memset(wl, 0, sizeof(*wl));
2361
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002362 INIT_LIST_HEAD(&wl->list);
2363
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002365 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366
2367 skb_queue_head_init(&wl->tx_queue);
2368
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002369 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002370 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002372 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 wl->rx_counter = 0;
2375 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2376 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002377 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002379 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002380 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002381 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2382 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002383 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002384 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002385 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002386 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002387 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002389 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 wl->tx_frames[i] = NULL;
2391
2392 spin_lock_init(&wl->wl_lock);
2393
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394 wl->state = WL1271_STATE_OFF;
2395 mutex_init(&wl->mutex);
2396
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002397 /* Apply default driver configuration. */
2398 wl1271_conf_init(wl);
2399
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002400 wl1271_debugfs_init(wl);
2401
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002402 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002403 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002404 if (ret) {
2405 wl1271_error("couldn't register platform device");
2406 goto err_hw;
2407 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002408 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002409
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002410 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002411 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002412 if (ret < 0) {
2413 wl1271_error("failed to create sysfs file bt_coex_state");
2414 goto err_platform;
2415 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002416
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002417 /* Create sysfs file to get HW PG version */
2418 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2419 if (ret < 0) {
2420 wl1271_error("failed to create sysfs file hw_pg_ver");
2421 goto err_bt_coex_state;
2422 }
2423
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002424 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002425
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002426err_bt_coex_state:
2427 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2428
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002429err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002430 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002431
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002432err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002433 wl1271_debugfs_exit(wl);
2434 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002435
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002436err_plat_alloc:
2437 ieee80211_free_hw(hw);
2438
2439err_hw_alloc:
2440
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002441 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002442}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002443EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002444
2445int wl1271_free_hw(struct wl1271 *wl)
2446{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002447 platform_device_unregister(wl->plat_dev);
2448 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002449
2450 wl1271_debugfs_exit(wl);
2451
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002452 vfree(wl->fw);
2453 wl->fw = NULL;
2454 kfree(wl->nvs);
2455 wl->nvs = NULL;
2456
2457 kfree(wl->fw_status);
2458 kfree(wl->tx_res_if);
2459
2460 ieee80211_free_hw(wl->hw);
2461
2462 return 0;
2463}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002464EXPORT_SYMBOL_GPL(wl1271_free_hw);
2465
2466MODULE_LICENSE("GPL");
2467MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2468MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");