blob: 15c99dd7677494ff3f8d6dcc1af79ec51e3ac587 [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,
57 [CONF_SG_AUTO_PS_MODE] = 0,
58 [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 Oikarinen71449f82009-12-11 15:41:07 +0200940 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 mutex_unlock(&wl->mutex);
942 ieee80211_scan_completed(wl->hw, true);
943 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 }
945
946 wl->state = WL1271_STATE_OFF;
947
948 wl1271_disable_interrupts(wl);
949
950 mutex_unlock(&wl->mutex);
951
952 cancel_work_sync(&wl->irq_work);
953 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300954 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
956 mutex_lock(&wl->mutex);
957
958 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300959 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960 wl1271_power_off(wl);
961
962 memset(wl->bssid, 0, ETH_ALEN);
963 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
964 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200966 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300967 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968
969 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200970 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
972 wl->tx_blocks_available = 0;
973 wl->tx_results_count = 0;
974 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300975 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200976 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 wl->time_offset = 0;
978 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200979 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
980 wl->sta_rate_set = 0;
981 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200982 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200983 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300984
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 for (i = 0; i < NUM_TX_QUEUES; i++)
986 wl->tx_blocks_freed[i] = 0;
987
988 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300989
990 kfree(wl->fw_status);
991 wl->fw_status = NULL;
992 kfree(wl->tx_res_if);
993 wl->tx_res_if = NULL;
994 kfree(wl->target_mem_map);
995 wl->target_mem_map = NULL;
996
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997 mutex_unlock(&wl->mutex);
998}
999
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001000static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1001{
1002 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1003 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1004
1005 /* combine requested filters with current filter config */
1006 filters = wl->filters | filters;
1007
1008 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1009
1010 if (filters & FIF_PROMISC_IN_BSS) {
1011 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1012 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1013 wl->rx_config |= CFG_BSSID_FILTER_EN;
1014 }
1015 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1016 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1017 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1018 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1019 }
1020 if (filters & FIF_OTHER_BSS) {
1021 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1022 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1023 }
1024 if (filters & FIF_CONTROL) {
1025 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1026 wl->rx_filter |= CFG_RX_CTL_EN;
1027 }
1028 if (filters & FIF_FCSFAIL) {
1029 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1030 wl->rx_filter |= CFG_RX_FCS_ERROR;
1031 }
1032}
1033
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001034static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001035{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001036 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001037 /* we need to use a dummy BSSID for now */
1038 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1039 0xad, 0xbe, 0xef };
1040
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001041 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1042
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001043 /* pass through frames from all BSS */
1044 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1045
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001046 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001047 if (ret < 0)
1048 goto out;
1049
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001050 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001051
1052out:
1053 return ret;
1054}
1055
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001056static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001057{
1058 int ret;
1059
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001060 /*
1061 * One of the side effects of the JOIN command is that is clears
1062 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1063 * to a WPA/WPA2 access point will therefore kill the data-path.
1064 * Currently there is no supported scenario for JOIN during
1065 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1066 * must be handled somehow.
1067 *
1068 */
1069 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1070 wl1271_info("JOIN while associated.");
1071
1072 if (set_assoc)
1073 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1074
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001075 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1076 if (ret < 0)
1077 goto out;
1078
1079 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1080
1081 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1082 goto out;
1083
1084 /*
1085 * The join command disable the keep-alive mode, shut down its process,
1086 * and also clear the template config, so we need to reset it all after
1087 * the join. The acx_aid starts the keep-alive process, and the order
1088 * of the commands below is relevant.
1089 */
1090 ret = wl1271_acx_keep_alive_mode(wl, true);
1091 if (ret < 0)
1092 goto out;
1093
1094 ret = wl1271_acx_aid(wl, wl->aid);
1095 if (ret < 0)
1096 goto out;
1097
1098 ret = wl1271_cmd_build_klv_null_data(wl);
1099 if (ret < 0)
1100 goto out;
1101
1102 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1103 ACX_KEEP_ALIVE_TPL_VALID);
1104 if (ret < 0)
1105 goto out;
1106
1107out:
1108 return ret;
1109}
1110
1111static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001112{
1113 int ret;
1114
1115 /* to stop listening to a channel, we disconnect */
1116 ret = wl1271_cmd_disconnect(wl);
1117 if (ret < 0)
1118 goto out;
1119
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001120 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001121 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001122
1123 /* stop filterting packets based on bssid */
1124 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001125
1126out:
1127 return ret;
1128}
1129
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001130static void wl1271_set_band_rate(struct wl1271 *wl)
1131{
1132 if (wl->band == IEEE80211_BAND_2GHZ)
1133 wl->basic_rate_set = wl->conf.tx.basic_rate;
1134 else
1135 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1136}
1137
1138static u32 wl1271_min_rate_get(struct wl1271 *wl)
1139{
1140 int i;
1141 u32 rate = 0;
1142
1143 if (!wl->basic_rate_set) {
1144 WARN_ON(1);
1145 wl->basic_rate_set = wl->conf.tx.basic_rate;
1146 }
1147
1148 for (i = 0; !rate; i++) {
1149 if ((wl->basic_rate_set >> i) & 0x1)
1150 rate = 1 << i;
1151 }
1152
1153 return rate;
1154}
1155
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001156static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1157{
1158 int ret;
1159
1160 if (idle) {
1161 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1162 ret = wl1271_unjoin(wl);
1163 if (ret < 0)
1164 goto out;
1165 }
1166 wl->rate_set = wl1271_min_rate_get(wl);
1167 wl->sta_rate_set = 0;
1168 ret = wl1271_acx_rate_policies(wl);
1169 if (ret < 0)
1170 goto out;
1171 ret = wl1271_acx_keep_alive_config(
1172 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1173 ACX_KEEP_ALIVE_TPL_INVALID);
1174 if (ret < 0)
1175 goto out;
1176 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1177 } else {
1178 /* increment the session counter */
1179 wl->session_counter++;
1180 if (wl->session_counter >= SESSION_COUNTER_MAX)
1181 wl->session_counter = 0;
1182 ret = wl1271_dummy_join(wl);
1183 if (ret < 0)
1184 goto out;
1185 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1186 }
1187
1188out:
1189 return ret;
1190}
1191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1193{
1194 struct wl1271 *wl = hw->priv;
1195 struct ieee80211_conf *conf = &hw->conf;
1196 int channel, ret = 0;
1197
1198 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1199
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001200 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 channel,
1202 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 conf->power_level,
1204 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001206 /*
1207 * mac80211 will go to idle nearly immediately after transmitting some
1208 * frames, such as the deauth. To make sure those frames reach the air,
1209 * wait here until the TX queue is fully flushed.
1210 */
1211 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1212 (conf->flags & IEEE80211_CONF_IDLE))
1213 wl1271_tx_flush(wl);
1214
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215 mutex_lock(&wl->mutex);
1216
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001217 if (unlikely(wl->state == WL1271_STATE_OFF))
1218 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 ret = wl1271_ps_elp_wakeup(wl, false);
1221 if (ret < 0)
1222 goto out;
1223
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001224 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001225 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1226 ((wl->band != conf->channel->band) ||
1227 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001228 wl->band = conf->channel->band;
1229 wl->channel = channel;
1230
1231 /*
1232 * FIXME: the mac80211 should really provide a fixed rate
1233 * to use here. for now, just use the smallest possible rate
1234 * for the band as a fixed rate for association frames and
1235 * other control messages.
1236 */
1237 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1238 wl1271_set_band_rate(wl);
1239
1240 wl->basic_rate = wl1271_min_rate_get(wl);
1241 ret = wl1271_acx_rate_policies(wl);
1242 if (ret < 0)
1243 wl1271_warning("rate policy for update channel "
1244 "failed %d", ret);
1245
1246 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001247 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001248 if (ret < 0)
1249 wl1271_warning("cmd join to update channel "
1250 "failed %d", ret);
1251 }
1252 }
1253
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001254 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001255 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1256 if (ret < 0)
1257 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001258 }
1259
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001260 /*
1261 * if mac80211 changes the PSM mode, make sure the mode is not
1262 * incorrectly changed after the pspoll failure active window.
1263 */
1264 if (changed & IEEE80211_CONF_CHANGE_PS)
1265 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1266
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001267 if (conf->flags & IEEE80211_CONF_PS &&
1268 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1269 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
1271 /*
1272 * We enter PSM only if we're already associated.
1273 * If we're not, we'll enter it when joining an SSID,
1274 * through the bss_info_changed() hook.
1275 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001276 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001277 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001278 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1279 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001280 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001282 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001283 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001285 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001287 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001288 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1289 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 }
1291
1292 if (conf->power_level != wl->power_level) {
1293 ret = wl1271_acx_tx_power(wl, conf->power_level);
1294 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001295 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296
1297 wl->power_level = conf->power_level;
1298 }
1299
1300out_sleep:
1301 wl1271_ps_elp_sleep(wl);
1302
1303out:
1304 mutex_unlock(&wl->mutex);
1305
1306 return ret;
1307}
1308
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001309struct wl1271_filter_params {
1310 bool enabled;
1311 int mc_list_length;
1312 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1313};
1314
Jiri Pirko22bedad32010-04-01 21:22:57 +00001315static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1316 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001317{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001318 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001319 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001320 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001321
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001322 if (unlikely(wl->state == WL1271_STATE_OFF))
1323 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001324
Juuso Oikarinen74441132009-10-13 12:47:53 +03001325 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 if (!fp) {
1327 wl1271_error("Out of memory setting filters.");
1328 return 0;
1329 }
1330
1331 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001332 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001333 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1334 fp->enabled = false;
1335 } else {
1336 fp->enabled = true;
1337 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001338 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001339 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001340 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001341 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001342 }
1343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001345}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001347#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1348 FIF_ALLMULTI | \
1349 FIF_FCSFAIL | \
1350 FIF_BCN_PRBRESP_PROMISC | \
1351 FIF_CONTROL | \
1352 FIF_OTHER_BSS)
1353
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1355 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001356 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001358 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001360 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001361
1362 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1363
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001364 mutex_lock(&wl->mutex);
1365
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001366 *total &= WL1271_SUPPORTED_FILTERS;
1367 changed &= WL1271_SUPPORTED_FILTERS;
1368
1369 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001370 goto out;
1371
1372 ret = wl1271_ps_elp_wakeup(wl, false);
1373 if (ret < 0)
1374 goto out;
1375
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001377 if (*total & FIF_ALLMULTI)
1378 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1379 else if (fp)
1380 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1381 fp->mc_list,
1382 fp->mc_list_length);
1383 if (ret < 0)
1384 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001386 /* determine, whether supported filter values have changed */
1387 if (changed == 0)
1388 goto out_sleep;
1389
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001390 /* configure filters */
1391 wl->filters = *total;
1392 wl1271_configure_filters(wl, 0);
1393
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394 /* apply configured filters */
1395 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1396 if (ret < 0)
1397 goto out_sleep;
1398
1399out_sleep:
1400 wl1271_ps_elp_sleep(wl);
1401
1402out:
1403 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001404 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405}
1406
1407static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1408 struct ieee80211_vif *vif,
1409 struct ieee80211_sta *sta,
1410 struct ieee80211_key_conf *key_conf)
1411{
1412 struct wl1271 *wl = hw->priv;
1413 const u8 *addr;
1414 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001415 u32 tx_seq_32 = 0;
1416 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001417 u8 key_type;
1418
1419 static const u8 bcast_addr[ETH_ALEN] =
1420 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1421
1422 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1423
1424 addr = sta ? sta->addr : bcast_addr;
1425
1426 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1427 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1428 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1429 key_conf->alg, key_conf->keyidx,
1430 key_conf->keylen, key_conf->flags);
1431 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1432
1433 if (is_zero_ether_addr(addr)) {
1434 /* We dont support TX only encryption */
1435 ret = -EOPNOTSUPP;
1436 goto out;
1437 }
1438
1439 mutex_lock(&wl->mutex);
1440
1441 ret = wl1271_ps_elp_wakeup(wl, false);
1442 if (ret < 0)
1443 goto out_unlock;
1444
1445 switch (key_conf->alg) {
1446 case ALG_WEP:
1447 key_type = KEY_WEP;
1448
1449 key_conf->hw_key_idx = key_conf->keyidx;
1450 break;
1451 case ALG_TKIP:
1452 key_type = KEY_TKIP;
1453
1454 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001455 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1456 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457 break;
1458 case ALG_CCMP:
1459 key_type = KEY_AES;
1460
1461 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001462 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1463 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 break;
1465 default:
1466 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1467
1468 ret = -EOPNOTSUPP;
1469 goto out_sleep;
1470 }
1471
1472 switch (cmd) {
1473 case SET_KEY:
1474 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1475 key_conf->keyidx, key_type,
1476 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001477 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478 if (ret < 0) {
1479 wl1271_error("Could not add or replace key");
1480 goto out_sleep;
1481 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001482
1483 /* the default WEP key needs to be configured at least once */
1484 if (key_type == KEY_WEP) {
1485 ret = wl1271_cmd_set_default_wep_key(wl,
1486 wl->default_key);
1487 if (ret < 0)
1488 goto out_sleep;
1489 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001490 break;
1491
1492 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001493 /* The wl1271 does not allow to remove unicast keys - they
1494 will be cleared automatically on next CMD_JOIN. Ignore the
1495 request silently, as we dont want the mac80211 to emit
1496 an error message. */
1497 if (!is_broadcast_ether_addr(addr))
1498 break;
1499
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1501 key_conf->keyidx, key_type,
1502 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001503 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 if (ret < 0) {
1505 wl1271_error("Could not remove key");
1506 goto out_sleep;
1507 }
1508 break;
1509
1510 default:
1511 wl1271_error("Unsupported key cmd 0x%x", cmd);
1512 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001513 break;
1514 }
1515
1516out_sleep:
1517 wl1271_ps_elp_sleep(wl);
1518
1519out_unlock:
1520 mutex_unlock(&wl->mutex);
1521
1522out:
1523 return ret;
1524}
1525
1526static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001527 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 struct cfg80211_scan_request *req)
1529{
1530 struct wl1271 *wl = hw->priv;
1531 int ret;
1532 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001533 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534
1535 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1536
1537 if (req->n_ssids) {
1538 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001539 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540 }
1541
1542 mutex_lock(&wl->mutex);
1543
1544 ret = wl1271_ps_elp_wakeup(wl, false);
1545 if (ret < 0)
1546 goto out;
1547
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001548 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001549 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1550 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001551 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001552 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1553 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554
1555 wl1271_ps_elp_sleep(wl);
1556
1557out:
1558 mutex_unlock(&wl->mutex);
1559
1560 return ret;
1561}
1562
1563static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1564{
1565 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001566 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567
1568 mutex_lock(&wl->mutex);
1569
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001570 if (unlikely(wl->state == WL1271_STATE_OFF))
1571 goto out;
1572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573 ret = wl1271_ps_elp_wakeup(wl, false);
1574 if (ret < 0)
1575 goto out;
1576
1577 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1578 if (ret < 0)
1579 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1580
1581 wl1271_ps_elp_sleep(wl);
1582
1583out:
1584 mutex_unlock(&wl->mutex);
1585
1586 return ret;
1587}
1588
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001589static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1590{
1591 u8 *ptr = beacon->data +
1592 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1593
1594 /* find the location of the ssid in the beacon */
1595 while (ptr < beacon->data + beacon->len) {
1596 if (ptr[0] == WLAN_EID_SSID) {
1597 wl->ssid_len = ptr[1];
1598 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1599 return;
1600 }
1601 ptr += ptr[1];
1602 }
1603 wl1271_error("ad-hoc beacon template has no SSID!\n");
1604}
1605
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1607 struct ieee80211_vif *vif,
1608 struct ieee80211_bss_conf *bss_conf,
1609 u32 changed)
1610{
1611 enum wl1271_cmd_ps_mode mode;
1612 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001613 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001614 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 int ret;
1616
1617 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1618
1619 mutex_lock(&wl->mutex);
1620
1621 ret = wl1271_ps_elp_wakeup(wl, false);
1622 if (ret < 0)
1623 goto out;
1624
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001625 if ((changed && BSS_CHANGED_BEACON_INT) &&
1626 (wl->bss_type == BSS_TYPE_IBSS)) {
1627 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1628 bss_conf->beacon_int);
1629
1630 wl->beacon_int = bss_conf->beacon_int;
1631 do_join = true;
1632 }
1633
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001634 if ((changed && BSS_CHANGED_BEACON) &&
1635 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001636 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1637
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001638 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1639
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001640 if (beacon) {
1641 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001642
1643 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1645 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001646 beacon->len, 0,
1647 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648
1649 if (ret < 0) {
1650 dev_kfree_skb(beacon);
1651 goto out_sleep;
1652 }
1653
1654 hdr = (struct ieee80211_hdr *) beacon->data;
1655 hdr->frame_control = cpu_to_le16(
1656 IEEE80211_FTYPE_MGMT |
1657 IEEE80211_STYPE_PROBE_RESP);
1658
1659 ret = wl1271_cmd_template_set(wl,
1660 CMD_TEMPL_PROBE_RESPONSE,
1661 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001662 beacon->len, 0,
1663 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001664 dev_kfree_skb(beacon);
1665 if (ret < 0)
1666 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001667
1668 /* Need to update the SSID (for filtering etc) */
1669 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001670 }
1671 }
1672
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001673 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1674 (wl->bss_type == BSS_TYPE_IBSS)) {
1675 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1676 bss_conf->enable_beacon ? "enabled" : "disabled");
1677
1678 if (bss_conf->enable_beacon)
1679 wl->set_bss_type = BSS_TYPE_IBSS;
1680 else
1681 wl->set_bss_type = BSS_TYPE_STA_BSS;
1682 do_join = true;
1683 }
1684
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001685 if (changed & BSS_CHANGED_CQM) {
1686 bool enable = false;
1687 if (bss_conf->cqm_rssi_thold)
1688 enable = true;
1689 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1690 bss_conf->cqm_rssi_thold,
1691 bss_conf->cqm_rssi_hyst);
1692 if (ret < 0)
1693 goto out;
1694 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1695 }
1696
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001697 if ((changed & BSS_CHANGED_BSSID) &&
1698 /*
1699 * Now we know the correct bssid, so we send a new join command
1700 * and enable the BSSID filter
1701 */
1702 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001703 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001704
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001705 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001706 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001707 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001708
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001709 ret = wl1271_build_qos_null_data(wl);
1710 if (ret < 0)
1711 goto out_sleep;
1712
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001713 /* filter out all packets not from this BSSID */
1714 wl1271_configure_filters(wl, 0);
1715
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001716 /* Need to update the BSSID (for filtering etc) */
1717 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001718 }
1719
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 if (changed & BSS_CHANGED_ASSOC) {
1721 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001722 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001724 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001726 wl->ps_poll_failures = 0;
1727
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001728 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001729 * use basic rates from AP, and determine lowest rate
1730 * to use with control frames.
1731 */
1732 rates = bss_conf->basic_rates;
1733 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1734 rates);
1735 wl->basic_rate = wl1271_min_rate_get(wl);
1736 ret = wl1271_acx_rate_policies(wl);
1737 if (ret < 0)
1738 goto out_sleep;
1739
1740 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001741 * with wl1271, we don't need to update the
1742 * beacon_int and dtim_period, because the firmware
1743 * updates it by itself when the first beacon is
1744 * received after a join.
1745 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001746 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1747 if (ret < 0)
1748 goto out_sleep;
1749
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001750 /*
1751 * The SSID is intentionally set to NULL here - the
1752 * firmware will set the probe request with a
1753 * broadcast SSID regardless of what we set in the
1754 * template.
1755 */
1756 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1757 NULL, 0, wl->band);
1758
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001759 /* enable the connection monitoring feature */
1760 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001761 if (ret < 0)
1762 goto out_sleep;
1763
1764 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001765 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1766 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001768 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769 if (ret < 0)
1770 goto out_sleep;
1771 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001772 } else {
1773 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001774 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001775 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001776
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001777 /* revert back to minimum rates for the current band */
1778 wl1271_set_band_rate(wl);
1779 wl->basic_rate = wl1271_min_rate_get(wl);
1780 ret = wl1271_acx_rate_policies(wl);
1781 if (ret < 0)
1782 goto out_sleep;
1783
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001784 /* disable connection monitor features */
1785 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001786
1787 /* Disable the keep-alive feature */
1788 ret = wl1271_acx_keep_alive_mode(wl, false);
1789
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001790 if (ret < 0)
1791 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001793
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001794 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001795
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001796 if (changed & BSS_CHANGED_ERP_SLOT) {
1797 if (bss_conf->use_short_slot)
1798 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1799 else
1800 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1801 if (ret < 0) {
1802 wl1271_warning("Set slot time failed %d", ret);
1803 goto out_sleep;
1804 }
1805 }
1806
1807 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1808 if (bss_conf->use_short_preamble)
1809 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1810 else
1811 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1812 }
1813
1814 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1815 if (bss_conf->use_cts_prot)
1816 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1817 else
1818 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1819 if (ret < 0) {
1820 wl1271_warning("Set ctsprotect failed %d", ret);
1821 goto out_sleep;
1822 }
1823 }
1824
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001825 if (changed & BSS_CHANGED_ARP_FILTER) {
1826 __be32 addr = bss_conf->arp_addr_list[0];
1827 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1828
1829 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1830 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1831 else
1832 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1833
1834 if (ret < 0)
1835 goto out_sleep;
1836 }
1837
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001838 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001839 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001840 if (ret < 0) {
1841 wl1271_warning("cmd join failed %d", ret);
1842 goto out_sleep;
1843 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001844 }
1845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846out_sleep:
1847 wl1271_ps_elp_sleep(wl);
1848
1849out:
1850 mutex_unlock(&wl->mutex);
1851}
1852
Kalle Valoc6999d82010-02-18 13:25:41 +02001853static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1854 const struct ieee80211_tx_queue_params *params)
1855{
1856 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001857 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001858 int ret;
1859
1860 mutex_lock(&wl->mutex);
1861
1862 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1863
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001864 ret = wl1271_ps_elp_wakeup(wl, false);
1865 if (ret < 0)
1866 goto out;
1867
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001868 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001869 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1870 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001871 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001872 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001873 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001874
Kalle Valo4695dc92010-03-18 12:26:38 +02001875 if (params->uapsd)
1876 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1877 else
1878 ps_scheme = CONF_PS_SCHEME_LEGACY;
1879
Kalle Valoc6999d82010-02-18 13:25:41 +02001880 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1881 CONF_CHANNEL_TYPE_EDCF,
1882 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001883 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001884 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001885 goto out_sleep;
1886
1887out_sleep:
1888 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001889
1890out:
1891 mutex_unlock(&wl->mutex);
1892
1893 return ret;
1894}
1895
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001896static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1897{
1898
1899 struct wl1271 *wl = hw->priv;
1900 u64 mactime = ULLONG_MAX;
1901 int ret;
1902
1903 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1904
1905 mutex_lock(&wl->mutex);
1906
1907 ret = wl1271_ps_elp_wakeup(wl, false);
1908 if (ret < 0)
1909 goto out;
1910
1911 ret = wl1271_acx_tsf_info(wl, &mactime);
1912 if (ret < 0)
1913 goto out_sleep;
1914
1915out_sleep:
1916 wl1271_ps_elp_sleep(wl);
1917
1918out:
1919 mutex_unlock(&wl->mutex);
1920 return mactime;
1921}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001922
1923/* can't be const, mac80211 writes to this */
1924static struct ieee80211_rate wl1271_rates[] = {
1925 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001926 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1927 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001929 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1930 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1932 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001933 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1934 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1936 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001937 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1938 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1940 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001941 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1942 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001944 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1945 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001947 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1948 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001950 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1951 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001953 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1954 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001956 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1957 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001959 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1960 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001962 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1963 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964};
1965
1966/* can't be const, mac80211 writes to this */
1967static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001968 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1969 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1970 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1971 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1972 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1973 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1974 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1975 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1976 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1977 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1978 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1979 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1980 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981};
1982
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001983/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02001984static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001985 /* MCS rates are used only with 11n */
1986 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1987 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1988 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1989 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1990 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1993 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1994
1995 11, /* CONF_HW_RXTX_RATE_54 */
1996 10, /* CONF_HW_RXTX_RATE_48 */
1997 9, /* CONF_HW_RXTX_RATE_36 */
1998 8, /* CONF_HW_RXTX_RATE_24 */
1999
2000 /* TI-specific rate */
2001 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2002
2003 7, /* CONF_HW_RXTX_RATE_18 */
2004 6, /* CONF_HW_RXTX_RATE_12 */
2005 3, /* CONF_HW_RXTX_RATE_11 */
2006 5, /* CONF_HW_RXTX_RATE_9 */
2007 4, /* CONF_HW_RXTX_RATE_6 */
2008 2, /* CONF_HW_RXTX_RATE_5_5 */
2009 1, /* CONF_HW_RXTX_RATE_2 */
2010 0 /* CONF_HW_RXTX_RATE_1 */
2011};
2012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002013/* can't be const, mac80211 writes to this */
2014static struct ieee80211_supported_band wl1271_band_2ghz = {
2015 .channels = wl1271_channels,
2016 .n_channels = ARRAY_SIZE(wl1271_channels),
2017 .bitrates = wl1271_rates,
2018 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2019};
2020
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002021/* 5 GHz data rates for WL1273 */
2022static struct ieee80211_rate wl1271_rates_5ghz[] = {
2023 { .bitrate = 60,
2024 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2025 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2026 { .bitrate = 90,
2027 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2028 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2029 { .bitrate = 120,
2030 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2031 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2032 { .bitrate = 180,
2033 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2035 { .bitrate = 240,
2036 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2037 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2038 { .bitrate = 360,
2039 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2040 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2041 { .bitrate = 480,
2042 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2043 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2044 { .bitrate = 540,
2045 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2046 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2047};
2048
2049/* 5 GHz band channels for WL1273 */
2050static struct ieee80211_channel wl1271_channels_5ghz[] = {
2051 { .hw_value = 183, .center_freq = 4915},
2052 { .hw_value = 184, .center_freq = 4920},
2053 { .hw_value = 185, .center_freq = 4925},
2054 { .hw_value = 187, .center_freq = 4935},
2055 { .hw_value = 188, .center_freq = 4940},
2056 { .hw_value = 189, .center_freq = 4945},
2057 { .hw_value = 192, .center_freq = 4960},
2058 { .hw_value = 196, .center_freq = 4980},
2059 { .hw_value = 7, .center_freq = 5035},
2060 { .hw_value = 8, .center_freq = 5040},
2061 { .hw_value = 9, .center_freq = 5045},
2062 { .hw_value = 11, .center_freq = 5055},
2063 { .hw_value = 12, .center_freq = 5060},
2064 { .hw_value = 16, .center_freq = 5080},
2065 { .hw_value = 34, .center_freq = 5170},
2066 { .hw_value = 36, .center_freq = 5180},
2067 { .hw_value = 38, .center_freq = 5190},
2068 { .hw_value = 40, .center_freq = 5200},
2069 { .hw_value = 42, .center_freq = 5210},
2070 { .hw_value = 44, .center_freq = 5220},
2071 { .hw_value = 46, .center_freq = 5230},
2072 { .hw_value = 48, .center_freq = 5240},
2073 { .hw_value = 52, .center_freq = 5260},
2074 { .hw_value = 56, .center_freq = 5280},
2075 { .hw_value = 60, .center_freq = 5300},
2076 { .hw_value = 64, .center_freq = 5320},
2077 { .hw_value = 100, .center_freq = 5500},
2078 { .hw_value = 104, .center_freq = 5520},
2079 { .hw_value = 108, .center_freq = 5540},
2080 { .hw_value = 112, .center_freq = 5560},
2081 { .hw_value = 116, .center_freq = 5580},
2082 { .hw_value = 120, .center_freq = 5600},
2083 { .hw_value = 124, .center_freq = 5620},
2084 { .hw_value = 128, .center_freq = 5640},
2085 { .hw_value = 132, .center_freq = 5660},
2086 { .hw_value = 136, .center_freq = 5680},
2087 { .hw_value = 140, .center_freq = 5700},
2088 { .hw_value = 149, .center_freq = 5745},
2089 { .hw_value = 153, .center_freq = 5765},
2090 { .hw_value = 157, .center_freq = 5785},
2091 { .hw_value = 161, .center_freq = 5805},
2092 { .hw_value = 165, .center_freq = 5825},
2093};
2094
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002095/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002096static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002097 /* MCS rates are used only with 11n */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2099 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2102 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2103 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2104 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2106
2107 7, /* CONF_HW_RXTX_RATE_54 */
2108 6, /* CONF_HW_RXTX_RATE_48 */
2109 5, /* CONF_HW_RXTX_RATE_36 */
2110 4, /* CONF_HW_RXTX_RATE_24 */
2111
2112 /* TI-specific rate */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2114
2115 3, /* CONF_HW_RXTX_RATE_18 */
2116 2, /* CONF_HW_RXTX_RATE_12 */
2117 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2118 1, /* CONF_HW_RXTX_RATE_9 */
2119 0, /* CONF_HW_RXTX_RATE_6 */
2120 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2122 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2123};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002124
2125static struct ieee80211_supported_band wl1271_band_5ghz = {
2126 .channels = wl1271_channels_5ghz,
2127 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2128 .bitrates = wl1271_rates_5ghz,
2129 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2130};
2131
Tobias Klausera0ea9492010-05-20 10:38:11 +02002132static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002133 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2134 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2135};
2136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137static const struct ieee80211_ops wl1271_ops = {
2138 .start = wl1271_op_start,
2139 .stop = wl1271_op_stop,
2140 .add_interface = wl1271_op_add_interface,
2141 .remove_interface = wl1271_op_remove_interface,
2142 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002143 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144 .configure_filter = wl1271_op_configure_filter,
2145 .tx = wl1271_op_tx,
2146 .set_key = wl1271_op_set_key,
2147 .hw_scan = wl1271_op_hw_scan,
2148 .bss_info_changed = wl1271_op_bss_info_changed,
2149 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002150 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002151 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002152 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153};
2154
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002155
2156u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2157{
2158 u8 idx;
2159
2160 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2161
2162 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2163 wl1271_error("Illegal RX rate from HW: %d", rate);
2164 return 0;
2165 }
2166
2167 idx = wl1271_band_rate_to_idx[wl->band][rate];
2168 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2169 wl1271_error("Unsupported RX rate from HW: %d", rate);
2170 return 0;
2171 }
2172
2173 return idx;
2174}
2175
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002176static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2177 struct device_attribute *attr,
2178 char *buf)
2179{
2180 struct wl1271 *wl = dev_get_drvdata(dev);
2181 ssize_t len;
2182
2183 /* FIXME: what's the maximum length of buf? page size?*/
2184 len = 500;
2185
2186 mutex_lock(&wl->mutex);
2187 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2188 wl->sg_enabled);
2189 mutex_unlock(&wl->mutex);
2190
2191 return len;
2192
2193}
2194
2195static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2196 struct device_attribute *attr,
2197 const char *buf, size_t count)
2198{
2199 struct wl1271 *wl = dev_get_drvdata(dev);
2200 unsigned long res;
2201 int ret;
2202
2203 ret = strict_strtoul(buf, 10, &res);
2204
2205 if (ret < 0) {
2206 wl1271_warning("incorrect value written to bt_coex_mode");
2207 return count;
2208 }
2209
2210 mutex_lock(&wl->mutex);
2211
2212 res = !!res;
2213
2214 if (res == wl->sg_enabled)
2215 goto out;
2216
2217 wl->sg_enabled = res;
2218
2219 if (wl->state == WL1271_STATE_OFF)
2220 goto out;
2221
2222 ret = wl1271_ps_elp_wakeup(wl, false);
2223 if (ret < 0)
2224 goto out;
2225
2226 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2227 wl1271_ps_elp_sleep(wl);
2228
2229 out:
2230 mutex_unlock(&wl->mutex);
2231 return count;
2232}
2233
2234static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2235 wl1271_sysfs_show_bt_coex_state,
2236 wl1271_sysfs_store_bt_coex_state);
2237
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002238static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2239 struct device_attribute *attr,
2240 char *buf)
2241{
2242 struct wl1271 *wl = dev_get_drvdata(dev);
2243 ssize_t len;
2244
2245 /* FIXME: what's the maximum length of buf? page size?*/
2246 len = 500;
2247
2248 mutex_lock(&wl->mutex);
2249 if (wl->hw_pg_ver >= 0)
2250 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2251 else
2252 len = snprintf(buf, len, "n/a\n");
2253 mutex_unlock(&wl->mutex);
2254
2255 return len;
2256}
2257
2258static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2259 wl1271_sysfs_show_hw_pg_ver, NULL);
2260
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002261int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262{
2263 int ret;
2264
2265 if (wl->mac80211_registered)
2266 return 0;
2267
2268 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2269
2270 ret = ieee80211_register_hw(wl->hw);
2271 if (ret < 0) {
2272 wl1271_error("unable to register mac80211 hw: %d", ret);
2273 return ret;
2274 }
2275
2276 wl->mac80211_registered = true;
2277
2278 wl1271_notice("loaded");
2279
2280 return 0;
2281}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002282EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002284void wl1271_unregister_hw(struct wl1271 *wl)
2285{
2286 ieee80211_unregister_hw(wl->hw);
2287 wl->mac80211_registered = false;
2288
2289}
2290EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2291
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002292int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002294 /* The tx descriptor buffer and the TKIP space. */
2295 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2296 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297
2298 /* unit us */
2299 /* FIXME: find a proper value */
2300 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002301 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302
2303 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002304 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002305 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002306 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002307 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002308 IEEE80211_HW_CONNECTION_MONITOR |
2309 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002310
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002311 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2312 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313 wl->hw->wiphy->max_scan_ssids = 1;
2314 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2315
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002316 if (wl1271_11a_enabled())
2317 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2318
Kalle Valo12bd8942010-03-18 12:26:33 +02002319 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002320 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002321
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002322 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323
2324 return 0;
2325}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002326EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002329
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002330struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002333 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002335 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336
2337 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2338 if (!hw) {
2339 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002340 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002341 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 }
2343
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002344 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2345 if (!plat_dev) {
2346 wl1271_error("could not allocate platform_device");
2347 ret = -ENOMEM;
2348 goto err_plat_alloc;
2349 }
2350
2351 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2352
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002353 wl = hw->priv;
2354 memset(wl, 0, sizeof(*wl));
2355
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002356 INIT_LIST_HEAD(&wl->list);
2357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002359 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360
2361 skb_queue_head_init(&wl->tx_queue);
2362
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002363 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002364 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002366 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 wl->rx_counter = 0;
2369 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2370 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002371 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002372 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002373 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002374 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002375 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2376 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002377 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002378 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002379 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002380 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002381 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002383 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002384 wl->tx_frames[i] = NULL;
2385
2386 spin_lock_init(&wl->wl_lock);
2387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 wl->state = WL1271_STATE_OFF;
2389 mutex_init(&wl->mutex);
2390
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002391 /* Apply default driver configuration. */
2392 wl1271_conf_init(wl);
2393
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002394 wl1271_debugfs_init(wl);
2395
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002396 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002397 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002398 if (ret) {
2399 wl1271_error("couldn't register platform device");
2400 goto err_hw;
2401 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002402 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002403
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002404 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002405 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002406 if (ret < 0) {
2407 wl1271_error("failed to create sysfs file bt_coex_state");
2408 goto err_platform;
2409 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002410
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002411 /* Create sysfs file to get HW PG version */
2412 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2413 if (ret < 0) {
2414 wl1271_error("failed to create sysfs file hw_pg_ver");
2415 goto err_bt_coex_state;
2416 }
2417
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002418 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002419
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002420err_bt_coex_state:
2421 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2422
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002423err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002424 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002425
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002426err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002427 wl1271_debugfs_exit(wl);
2428 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002429
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002430err_plat_alloc:
2431 ieee80211_free_hw(hw);
2432
2433err_hw_alloc:
2434
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002435 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002436}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002437EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002438
2439int wl1271_free_hw(struct wl1271 *wl)
2440{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002441 platform_device_unregister(wl->plat_dev);
2442 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002443
2444 wl1271_debugfs_exit(wl);
2445
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002446 vfree(wl->fw);
2447 wl->fw = NULL;
2448 kfree(wl->nvs);
2449 wl->nvs = NULL;
2450
2451 kfree(wl->fw_status);
2452 kfree(wl->tx_res_if);
2453
2454 ieee80211_free_hw(wl->hw);
2455
2456 return 0;
2457}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002458EXPORT_SYMBOL_GPL(wl1271_free_hw);
2459
2460MODULE_LICENSE("GPL");
2461MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2462MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");