blob: 3a648963fbedafc24c66e4207d6a7fa22e0f4f99 [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
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001315static int wl1271_op_configure_arp_filter(struct ieee80211_hw *hw,
1316 struct ieee80211_vif *vif,
1317 struct in_ifaddr *ifa_list)
1318{
1319 struct wl1271 *wl = hw->priv;
1320 int ret = 0;
1321
1322 WARN_ON(vif != wl->vif);
1323
1324 /* disable filtering if there are multiple addresses */
1325 if (ifa_list && ifa_list->ifa_next)
1326 ifa_list = NULL;
1327
1328 mutex_lock(&wl->mutex);
1329
1330 if (wl->state == WL1271_STATE_OFF)
1331 goto out;
1332
1333 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1334
1335 ret = wl1271_ps_elp_wakeup(wl, false);
1336 if (ret < 0)
1337 goto out;
1338
1339 if (ifa_list) {
1340 ret = wl1271_cmd_build_arp_reply(wl, &ifa_list->ifa_address);
1341 if (ret < 0)
1342 goto out_sleep;
1343 ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_FILTER_AND_REPLY,
1344 (u8 *)&ifa_list->ifa_address);
1345 if (ret < 0)
1346 goto out_sleep;
1347 } else {
1348 ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_DISABLE, NULL);
1349 if (ret < 0)
1350 goto out_sleep;
1351 }
1352
1353out_sleep:
1354 wl1271_ps_elp_sleep(wl);
1355
1356out:
1357 mutex_unlock(&wl->mutex);
1358
1359 return ret;
1360}
1361
Jiri Pirko22bedad32010-04-01 21:22:57 +00001362static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1363 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001365 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001366 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001367 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001368
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001369 if (unlikely(wl->state == WL1271_STATE_OFF))
1370 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001371
Juuso Oikarinen74441132009-10-13 12:47:53 +03001372 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001373 if (!fp) {
1374 wl1271_error("Out of memory setting filters.");
1375 return 0;
1376 }
1377
1378 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001379 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001380 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1381 fp->enabled = false;
1382 } else {
1383 fp->enabled = true;
1384 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001385 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001386 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001387 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001388 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001389 }
1390
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001391 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001392}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1395 FIF_ALLMULTI | \
1396 FIF_FCSFAIL | \
1397 FIF_BCN_PRBRESP_PROMISC | \
1398 FIF_CONTROL | \
1399 FIF_OTHER_BSS)
1400
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001401static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1402 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001403 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001405 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001407 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408
1409 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1410
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001411 mutex_lock(&wl->mutex);
1412
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001413 *total &= WL1271_SUPPORTED_FILTERS;
1414 changed &= WL1271_SUPPORTED_FILTERS;
1415
1416 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001417 goto out;
1418
1419 ret = wl1271_ps_elp_wakeup(wl, false);
1420 if (ret < 0)
1421 goto out;
1422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001424 if (*total & FIF_ALLMULTI)
1425 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1426 else if (fp)
1427 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1428 fp->mc_list,
1429 fp->mc_list_length);
1430 if (ret < 0)
1431 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001433 /* determine, whether supported filter values have changed */
1434 if (changed == 0)
1435 goto out_sleep;
1436
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001437 /* configure filters */
1438 wl->filters = *total;
1439 wl1271_configure_filters(wl, 0);
1440
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001441 /* apply configured filters */
1442 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1443 if (ret < 0)
1444 goto out_sleep;
1445
1446out_sleep:
1447 wl1271_ps_elp_sleep(wl);
1448
1449out:
1450 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001451 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001452}
1453
1454static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1455 struct ieee80211_vif *vif,
1456 struct ieee80211_sta *sta,
1457 struct ieee80211_key_conf *key_conf)
1458{
1459 struct wl1271 *wl = hw->priv;
1460 const u8 *addr;
1461 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001462 u32 tx_seq_32 = 0;
1463 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464 u8 key_type;
1465
1466 static const u8 bcast_addr[ETH_ALEN] =
1467 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1468
1469 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1470
1471 addr = sta ? sta->addr : bcast_addr;
1472
1473 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1474 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1475 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1476 key_conf->alg, key_conf->keyidx,
1477 key_conf->keylen, key_conf->flags);
1478 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1479
1480 if (is_zero_ether_addr(addr)) {
1481 /* We dont support TX only encryption */
1482 ret = -EOPNOTSUPP;
1483 goto out;
1484 }
1485
1486 mutex_lock(&wl->mutex);
1487
1488 ret = wl1271_ps_elp_wakeup(wl, false);
1489 if (ret < 0)
1490 goto out_unlock;
1491
1492 switch (key_conf->alg) {
1493 case ALG_WEP:
1494 key_type = KEY_WEP;
1495
1496 key_conf->hw_key_idx = key_conf->keyidx;
1497 break;
1498 case ALG_TKIP:
1499 key_type = KEY_TKIP;
1500
1501 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001502 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1503 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504 break;
1505 case ALG_CCMP:
1506 key_type = KEY_AES;
1507
1508 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001509 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1510 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511 break;
1512 default:
1513 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1514
1515 ret = -EOPNOTSUPP;
1516 goto out_sleep;
1517 }
1518
1519 switch (cmd) {
1520 case SET_KEY:
1521 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1522 key_conf->keyidx, key_type,
1523 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001524 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001525 if (ret < 0) {
1526 wl1271_error("Could not add or replace key");
1527 goto out_sleep;
1528 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001529
1530 /* the default WEP key needs to be configured at least once */
1531 if (key_type == KEY_WEP) {
1532 ret = wl1271_cmd_set_default_wep_key(wl,
1533 wl->default_key);
1534 if (ret < 0)
1535 goto out_sleep;
1536 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537 break;
1538
1539 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001540 /* The wl1271 does not allow to remove unicast keys - they
1541 will be cleared automatically on next CMD_JOIN. Ignore the
1542 request silently, as we dont want the mac80211 to emit
1543 an error message. */
1544 if (!is_broadcast_ether_addr(addr))
1545 break;
1546
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1548 key_conf->keyidx, key_type,
1549 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001550 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551 if (ret < 0) {
1552 wl1271_error("Could not remove key");
1553 goto out_sleep;
1554 }
1555 break;
1556
1557 default:
1558 wl1271_error("Unsupported key cmd 0x%x", cmd);
1559 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560 break;
1561 }
1562
1563out_sleep:
1564 wl1271_ps_elp_sleep(wl);
1565
1566out_unlock:
1567 mutex_unlock(&wl->mutex);
1568
1569out:
1570 return ret;
1571}
1572
1573static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001574 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 struct cfg80211_scan_request *req)
1576{
1577 struct wl1271 *wl = hw->priv;
1578 int ret;
1579 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001580 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001581
1582 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1583
1584 if (req->n_ssids) {
1585 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001586 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 }
1588
1589 mutex_lock(&wl->mutex);
1590
1591 ret = wl1271_ps_elp_wakeup(wl, false);
1592 if (ret < 0)
1593 goto out;
1594
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001595 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001596 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1597 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001598 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001599 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1600 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601
1602 wl1271_ps_elp_sleep(wl);
1603
1604out:
1605 mutex_unlock(&wl->mutex);
1606
1607 return ret;
1608}
1609
1610static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1611{
1612 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001613 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614
1615 mutex_lock(&wl->mutex);
1616
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001617 if (unlikely(wl->state == WL1271_STATE_OFF))
1618 goto out;
1619
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 ret = wl1271_ps_elp_wakeup(wl, false);
1621 if (ret < 0)
1622 goto out;
1623
1624 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1625 if (ret < 0)
1626 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1627
1628 wl1271_ps_elp_sleep(wl);
1629
1630out:
1631 mutex_unlock(&wl->mutex);
1632
1633 return ret;
1634}
1635
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001636static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1637{
1638 u8 *ptr = beacon->data +
1639 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1640
1641 /* find the location of the ssid in the beacon */
1642 while (ptr < beacon->data + beacon->len) {
1643 if (ptr[0] == WLAN_EID_SSID) {
1644 wl->ssid_len = ptr[1];
1645 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1646 return;
1647 }
1648 ptr += ptr[1];
1649 }
1650 wl1271_error("ad-hoc beacon template has no SSID!\n");
1651}
1652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1654 struct ieee80211_vif *vif,
1655 struct ieee80211_bss_conf *bss_conf,
1656 u32 changed)
1657{
1658 enum wl1271_cmd_ps_mode mode;
1659 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001660 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001661 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662 int ret;
1663
1664 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1665
1666 mutex_lock(&wl->mutex);
1667
1668 ret = wl1271_ps_elp_wakeup(wl, false);
1669 if (ret < 0)
1670 goto out;
1671
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001672 if ((changed && BSS_CHANGED_BEACON_INT) &&
1673 (wl->bss_type == BSS_TYPE_IBSS)) {
1674 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1675 bss_conf->beacon_int);
1676
1677 wl->beacon_int = bss_conf->beacon_int;
1678 do_join = true;
1679 }
1680
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001681 if ((changed && BSS_CHANGED_BEACON) &&
1682 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1684
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001685 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1686
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001687 if (beacon) {
1688 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001689
1690 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001691 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1692 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001693 beacon->len, 0,
1694 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001695
1696 if (ret < 0) {
1697 dev_kfree_skb(beacon);
1698 goto out_sleep;
1699 }
1700
1701 hdr = (struct ieee80211_hdr *) beacon->data;
1702 hdr->frame_control = cpu_to_le16(
1703 IEEE80211_FTYPE_MGMT |
1704 IEEE80211_STYPE_PROBE_RESP);
1705
1706 ret = wl1271_cmd_template_set(wl,
1707 CMD_TEMPL_PROBE_RESPONSE,
1708 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001709 beacon->len, 0,
1710 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001711 dev_kfree_skb(beacon);
1712 if (ret < 0)
1713 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001714
1715 /* Need to update the SSID (for filtering etc) */
1716 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001717 }
1718 }
1719
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001720 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1721 (wl->bss_type == BSS_TYPE_IBSS)) {
1722 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1723 bss_conf->enable_beacon ? "enabled" : "disabled");
1724
1725 if (bss_conf->enable_beacon)
1726 wl->set_bss_type = BSS_TYPE_IBSS;
1727 else
1728 wl->set_bss_type = BSS_TYPE_STA_BSS;
1729 do_join = true;
1730 }
1731
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001732 if (changed & BSS_CHANGED_CQM) {
1733 bool enable = false;
1734 if (bss_conf->cqm_rssi_thold)
1735 enable = true;
1736 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1737 bss_conf->cqm_rssi_thold,
1738 bss_conf->cqm_rssi_hyst);
1739 if (ret < 0)
1740 goto out;
1741 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1742 }
1743
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001744 if ((changed & BSS_CHANGED_BSSID) &&
1745 /*
1746 * Now we know the correct bssid, so we send a new join command
1747 * and enable the BSSID filter
1748 */
1749 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001750 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001751
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001752 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001753 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001754 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001755
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001756 ret = wl1271_build_qos_null_data(wl);
1757 if (ret < 0)
1758 goto out_sleep;
1759
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001760 /* filter out all packets not from this BSSID */
1761 wl1271_configure_filters(wl, 0);
1762
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001763 /* Need to update the BSSID (for filtering etc) */
1764 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001765 }
1766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 if (changed & BSS_CHANGED_ASSOC) {
1768 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001769 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001771 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001773 wl->ps_poll_failures = 0;
1774
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001775 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001776 * use basic rates from AP, and determine lowest rate
1777 * to use with control frames.
1778 */
1779 rates = bss_conf->basic_rates;
1780 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1781 rates);
1782 wl->basic_rate = wl1271_min_rate_get(wl);
1783 ret = wl1271_acx_rate_policies(wl);
1784 if (ret < 0)
1785 goto out_sleep;
1786
1787 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001788 * with wl1271, we don't need to update the
1789 * beacon_int and dtim_period, because the firmware
1790 * updates it by itself when the first beacon is
1791 * received after a join.
1792 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1794 if (ret < 0)
1795 goto out_sleep;
1796
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001797 /*
1798 * The SSID is intentionally set to NULL here - the
1799 * firmware will set the probe request with a
1800 * broadcast SSID regardless of what we set in the
1801 * template.
1802 */
1803 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1804 NULL, 0, wl->band);
1805
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001806 /* enable the connection monitoring feature */
1807 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 if (ret < 0)
1809 goto out_sleep;
1810
1811 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001812 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1813 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001815 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 if (ret < 0)
1817 goto out_sleep;
1818 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001819 } else {
1820 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001821 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001822 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001823
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001824 /* revert back to minimum rates for the current band */
1825 wl1271_set_band_rate(wl);
1826 wl->basic_rate = wl1271_min_rate_get(wl);
1827 ret = wl1271_acx_rate_policies(wl);
1828 if (ret < 0)
1829 goto out_sleep;
1830
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001831 /* disable connection monitor features */
1832 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001833
1834 /* Disable the keep-alive feature */
1835 ret = wl1271_acx_keep_alive_mode(wl, false);
1836
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001837 if (ret < 0)
1838 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 if (changed & BSS_CHANGED_ERP_SLOT) {
1844 if (bss_conf->use_short_slot)
1845 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1846 else
1847 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1848 if (ret < 0) {
1849 wl1271_warning("Set slot time failed %d", ret);
1850 goto out_sleep;
1851 }
1852 }
1853
1854 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1855 if (bss_conf->use_short_preamble)
1856 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1857 else
1858 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1859 }
1860
1861 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1862 if (bss_conf->use_cts_prot)
1863 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1864 else
1865 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1866 if (ret < 0) {
1867 wl1271_warning("Set ctsprotect failed %d", ret);
1868 goto out_sleep;
1869 }
1870 }
1871
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001872 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001873 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001874 if (ret < 0) {
1875 wl1271_warning("cmd join failed %d", ret);
1876 goto out_sleep;
1877 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001878 }
1879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880out_sleep:
1881 wl1271_ps_elp_sleep(wl);
1882
1883out:
1884 mutex_unlock(&wl->mutex);
1885}
1886
Kalle Valoc6999d82010-02-18 13:25:41 +02001887static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1888 const struct ieee80211_tx_queue_params *params)
1889{
1890 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001891 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001892 int ret;
1893
1894 mutex_lock(&wl->mutex);
1895
1896 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1897
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001898 ret = wl1271_ps_elp_wakeup(wl, false);
1899 if (ret < 0)
1900 goto out;
1901
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001902 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001903 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1904 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001905 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001906 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001907 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001908
Kalle Valo4695dc92010-03-18 12:26:38 +02001909 if (params->uapsd)
1910 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1911 else
1912 ps_scheme = CONF_PS_SCHEME_LEGACY;
1913
Kalle Valoc6999d82010-02-18 13:25:41 +02001914 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1915 CONF_CHANNEL_TYPE_EDCF,
1916 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001917 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001918 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001919 goto out_sleep;
1920
1921out_sleep:
1922 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001923
1924out:
1925 mutex_unlock(&wl->mutex);
1926
1927 return ret;
1928}
1929
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001930static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1931{
1932
1933 struct wl1271 *wl = hw->priv;
1934 u64 mactime = ULLONG_MAX;
1935 int ret;
1936
1937 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1938
1939 mutex_lock(&wl->mutex);
1940
1941 ret = wl1271_ps_elp_wakeup(wl, false);
1942 if (ret < 0)
1943 goto out;
1944
1945 ret = wl1271_acx_tsf_info(wl, &mactime);
1946 if (ret < 0)
1947 goto out_sleep;
1948
1949out_sleep:
1950 wl1271_ps_elp_sleep(wl);
1951
1952out:
1953 mutex_unlock(&wl->mutex);
1954 return mactime;
1955}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956
1957/* can't be const, mac80211 writes to this */
1958static struct ieee80211_rate wl1271_rates[] = {
1959 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001963 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1964 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1966 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001967 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1968 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1970 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001971 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1972 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1974 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001975 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1976 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001978 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1979 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001981 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1982 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001984 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1985 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001987 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1988 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001990 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1991 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001993 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1994 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001996 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1997 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998};
1999
2000/* can't be const, mac80211 writes to this */
2001static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002002 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
2003 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2004 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2005 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2006 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
2007 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2008 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2009 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2010 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
2011 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
2012 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2013 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2014 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015};
2016
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002017/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002018static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002019 /* MCS rates are used only with 11n */
2020 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2021 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2022 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2023 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2024 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2025 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2026 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2027 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2028
2029 11, /* CONF_HW_RXTX_RATE_54 */
2030 10, /* CONF_HW_RXTX_RATE_48 */
2031 9, /* CONF_HW_RXTX_RATE_36 */
2032 8, /* CONF_HW_RXTX_RATE_24 */
2033
2034 /* TI-specific rate */
2035 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2036
2037 7, /* CONF_HW_RXTX_RATE_18 */
2038 6, /* CONF_HW_RXTX_RATE_12 */
2039 3, /* CONF_HW_RXTX_RATE_11 */
2040 5, /* CONF_HW_RXTX_RATE_9 */
2041 4, /* CONF_HW_RXTX_RATE_6 */
2042 2, /* CONF_HW_RXTX_RATE_5_5 */
2043 1, /* CONF_HW_RXTX_RATE_2 */
2044 0 /* CONF_HW_RXTX_RATE_1 */
2045};
2046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047/* can't be const, mac80211 writes to this */
2048static struct ieee80211_supported_band wl1271_band_2ghz = {
2049 .channels = wl1271_channels,
2050 .n_channels = ARRAY_SIZE(wl1271_channels),
2051 .bitrates = wl1271_rates,
2052 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2053};
2054
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002055/* 5 GHz data rates for WL1273 */
2056static struct ieee80211_rate wl1271_rates_5ghz[] = {
2057 { .bitrate = 60,
2058 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2059 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2060 { .bitrate = 90,
2061 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2062 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2063 { .bitrate = 120,
2064 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2065 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2066 { .bitrate = 180,
2067 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2068 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2069 { .bitrate = 240,
2070 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2071 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2072 { .bitrate = 360,
2073 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2074 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2075 { .bitrate = 480,
2076 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2077 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2078 { .bitrate = 540,
2079 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2080 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2081};
2082
2083/* 5 GHz band channels for WL1273 */
2084static struct ieee80211_channel wl1271_channels_5ghz[] = {
2085 { .hw_value = 183, .center_freq = 4915},
2086 { .hw_value = 184, .center_freq = 4920},
2087 { .hw_value = 185, .center_freq = 4925},
2088 { .hw_value = 187, .center_freq = 4935},
2089 { .hw_value = 188, .center_freq = 4940},
2090 { .hw_value = 189, .center_freq = 4945},
2091 { .hw_value = 192, .center_freq = 4960},
2092 { .hw_value = 196, .center_freq = 4980},
2093 { .hw_value = 7, .center_freq = 5035},
2094 { .hw_value = 8, .center_freq = 5040},
2095 { .hw_value = 9, .center_freq = 5045},
2096 { .hw_value = 11, .center_freq = 5055},
2097 { .hw_value = 12, .center_freq = 5060},
2098 { .hw_value = 16, .center_freq = 5080},
2099 { .hw_value = 34, .center_freq = 5170},
2100 { .hw_value = 36, .center_freq = 5180},
2101 { .hw_value = 38, .center_freq = 5190},
2102 { .hw_value = 40, .center_freq = 5200},
2103 { .hw_value = 42, .center_freq = 5210},
2104 { .hw_value = 44, .center_freq = 5220},
2105 { .hw_value = 46, .center_freq = 5230},
2106 { .hw_value = 48, .center_freq = 5240},
2107 { .hw_value = 52, .center_freq = 5260},
2108 { .hw_value = 56, .center_freq = 5280},
2109 { .hw_value = 60, .center_freq = 5300},
2110 { .hw_value = 64, .center_freq = 5320},
2111 { .hw_value = 100, .center_freq = 5500},
2112 { .hw_value = 104, .center_freq = 5520},
2113 { .hw_value = 108, .center_freq = 5540},
2114 { .hw_value = 112, .center_freq = 5560},
2115 { .hw_value = 116, .center_freq = 5580},
2116 { .hw_value = 120, .center_freq = 5600},
2117 { .hw_value = 124, .center_freq = 5620},
2118 { .hw_value = 128, .center_freq = 5640},
2119 { .hw_value = 132, .center_freq = 5660},
2120 { .hw_value = 136, .center_freq = 5680},
2121 { .hw_value = 140, .center_freq = 5700},
2122 { .hw_value = 149, .center_freq = 5745},
2123 { .hw_value = 153, .center_freq = 5765},
2124 { .hw_value = 157, .center_freq = 5785},
2125 { .hw_value = 161, .center_freq = 5805},
2126 { .hw_value = 165, .center_freq = 5825},
2127};
2128
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002129/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002130static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002131 /* MCS rates are used only with 11n */
2132 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2133 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2134 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2135 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2136 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2137 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2138 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2139 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2140
2141 7, /* CONF_HW_RXTX_RATE_54 */
2142 6, /* CONF_HW_RXTX_RATE_48 */
2143 5, /* CONF_HW_RXTX_RATE_36 */
2144 4, /* CONF_HW_RXTX_RATE_24 */
2145
2146 /* TI-specific rate */
2147 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2148
2149 3, /* CONF_HW_RXTX_RATE_18 */
2150 2, /* CONF_HW_RXTX_RATE_12 */
2151 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2152 1, /* CONF_HW_RXTX_RATE_9 */
2153 0, /* CONF_HW_RXTX_RATE_6 */
2154 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2155 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2156 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2157};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002158
2159static struct ieee80211_supported_band wl1271_band_5ghz = {
2160 .channels = wl1271_channels_5ghz,
2161 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2162 .bitrates = wl1271_rates_5ghz,
2163 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2164};
2165
Tobias Klausera0ea9492010-05-20 10:38:11 +02002166static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002167 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2168 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2169};
2170
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171static const struct ieee80211_ops wl1271_ops = {
2172 .start = wl1271_op_start,
2173 .stop = wl1271_op_stop,
2174 .add_interface = wl1271_op_add_interface,
2175 .remove_interface = wl1271_op_remove_interface,
2176 .config = wl1271_op_config,
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002177 .configure_arp_filter = wl1271_op_configure_arp_filter,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002178 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179 .configure_filter = wl1271_op_configure_filter,
2180 .tx = wl1271_op_tx,
2181 .set_key = wl1271_op_set_key,
2182 .hw_scan = wl1271_op_hw_scan,
2183 .bss_info_changed = wl1271_op_bss_info_changed,
2184 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002185 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002186 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002187 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002188};
2189
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002190
2191u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2192{
2193 u8 idx;
2194
2195 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2196
2197 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2198 wl1271_error("Illegal RX rate from HW: %d", rate);
2199 return 0;
2200 }
2201
2202 idx = wl1271_band_rate_to_idx[wl->band][rate];
2203 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2204 wl1271_error("Unsupported RX rate from HW: %d", rate);
2205 return 0;
2206 }
2207
2208 return idx;
2209}
2210
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002211static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2212 struct device_attribute *attr,
2213 char *buf)
2214{
2215 struct wl1271 *wl = dev_get_drvdata(dev);
2216 ssize_t len;
2217
2218 /* FIXME: what's the maximum length of buf? page size?*/
2219 len = 500;
2220
2221 mutex_lock(&wl->mutex);
2222 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2223 wl->sg_enabled);
2224 mutex_unlock(&wl->mutex);
2225
2226 return len;
2227
2228}
2229
2230static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2231 struct device_attribute *attr,
2232 const char *buf, size_t count)
2233{
2234 struct wl1271 *wl = dev_get_drvdata(dev);
2235 unsigned long res;
2236 int ret;
2237
2238 ret = strict_strtoul(buf, 10, &res);
2239
2240 if (ret < 0) {
2241 wl1271_warning("incorrect value written to bt_coex_mode");
2242 return count;
2243 }
2244
2245 mutex_lock(&wl->mutex);
2246
2247 res = !!res;
2248
2249 if (res == wl->sg_enabled)
2250 goto out;
2251
2252 wl->sg_enabled = res;
2253
2254 if (wl->state == WL1271_STATE_OFF)
2255 goto out;
2256
2257 ret = wl1271_ps_elp_wakeup(wl, false);
2258 if (ret < 0)
2259 goto out;
2260
2261 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2262 wl1271_ps_elp_sleep(wl);
2263
2264 out:
2265 mutex_unlock(&wl->mutex);
2266 return count;
2267}
2268
2269static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2270 wl1271_sysfs_show_bt_coex_state,
2271 wl1271_sysfs_store_bt_coex_state);
2272
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002273static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2274 struct device_attribute *attr,
2275 char *buf)
2276{
2277 struct wl1271 *wl = dev_get_drvdata(dev);
2278 ssize_t len;
2279
2280 /* FIXME: what's the maximum length of buf? page size?*/
2281 len = 500;
2282
2283 mutex_lock(&wl->mutex);
2284 if (wl->hw_pg_ver >= 0)
2285 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2286 else
2287 len = snprintf(buf, len, "n/a\n");
2288 mutex_unlock(&wl->mutex);
2289
2290 return len;
2291}
2292
2293static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2294 wl1271_sysfs_show_hw_pg_ver, NULL);
2295
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002296int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297{
2298 int ret;
2299
2300 if (wl->mac80211_registered)
2301 return 0;
2302
2303 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2304
2305 ret = ieee80211_register_hw(wl->hw);
2306 if (ret < 0) {
2307 wl1271_error("unable to register mac80211 hw: %d", ret);
2308 return ret;
2309 }
2310
2311 wl->mac80211_registered = true;
2312
2313 wl1271_notice("loaded");
2314
2315 return 0;
2316}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002317EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002319void wl1271_unregister_hw(struct wl1271 *wl)
2320{
2321 ieee80211_unregister_hw(wl->hw);
2322 wl->mac80211_registered = false;
2323
2324}
2325EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2326
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002327int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002329 /* The tx descriptor buffer and the TKIP space. */
2330 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2331 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332
2333 /* unit us */
2334 /* FIXME: find a proper value */
2335 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002336 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337
2338 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002339 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002340 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002341 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002342 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002343 IEEE80211_HW_CONNECTION_MONITOR |
2344 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002346 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2347 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002348 wl->hw->wiphy->max_scan_ssids = 1;
2349 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2350
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002351 if (wl1271_11a_enabled())
2352 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2353
Kalle Valo12bd8942010-03-18 12:26:33 +02002354 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002355 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002356
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002357 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358
2359 return 0;
2360}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002361EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002364
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002365struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002368 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002370 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371
2372 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2373 if (!hw) {
2374 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002375 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002376 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377 }
2378
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002379 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2380 if (!plat_dev) {
2381 wl1271_error("could not allocate platform_device");
2382 ret = -ENOMEM;
2383 goto err_plat_alloc;
2384 }
2385
2386 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 wl = hw->priv;
2389 memset(wl, 0, sizeof(*wl));
2390
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002391 INIT_LIST_HEAD(&wl->list);
2392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002394 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395
2396 skb_queue_head_init(&wl->tx_queue);
2397
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002398 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002399 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002401 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403 wl->rx_counter = 0;
2404 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2405 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002406 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002407 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002408 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002409 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002410 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2411 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002412 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002413 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002414 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002415 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002416 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002417
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002418 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002419 wl->tx_frames[i] = NULL;
2420
2421 spin_lock_init(&wl->wl_lock);
2422
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002423 wl->state = WL1271_STATE_OFF;
2424 mutex_init(&wl->mutex);
2425
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002426 /* Apply default driver configuration. */
2427 wl1271_conf_init(wl);
2428
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002429 wl1271_debugfs_init(wl);
2430
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002431 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002432 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002433 if (ret) {
2434 wl1271_error("couldn't register platform device");
2435 goto err_hw;
2436 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002437 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002438
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002439 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002440 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002441 if (ret < 0) {
2442 wl1271_error("failed to create sysfs file bt_coex_state");
2443 goto err_platform;
2444 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002445
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002446 /* Create sysfs file to get HW PG version */
2447 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2448 if (ret < 0) {
2449 wl1271_error("failed to create sysfs file hw_pg_ver");
2450 goto err_bt_coex_state;
2451 }
2452
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002453 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002454
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002455err_bt_coex_state:
2456 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2457
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002458err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002459 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002460
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002461err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002462 wl1271_debugfs_exit(wl);
2463 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002464
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002465err_plat_alloc:
2466 ieee80211_free_hw(hw);
2467
2468err_hw_alloc:
2469
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002470 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002471}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002472EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002473
2474int wl1271_free_hw(struct wl1271 *wl)
2475{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002476 platform_device_unregister(wl->plat_dev);
2477 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002478
2479 wl1271_debugfs_exit(wl);
2480
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002481 vfree(wl->fw);
2482 wl->fw = NULL;
2483 kfree(wl->nvs);
2484 wl->nvs = NULL;
2485
2486 kfree(wl->fw_status);
2487 kfree(wl->tx_res_if);
2488
2489 ieee80211_free_hw(wl->hw);
2490
2491 return 0;
2492}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002493EXPORT_SYMBOL_GPL(wl1271_free_hw);
2494
2495MODULE_LICENSE("GPL");
2496MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2497MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");