blob: 70c6b0d22353f99f8d3f8430dc518547ac6c9287 [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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300941 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300942 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300943
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200944 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 mutex_unlock(&wl->mutex);
946 ieee80211_scan_completed(wl->hw, true);
947 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 }
949
950 wl->state = WL1271_STATE_OFF;
951
952 wl1271_disable_interrupts(wl);
953
954 mutex_unlock(&wl->mutex);
955
956 cancel_work_sync(&wl->irq_work);
957 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300958 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300959
960 mutex_lock(&wl->mutex);
961
962 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300963 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964 wl1271_power_off(wl);
965
966 memset(wl->bssid, 0, ETH_ALEN);
967 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
968 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300969 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200970 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300971 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972
973 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200974 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
976 wl->tx_blocks_available = 0;
977 wl->tx_results_count = 0;
978 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300979 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200980 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981 wl->time_offset = 0;
982 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200983 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
984 wl->sta_rate_set = 0;
985 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200986 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200987 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 for (i = 0; i < NUM_TX_QUEUES; i++)
990 wl->tx_blocks_freed[i] = 0;
991
992 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300993
994 kfree(wl->fw_status);
995 wl->fw_status = NULL;
996 kfree(wl->tx_res_if);
997 wl->tx_res_if = NULL;
998 kfree(wl->target_mem_map);
999 wl->target_mem_map = NULL;
1000
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 mutex_unlock(&wl->mutex);
1002}
1003
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001004static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1005{
1006 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1007 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1008
1009 /* combine requested filters with current filter config */
1010 filters = wl->filters | filters;
1011
1012 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1013
1014 if (filters & FIF_PROMISC_IN_BSS) {
1015 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1016 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1017 wl->rx_config |= CFG_BSSID_FILTER_EN;
1018 }
1019 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1020 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1021 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1022 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1023 }
1024 if (filters & FIF_OTHER_BSS) {
1025 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1026 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1027 }
1028 if (filters & FIF_CONTROL) {
1029 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1030 wl->rx_filter |= CFG_RX_CTL_EN;
1031 }
1032 if (filters & FIF_FCSFAIL) {
1033 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1034 wl->rx_filter |= CFG_RX_FCS_ERROR;
1035 }
1036}
1037
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001038static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001039{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001040 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001041 /* we need to use a dummy BSSID for now */
1042 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1043 0xad, 0xbe, 0xef };
1044
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001045 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1046
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001047 /* pass through frames from all BSS */
1048 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1049
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001050 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001051 if (ret < 0)
1052 goto out;
1053
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001054 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001055
1056out:
1057 return ret;
1058}
1059
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001060static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001061{
1062 int ret;
1063
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001064 /*
1065 * One of the side effects of the JOIN command is that is clears
1066 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1067 * to a WPA/WPA2 access point will therefore kill the data-path.
1068 * Currently there is no supported scenario for JOIN during
1069 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1070 * must be handled somehow.
1071 *
1072 */
1073 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1074 wl1271_info("JOIN while associated.");
1075
1076 if (set_assoc)
1077 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1078
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001079 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1080 if (ret < 0)
1081 goto out;
1082
1083 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1084
1085 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1086 goto out;
1087
1088 /*
1089 * The join command disable the keep-alive mode, shut down its process,
1090 * and also clear the template config, so we need to reset it all after
1091 * the join. The acx_aid starts the keep-alive process, and the order
1092 * of the commands below is relevant.
1093 */
1094 ret = wl1271_acx_keep_alive_mode(wl, true);
1095 if (ret < 0)
1096 goto out;
1097
1098 ret = wl1271_acx_aid(wl, wl->aid);
1099 if (ret < 0)
1100 goto out;
1101
1102 ret = wl1271_cmd_build_klv_null_data(wl);
1103 if (ret < 0)
1104 goto out;
1105
1106 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1107 ACX_KEEP_ALIVE_TPL_VALID);
1108 if (ret < 0)
1109 goto out;
1110
1111out:
1112 return ret;
1113}
1114
1115static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001116{
1117 int ret;
1118
1119 /* to stop listening to a channel, we disconnect */
1120 ret = wl1271_cmd_disconnect(wl);
1121 if (ret < 0)
1122 goto out;
1123
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001124 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001125 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001126
1127 /* stop filterting packets based on bssid */
1128 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001129
1130out:
1131 return ret;
1132}
1133
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001134static void wl1271_set_band_rate(struct wl1271 *wl)
1135{
1136 if (wl->band == IEEE80211_BAND_2GHZ)
1137 wl->basic_rate_set = wl->conf.tx.basic_rate;
1138 else
1139 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1140}
1141
1142static u32 wl1271_min_rate_get(struct wl1271 *wl)
1143{
1144 int i;
1145 u32 rate = 0;
1146
1147 if (!wl->basic_rate_set) {
1148 WARN_ON(1);
1149 wl->basic_rate_set = wl->conf.tx.basic_rate;
1150 }
1151
1152 for (i = 0; !rate; i++) {
1153 if ((wl->basic_rate_set >> i) & 0x1)
1154 rate = 1 << i;
1155 }
1156
1157 return rate;
1158}
1159
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001160static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1161{
1162 int ret;
1163
1164 if (idle) {
1165 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1166 ret = wl1271_unjoin(wl);
1167 if (ret < 0)
1168 goto out;
1169 }
1170 wl->rate_set = wl1271_min_rate_get(wl);
1171 wl->sta_rate_set = 0;
1172 ret = wl1271_acx_rate_policies(wl);
1173 if (ret < 0)
1174 goto out;
1175 ret = wl1271_acx_keep_alive_config(
1176 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1177 ACX_KEEP_ALIVE_TPL_INVALID);
1178 if (ret < 0)
1179 goto out;
1180 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1181 } else {
1182 /* increment the session counter */
1183 wl->session_counter++;
1184 if (wl->session_counter >= SESSION_COUNTER_MAX)
1185 wl->session_counter = 0;
1186 ret = wl1271_dummy_join(wl);
1187 if (ret < 0)
1188 goto out;
1189 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1190 }
1191
1192out:
1193 return ret;
1194}
1195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1197{
1198 struct wl1271 *wl = hw->priv;
1199 struct ieee80211_conf *conf = &hw->conf;
1200 int channel, ret = 0;
1201
1202 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1203
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001204 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 channel,
1206 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001207 conf->power_level,
1208 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001210 /*
1211 * mac80211 will go to idle nearly immediately after transmitting some
1212 * frames, such as the deauth. To make sure those frames reach the air,
1213 * wait here until the TX queue is fully flushed.
1214 */
1215 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1216 (conf->flags & IEEE80211_CONF_IDLE))
1217 wl1271_tx_flush(wl);
1218
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219 mutex_lock(&wl->mutex);
1220
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001221 if (unlikely(wl->state == WL1271_STATE_OFF))
1222 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001223
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224 ret = wl1271_ps_elp_wakeup(wl, false);
1225 if (ret < 0)
1226 goto out;
1227
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001228 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001229 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1230 ((wl->band != conf->channel->band) ||
1231 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001232 wl->band = conf->channel->band;
1233 wl->channel = channel;
1234
1235 /*
1236 * FIXME: the mac80211 should really provide a fixed rate
1237 * to use here. for now, just use the smallest possible rate
1238 * for the band as a fixed rate for association frames and
1239 * other control messages.
1240 */
1241 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1242 wl1271_set_band_rate(wl);
1243
1244 wl->basic_rate = wl1271_min_rate_get(wl);
1245 ret = wl1271_acx_rate_policies(wl);
1246 if (ret < 0)
1247 wl1271_warning("rate policy for update channel "
1248 "failed %d", ret);
1249
1250 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001251 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001252 if (ret < 0)
1253 wl1271_warning("cmd join to update channel "
1254 "failed %d", ret);
1255 }
1256 }
1257
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001258 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001259 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1260 if (ret < 0)
1261 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262 }
1263
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001264 /*
1265 * if mac80211 changes the PSM mode, make sure the mode is not
1266 * incorrectly changed after the pspoll failure active window.
1267 */
1268 if (changed & IEEE80211_CONF_CHANGE_PS)
1269 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1270
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001271 if (conf->flags & IEEE80211_CONF_PS &&
1272 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1273 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274
1275 /*
1276 * We enter PSM only if we're already associated.
1277 * If we're not, we'll enter it when joining an SSID,
1278 * through the bss_info_changed() hook.
1279 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001280 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001281 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001282 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1283 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001284 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001286 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001287 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001289 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001291 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001292 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1293 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 }
1295
1296 if (conf->power_level != wl->power_level) {
1297 ret = wl1271_acx_tx_power(wl, conf->power_level);
1298 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001299 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 wl->power_level = conf->power_level;
1302 }
1303
1304out_sleep:
1305 wl1271_ps_elp_sleep(wl);
1306
1307out:
1308 mutex_unlock(&wl->mutex);
1309
1310 return ret;
1311}
1312
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313struct wl1271_filter_params {
1314 bool enabled;
1315 int mc_list_length;
1316 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1317};
1318
Jiri Pirko22bedad32010-04-01 21:22:57 +00001319static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1320 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001322 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001323 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001324 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001325
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001326 if (unlikely(wl->state == WL1271_STATE_OFF))
1327 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001328
Juuso Oikarinen74441132009-10-13 12:47:53 +03001329 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001330 if (!fp) {
1331 wl1271_error("Out of memory setting filters.");
1332 return 0;
1333 }
1334
1335 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001336 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001337 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1338 fp->enabled = false;
1339 } else {
1340 fp->enabled = true;
1341 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001342 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001343 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001344 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001345 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346 }
1347
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001349}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001351#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1352 FIF_ALLMULTI | \
1353 FIF_FCSFAIL | \
1354 FIF_BCN_PRBRESP_PROMISC | \
1355 FIF_CONTROL | \
1356 FIF_OTHER_BSS)
1357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1359 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001362 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001364 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365
1366 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1367
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001368 mutex_lock(&wl->mutex);
1369
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001370 *total &= WL1271_SUPPORTED_FILTERS;
1371 changed &= WL1271_SUPPORTED_FILTERS;
1372
1373 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001374 goto out;
1375
1376 ret = wl1271_ps_elp_wakeup(wl, false);
1377 if (ret < 0)
1378 goto out;
1379
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001381 if (*total & FIF_ALLMULTI)
1382 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1383 else if (fp)
1384 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1385 fp->mc_list,
1386 fp->mc_list_length);
1387 if (ret < 0)
1388 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001390 /* determine, whether supported filter values have changed */
1391 if (changed == 0)
1392 goto out_sleep;
1393
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001394 /* configure filters */
1395 wl->filters = *total;
1396 wl1271_configure_filters(wl, 0);
1397
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001398 /* apply configured filters */
1399 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1400 if (ret < 0)
1401 goto out_sleep;
1402
1403out_sleep:
1404 wl1271_ps_elp_sleep(wl);
1405
1406out:
1407 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001408 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001409}
1410
1411static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1412 struct ieee80211_vif *vif,
1413 struct ieee80211_sta *sta,
1414 struct ieee80211_key_conf *key_conf)
1415{
1416 struct wl1271 *wl = hw->priv;
1417 const u8 *addr;
1418 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001419 u32 tx_seq_32 = 0;
1420 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421 u8 key_type;
1422
1423 static const u8 bcast_addr[ETH_ALEN] =
1424 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1425
1426 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1427
1428 addr = sta ? sta->addr : bcast_addr;
1429
1430 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1431 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1432 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1433 key_conf->alg, key_conf->keyidx,
1434 key_conf->keylen, key_conf->flags);
1435 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1436
1437 if (is_zero_ether_addr(addr)) {
1438 /* We dont support TX only encryption */
1439 ret = -EOPNOTSUPP;
1440 goto out;
1441 }
1442
1443 mutex_lock(&wl->mutex);
1444
1445 ret = wl1271_ps_elp_wakeup(wl, false);
1446 if (ret < 0)
1447 goto out_unlock;
1448
1449 switch (key_conf->alg) {
1450 case ALG_WEP:
1451 key_type = KEY_WEP;
1452
1453 key_conf->hw_key_idx = key_conf->keyidx;
1454 break;
1455 case ALG_TKIP:
1456 key_type = KEY_TKIP;
1457
1458 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001459 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1460 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 break;
1462 case ALG_CCMP:
1463 key_type = KEY_AES;
1464
1465 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001466 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1467 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468 break;
1469 default:
1470 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1471
1472 ret = -EOPNOTSUPP;
1473 goto out_sleep;
1474 }
1475
1476 switch (cmd) {
1477 case SET_KEY:
1478 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1479 key_conf->keyidx, key_type,
1480 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001481 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 if (ret < 0) {
1483 wl1271_error("Could not add or replace key");
1484 goto out_sleep;
1485 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001486
1487 /* the default WEP key needs to be configured at least once */
1488 if (key_type == KEY_WEP) {
1489 ret = wl1271_cmd_set_default_wep_key(wl,
1490 wl->default_key);
1491 if (ret < 0)
1492 goto out_sleep;
1493 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494 break;
1495
1496 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001497 /* The wl1271 does not allow to remove unicast keys - they
1498 will be cleared automatically on next CMD_JOIN. Ignore the
1499 request silently, as we dont want the mac80211 to emit
1500 an error message. */
1501 if (!is_broadcast_ether_addr(addr))
1502 break;
1503
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1505 key_conf->keyidx, key_type,
1506 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001507 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 if (ret < 0) {
1509 wl1271_error("Could not remove key");
1510 goto out_sleep;
1511 }
1512 break;
1513
1514 default:
1515 wl1271_error("Unsupported key cmd 0x%x", cmd);
1516 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517 break;
1518 }
1519
1520out_sleep:
1521 wl1271_ps_elp_sleep(wl);
1522
1523out_unlock:
1524 mutex_unlock(&wl->mutex);
1525
1526out:
1527 return ret;
1528}
1529
1530static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001531 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 struct cfg80211_scan_request *req)
1533{
1534 struct wl1271 *wl = hw->priv;
1535 int ret;
1536 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001537 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538
1539 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1540
1541 if (req->n_ssids) {
1542 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001543 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 }
1545
1546 mutex_lock(&wl->mutex);
1547
1548 ret = wl1271_ps_elp_wakeup(wl, false);
1549 if (ret < 0)
1550 goto out;
1551
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001552 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001553 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1554 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001555 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001556 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1557 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558
1559 wl1271_ps_elp_sleep(wl);
1560
1561out:
1562 mutex_unlock(&wl->mutex);
1563
1564 return ret;
1565}
1566
1567static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1568{
1569 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001570 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571
1572 mutex_lock(&wl->mutex);
1573
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001574 if (unlikely(wl->state == WL1271_STATE_OFF))
1575 goto out;
1576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 ret = wl1271_ps_elp_wakeup(wl, false);
1578 if (ret < 0)
1579 goto out;
1580
1581 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1582 if (ret < 0)
1583 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1584
1585 wl1271_ps_elp_sleep(wl);
1586
1587out:
1588 mutex_unlock(&wl->mutex);
1589
1590 return ret;
1591}
1592
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001593static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1594{
1595 u8 *ptr = beacon->data +
1596 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1597
1598 /* find the location of the ssid in the beacon */
1599 while (ptr < beacon->data + beacon->len) {
1600 if (ptr[0] == WLAN_EID_SSID) {
1601 wl->ssid_len = ptr[1];
1602 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1603 return;
1604 }
1605 ptr += ptr[1];
1606 }
1607 wl1271_error("ad-hoc beacon template has no SSID!\n");
1608}
1609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1611 struct ieee80211_vif *vif,
1612 struct ieee80211_bss_conf *bss_conf,
1613 u32 changed)
1614{
1615 enum wl1271_cmd_ps_mode mode;
1616 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001617 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001618 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 int ret;
1620
1621 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1622
1623 mutex_lock(&wl->mutex);
1624
1625 ret = wl1271_ps_elp_wakeup(wl, false);
1626 if (ret < 0)
1627 goto out;
1628
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001629 if ((changed && BSS_CHANGED_BEACON_INT) &&
1630 (wl->bss_type == BSS_TYPE_IBSS)) {
1631 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1632 bss_conf->beacon_int);
1633
1634 wl->beacon_int = bss_conf->beacon_int;
1635 do_join = true;
1636 }
1637
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001638 if ((changed && BSS_CHANGED_BEACON) &&
1639 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001640 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1641
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001642 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1643
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 if (beacon) {
1645 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001646
1647 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1649 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001650 beacon->len, 0,
1651 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001652
1653 if (ret < 0) {
1654 dev_kfree_skb(beacon);
1655 goto out_sleep;
1656 }
1657
1658 hdr = (struct ieee80211_hdr *) beacon->data;
1659 hdr->frame_control = cpu_to_le16(
1660 IEEE80211_FTYPE_MGMT |
1661 IEEE80211_STYPE_PROBE_RESP);
1662
1663 ret = wl1271_cmd_template_set(wl,
1664 CMD_TEMPL_PROBE_RESPONSE,
1665 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001666 beacon->len, 0,
1667 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001668 dev_kfree_skb(beacon);
1669 if (ret < 0)
1670 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001671
1672 /* Need to update the SSID (for filtering etc) */
1673 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001674 }
1675 }
1676
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001677 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1678 (wl->bss_type == BSS_TYPE_IBSS)) {
1679 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1680 bss_conf->enable_beacon ? "enabled" : "disabled");
1681
1682 if (bss_conf->enable_beacon)
1683 wl->set_bss_type = BSS_TYPE_IBSS;
1684 else
1685 wl->set_bss_type = BSS_TYPE_STA_BSS;
1686 do_join = true;
1687 }
1688
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001689 if (changed & BSS_CHANGED_CQM) {
1690 bool enable = false;
1691 if (bss_conf->cqm_rssi_thold)
1692 enable = true;
1693 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1694 bss_conf->cqm_rssi_thold,
1695 bss_conf->cqm_rssi_hyst);
1696 if (ret < 0)
1697 goto out;
1698 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1699 }
1700
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001701 if ((changed & BSS_CHANGED_BSSID) &&
1702 /*
1703 * Now we know the correct bssid, so we send a new join command
1704 * and enable the BSSID filter
1705 */
1706 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001707 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001708
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001709 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001710 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001711 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001712
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001713 ret = wl1271_build_qos_null_data(wl);
1714 if (ret < 0)
1715 goto out_sleep;
1716
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001717 /* filter out all packets not from this BSSID */
1718 wl1271_configure_filters(wl, 0);
1719
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001720 /* Need to update the BSSID (for filtering etc) */
1721 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001722 }
1723
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724 if (changed & BSS_CHANGED_ASSOC) {
1725 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001726 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001728 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001730 wl->ps_poll_failures = 0;
1731
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001732 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001733 * use basic rates from AP, and determine lowest rate
1734 * to use with control frames.
1735 */
1736 rates = bss_conf->basic_rates;
1737 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1738 rates);
1739 wl->basic_rate = wl1271_min_rate_get(wl);
1740 ret = wl1271_acx_rate_policies(wl);
1741 if (ret < 0)
1742 goto out_sleep;
1743
1744 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001745 * with wl1271, we don't need to update the
1746 * beacon_int and dtim_period, because the firmware
1747 * updates it by itself when the first beacon is
1748 * received after a join.
1749 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1751 if (ret < 0)
1752 goto out_sleep;
1753
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001754 /*
1755 * The SSID is intentionally set to NULL here - the
1756 * firmware will set the probe request with a
1757 * broadcast SSID regardless of what we set in the
1758 * template.
1759 */
1760 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1761 NULL, 0, wl->band);
1762
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001763 /* enable the connection monitoring feature */
1764 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001765 if (ret < 0)
1766 goto out_sleep;
1767
1768 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001769 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1770 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001772 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773 if (ret < 0)
1774 goto out_sleep;
1775 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001776 } else {
1777 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001778 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001779 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001780
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001781 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001782 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001783
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001784 /* revert back to minimum rates for the current band */
1785 wl1271_set_band_rate(wl);
1786 wl->basic_rate = wl1271_min_rate_get(wl);
1787 ret = wl1271_acx_rate_policies(wl);
1788 if (ret < 0)
1789 goto out_sleep;
1790
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001791 /* disable connection monitor features */
1792 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001793
1794 /* Disable the keep-alive feature */
1795 ret = wl1271_acx_keep_alive_mode(wl, false);
1796
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001797 if (ret < 0)
1798 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 if (changed & BSS_CHANGED_ERP_SLOT) {
1804 if (bss_conf->use_short_slot)
1805 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1806 else
1807 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1808 if (ret < 0) {
1809 wl1271_warning("Set slot time failed %d", ret);
1810 goto out_sleep;
1811 }
1812 }
1813
1814 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1815 if (bss_conf->use_short_preamble)
1816 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1817 else
1818 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1819 }
1820
1821 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1822 if (bss_conf->use_cts_prot)
1823 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1824 else
1825 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1826 if (ret < 0) {
1827 wl1271_warning("Set ctsprotect failed %d", ret);
1828 goto out_sleep;
1829 }
1830 }
1831
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001832 if (changed & BSS_CHANGED_ARP_FILTER) {
1833 __be32 addr = bss_conf->arp_addr_list[0];
1834 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1835
1836 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1837 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1838 else
1839 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1840
1841 if (ret < 0)
1842 goto out_sleep;
1843 }
1844
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001845 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001846 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001847 if (ret < 0) {
1848 wl1271_warning("cmd join failed %d", ret);
1849 goto out_sleep;
1850 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001851 }
1852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853out_sleep:
1854 wl1271_ps_elp_sleep(wl);
1855
1856out:
1857 mutex_unlock(&wl->mutex);
1858}
1859
Kalle Valoc6999d82010-02-18 13:25:41 +02001860static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1861 const struct ieee80211_tx_queue_params *params)
1862{
1863 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001864 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001865 int ret;
1866
1867 mutex_lock(&wl->mutex);
1868
1869 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1870
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001871 ret = wl1271_ps_elp_wakeup(wl, false);
1872 if (ret < 0)
1873 goto out;
1874
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001875 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001876 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1877 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001878 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001879 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001880 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001881
Kalle Valo4695dc92010-03-18 12:26:38 +02001882 if (params->uapsd)
1883 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1884 else
1885 ps_scheme = CONF_PS_SCHEME_LEGACY;
1886
Kalle Valoc6999d82010-02-18 13:25:41 +02001887 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1888 CONF_CHANNEL_TYPE_EDCF,
1889 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001890 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001891 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001892 goto out_sleep;
1893
1894out_sleep:
1895 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001896
1897out:
1898 mutex_unlock(&wl->mutex);
1899
1900 return ret;
1901}
1902
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001903static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1904{
1905
1906 struct wl1271 *wl = hw->priv;
1907 u64 mactime = ULLONG_MAX;
1908 int ret;
1909
1910 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1911
1912 mutex_lock(&wl->mutex);
1913
1914 ret = wl1271_ps_elp_wakeup(wl, false);
1915 if (ret < 0)
1916 goto out;
1917
1918 ret = wl1271_acx_tsf_info(wl, &mactime);
1919 if (ret < 0)
1920 goto out_sleep;
1921
1922out_sleep:
1923 wl1271_ps_elp_sleep(wl);
1924
1925out:
1926 mutex_unlock(&wl->mutex);
1927 return mactime;
1928}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929
1930/* can't be const, mac80211 writes to this */
1931static struct ieee80211_rate wl1271_rates[] = {
1932 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001933 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1934 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001936 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1937 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1939 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001940 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1941 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1943 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001944 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1945 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1947 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001948 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1949 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001951 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1952 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001954 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1955 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001957 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1958 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001963 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1964 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001966 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1967 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001969 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1970 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971};
1972
1973/* can't be const, mac80211 writes to this */
1974static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001975 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1976 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1977 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1978 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1979 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1980 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1981 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1982 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1983 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1984 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1985 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1986 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1987 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988};
1989
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001990/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02001991static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001992 /* MCS rates are used only with 11n */
1993 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2000 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2001
2002 11, /* CONF_HW_RXTX_RATE_54 */
2003 10, /* CONF_HW_RXTX_RATE_48 */
2004 9, /* CONF_HW_RXTX_RATE_36 */
2005 8, /* CONF_HW_RXTX_RATE_24 */
2006
2007 /* TI-specific rate */
2008 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2009
2010 7, /* CONF_HW_RXTX_RATE_18 */
2011 6, /* CONF_HW_RXTX_RATE_12 */
2012 3, /* CONF_HW_RXTX_RATE_11 */
2013 5, /* CONF_HW_RXTX_RATE_9 */
2014 4, /* CONF_HW_RXTX_RATE_6 */
2015 2, /* CONF_HW_RXTX_RATE_5_5 */
2016 1, /* CONF_HW_RXTX_RATE_2 */
2017 0 /* CONF_HW_RXTX_RATE_1 */
2018};
2019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002020/* can't be const, mac80211 writes to this */
2021static struct ieee80211_supported_band wl1271_band_2ghz = {
2022 .channels = wl1271_channels,
2023 .n_channels = ARRAY_SIZE(wl1271_channels),
2024 .bitrates = wl1271_rates,
2025 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2026};
2027
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002028/* 5 GHz data rates for WL1273 */
2029static struct ieee80211_rate wl1271_rates_5ghz[] = {
2030 { .bitrate = 60,
2031 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2032 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2033 { .bitrate = 90,
2034 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2035 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2036 { .bitrate = 120,
2037 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2038 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2039 { .bitrate = 180,
2040 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2041 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2042 { .bitrate = 240,
2043 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2044 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2045 { .bitrate = 360,
2046 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2047 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2048 { .bitrate = 480,
2049 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2050 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2051 { .bitrate = 540,
2052 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2053 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2054};
2055
2056/* 5 GHz band channels for WL1273 */
2057static struct ieee80211_channel wl1271_channels_5ghz[] = {
2058 { .hw_value = 183, .center_freq = 4915},
2059 { .hw_value = 184, .center_freq = 4920},
2060 { .hw_value = 185, .center_freq = 4925},
2061 { .hw_value = 187, .center_freq = 4935},
2062 { .hw_value = 188, .center_freq = 4940},
2063 { .hw_value = 189, .center_freq = 4945},
2064 { .hw_value = 192, .center_freq = 4960},
2065 { .hw_value = 196, .center_freq = 4980},
2066 { .hw_value = 7, .center_freq = 5035},
2067 { .hw_value = 8, .center_freq = 5040},
2068 { .hw_value = 9, .center_freq = 5045},
2069 { .hw_value = 11, .center_freq = 5055},
2070 { .hw_value = 12, .center_freq = 5060},
2071 { .hw_value = 16, .center_freq = 5080},
2072 { .hw_value = 34, .center_freq = 5170},
2073 { .hw_value = 36, .center_freq = 5180},
2074 { .hw_value = 38, .center_freq = 5190},
2075 { .hw_value = 40, .center_freq = 5200},
2076 { .hw_value = 42, .center_freq = 5210},
2077 { .hw_value = 44, .center_freq = 5220},
2078 { .hw_value = 46, .center_freq = 5230},
2079 { .hw_value = 48, .center_freq = 5240},
2080 { .hw_value = 52, .center_freq = 5260},
2081 { .hw_value = 56, .center_freq = 5280},
2082 { .hw_value = 60, .center_freq = 5300},
2083 { .hw_value = 64, .center_freq = 5320},
2084 { .hw_value = 100, .center_freq = 5500},
2085 { .hw_value = 104, .center_freq = 5520},
2086 { .hw_value = 108, .center_freq = 5540},
2087 { .hw_value = 112, .center_freq = 5560},
2088 { .hw_value = 116, .center_freq = 5580},
2089 { .hw_value = 120, .center_freq = 5600},
2090 { .hw_value = 124, .center_freq = 5620},
2091 { .hw_value = 128, .center_freq = 5640},
2092 { .hw_value = 132, .center_freq = 5660},
2093 { .hw_value = 136, .center_freq = 5680},
2094 { .hw_value = 140, .center_freq = 5700},
2095 { .hw_value = 149, .center_freq = 5745},
2096 { .hw_value = 153, .center_freq = 5765},
2097 { .hw_value = 157, .center_freq = 5785},
2098 { .hw_value = 161, .center_freq = 5805},
2099 { .hw_value = 165, .center_freq = 5825},
2100};
2101
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002102/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002103static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002104 /* MCS rates are used only with 11n */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2106 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2107 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2112 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2113
2114 7, /* CONF_HW_RXTX_RATE_54 */
2115 6, /* CONF_HW_RXTX_RATE_48 */
2116 5, /* CONF_HW_RXTX_RATE_36 */
2117 4, /* CONF_HW_RXTX_RATE_24 */
2118
2119 /* TI-specific rate */
2120 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2121
2122 3, /* CONF_HW_RXTX_RATE_18 */
2123 2, /* CONF_HW_RXTX_RATE_12 */
2124 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2125 1, /* CONF_HW_RXTX_RATE_9 */
2126 0, /* CONF_HW_RXTX_RATE_6 */
2127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2129 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2130};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002131
2132static struct ieee80211_supported_band wl1271_band_5ghz = {
2133 .channels = wl1271_channels_5ghz,
2134 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2135 .bitrates = wl1271_rates_5ghz,
2136 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2137};
2138
Tobias Klausera0ea9492010-05-20 10:38:11 +02002139static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002140 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2141 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2142};
2143
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144static const struct ieee80211_ops wl1271_ops = {
2145 .start = wl1271_op_start,
2146 .stop = wl1271_op_stop,
2147 .add_interface = wl1271_op_add_interface,
2148 .remove_interface = wl1271_op_remove_interface,
2149 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002150 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002151 .configure_filter = wl1271_op_configure_filter,
2152 .tx = wl1271_op_tx,
2153 .set_key = wl1271_op_set_key,
2154 .hw_scan = wl1271_op_hw_scan,
2155 .bss_info_changed = wl1271_op_bss_info_changed,
2156 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002157 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002158 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002159 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160};
2161
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002162
2163u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2164{
2165 u8 idx;
2166
2167 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2168
2169 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2170 wl1271_error("Illegal RX rate from HW: %d", rate);
2171 return 0;
2172 }
2173
2174 idx = wl1271_band_rate_to_idx[wl->band][rate];
2175 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2176 wl1271_error("Unsupported RX rate from HW: %d", rate);
2177 return 0;
2178 }
2179
2180 return idx;
2181}
2182
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002183static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2184 struct device_attribute *attr,
2185 char *buf)
2186{
2187 struct wl1271 *wl = dev_get_drvdata(dev);
2188 ssize_t len;
2189
2190 /* FIXME: what's the maximum length of buf? page size?*/
2191 len = 500;
2192
2193 mutex_lock(&wl->mutex);
2194 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2195 wl->sg_enabled);
2196 mutex_unlock(&wl->mutex);
2197
2198 return len;
2199
2200}
2201
2202static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2203 struct device_attribute *attr,
2204 const char *buf, size_t count)
2205{
2206 struct wl1271 *wl = dev_get_drvdata(dev);
2207 unsigned long res;
2208 int ret;
2209
2210 ret = strict_strtoul(buf, 10, &res);
2211
2212 if (ret < 0) {
2213 wl1271_warning("incorrect value written to bt_coex_mode");
2214 return count;
2215 }
2216
2217 mutex_lock(&wl->mutex);
2218
2219 res = !!res;
2220
2221 if (res == wl->sg_enabled)
2222 goto out;
2223
2224 wl->sg_enabled = res;
2225
2226 if (wl->state == WL1271_STATE_OFF)
2227 goto out;
2228
2229 ret = wl1271_ps_elp_wakeup(wl, false);
2230 if (ret < 0)
2231 goto out;
2232
2233 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2234 wl1271_ps_elp_sleep(wl);
2235
2236 out:
2237 mutex_unlock(&wl->mutex);
2238 return count;
2239}
2240
2241static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2242 wl1271_sysfs_show_bt_coex_state,
2243 wl1271_sysfs_store_bt_coex_state);
2244
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002245static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2246 struct device_attribute *attr,
2247 char *buf)
2248{
2249 struct wl1271 *wl = dev_get_drvdata(dev);
2250 ssize_t len;
2251
2252 /* FIXME: what's the maximum length of buf? page size?*/
2253 len = 500;
2254
2255 mutex_lock(&wl->mutex);
2256 if (wl->hw_pg_ver >= 0)
2257 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2258 else
2259 len = snprintf(buf, len, "n/a\n");
2260 mutex_unlock(&wl->mutex);
2261
2262 return len;
2263}
2264
2265static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2266 wl1271_sysfs_show_hw_pg_ver, NULL);
2267
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002268int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002269{
2270 int ret;
2271
2272 if (wl->mac80211_registered)
2273 return 0;
2274
2275 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2276
2277 ret = ieee80211_register_hw(wl->hw);
2278 if (ret < 0) {
2279 wl1271_error("unable to register mac80211 hw: %d", ret);
2280 return ret;
2281 }
2282
2283 wl->mac80211_registered = true;
2284
2285 wl1271_notice("loaded");
2286
2287 return 0;
2288}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002289EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002291void wl1271_unregister_hw(struct wl1271 *wl)
2292{
2293 ieee80211_unregister_hw(wl->hw);
2294 wl->mac80211_registered = false;
2295
2296}
2297EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2298
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002299int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002300{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002301 /* The tx descriptor buffer and the TKIP space. */
2302 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2303 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304
2305 /* unit us */
2306 /* FIXME: find a proper value */
2307 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002308 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002309
2310 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002311 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002312 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002313 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002314 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002315 IEEE80211_HW_CONNECTION_MONITOR |
2316 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002318 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2319 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320 wl->hw->wiphy->max_scan_ssids = 1;
2321 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2322
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002323 if (wl1271_11a_enabled())
2324 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2325
Kalle Valo12bd8942010-03-18 12:26:33 +02002326 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002327 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002328
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002329 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330
2331 return 0;
2332}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002333EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002336
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002337struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002339 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002340 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002342 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343
2344 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2345 if (!hw) {
2346 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002347 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002348 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349 }
2350
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002351 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2352 if (!plat_dev) {
2353 wl1271_error("could not allocate platform_device");
2354 ret = -ENOMEM;
2355 goto err_plat_alloc;
2356 }
2357
2358 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360 wl = hw->priv;
2361 memset(wl, 0, sizeof(*wl));
2362
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002363 INIT_LIST_HEAD(&wl->list);
2364
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002366 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367
2368 skb_queue_head_init(&wl->tx_queue);
2369
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002370 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002371 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002373 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 wl->rx_counter = 0;
2376 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2377 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002378 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002380 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002381 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002382 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2383 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002384 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002385 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002386 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002387 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002388 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002390 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391 wl->tx_frames[i] = NULL;
2392
2393 spin_lock_init(&wl->wl_lock);
2394
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 wl->state = WL1271_STATE_OFF;
2396 mutex_init(&wl->mutex);
2397
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002398 /* Apply default driver configuration. */
2399 wl1271_conf_init(wl);
2400
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002401 wl1271_debugfs_init(wl);
2402
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002403 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002404 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002405 if (ret) {
2406 wl1271_error("couldn't register platform device");
2407 goto err_hw;
2408 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002409 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002410
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002411 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002412 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002413 if (ret < 0) {
2414 wl1271_error("failed to create sysfs file bt_coex_state");
2415 goto err_platform;
2416 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002417
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002418 /* Create sysfs file to get HW PG version */
2419 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2420 if (ret < 0) {
2421 wl1271_error("failed to create sysfs file hw_pg_ver");
2422 goto err_bt_coex_state;
2423 }
2424
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002425 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002426
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002427err_bt_coex_state:
2428 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2429
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002430err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002431 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002432
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002433err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002434 wl1271_debugfs_exit(wl);
2435 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002436
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002437err_plat_alloc:
2438 ieee80211_free_hw(hw);
2439
2440err_hw_alloc:
2441
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002442 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002443}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002444EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002445
2446int wl1271_free_hw(struct wl1271 *wl)
2447{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002448 platform_device_unregister(wl->plat_dev);
2449 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002450
2451 wl1271_debugfs_exit(wl);
2452
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002453 vfree(wl->fw);
2454 wl->fw = NULL;
2455 kfree(wl->nvs);
2456 wl->nvs = NULL;
2457
2458 kfree(wl->fw_status);
2459 kfree(wl->tx_res_if);
2460
2461 ieee80211_free_hw(wl->hw);
2462
2463 return 0;
2464}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002465EXPORT_SYMBOL_GPL(wl1271_free_hw);
2466
2467MODULE_LICENSE("GPL");
2468MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2469MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");