blob: 374abf0f5cc77dc18855089146b65846efb20fd9 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
127 [0] = {
128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
134 [1] = {
135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
141 [2] = {
142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
148 [3] = {
149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
156 .tid_conf_count = 7,
157 .tid_conf = {
158 [0] = {
159 .queue_id = 0,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
166 [1] = {
167 .queue_id = 1,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
174 [2] = {
175 .queue_id = 2,
176 .channel_type = CONF_CHANNEL_TYPE_DCF,
177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
182 [3] = {
183 .queue_id = 3,
184 .channel_type = CONF_CHANNEL_TYPE_DCF,
185 .tsid = CONF_TX_AC_BE,
186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
190 [4] = {
191 .queue_id = 4,
192 .channel_type = CONF_CHANNEL_TYPE_DCF,
193 .tsid = CONF_TX_AC_BE,
194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
198 [5] = {
199 .queue_id = 5,
200 .channel_type = CONF_CHANNEL_TYPE_DCF,
201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
206 [6] = {
207 .queue_id = 6,
208 .channel_type = CONF_CHANNEL_TYPE_DCF,
209 .tsid = CONF_TX_AC_BE,
210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 }
214 },
215 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200216 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300217 .tx_compl_threshold = 4,
218 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
219 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300224 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
225 .bcn_filt_ie_count = 1,
226 .bcn_filt_ie = {
227 [0] = {
228 .ie = WLAN_EID_CHANNEL_SWITCH,
229 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
230 }
231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200240 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200241 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
254 /* FIXME: due to firmware bug, must use value 1 for now */
255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
259 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 }
261};
262
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200263static void wl1271_device_release(struct device *dev)
264{
265
266}
267
268static struct platform_device wl1271_device = {
269 .name = "wl1271",
270 .id = -1,
271
272 /* device model insists to have a release function */
273 .dev = {
274 .release = wl1271_device_release,
275 },
276};
277
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300278static LIST_HEAD(wl_list);
279
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300280static void wl1271_conf_init(struct wl1271 *wl)
281{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300282
283 /*
284 * This function applies the default configuration to the driver. This
285 * function is invoked upon driver load (spi probe.)
286 *
287 * The configuration is stored in a run-time structure in order to
288 * facilitate for run-time adjustment of any of the parameters. Making
289 * changes to the configuration structure will apply the new values on
290 * the next interface up (wl1271_op_start.)
291 */
292
293 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300294 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300295}
296
297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300298static int wl1271_plt_init(struct wl1271 *wl)
299{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200300 struct conf_tx_ac_category *conf_ac;
301 struct conf_tx_tid *conf_tid;
302 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300303
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200304 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200305 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200306 return ret;
307
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200308 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200309 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200310 return ret;
311
Luciano Coelho12419cc2010-02-18 13:25:44 +0200312 ret = wl1271_init_templates_config(wl);
313 if (ret < 0)
314 return ret;
315
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300316 ret = wl1271_acx_init_mem_config(wl);
317 if (ret < 0)
318 return ret;
319
Luciano Coelho12419cc2010-02-18 13:25:44 +0200320 /* PHY layer config */
321 ret = wl1271_init_phy_config(wl);
322 if (ret < 0)
323 goto out_free_memmap;
324
325 ret = wl1271_acx_dco_itrim_params(wl);
326 if (ret < 0)
327 goto out_free_memmap;
328
329 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200330 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200331 if (ret < 0)
332 goto out_free_memmap;
333
334 /* Bluetooth WLAN coexistence */
335 ret = wl1271_init_pta(wl);
336 if (ret < 0)
337 goto out_free_memmap;
338
339 /* Energy detection */
340 ret = wl1271_init_energy_detection(wl);
341 if (ret < 0)
342 goto out_free_memmap;
343
344 /* Default fragmentation threshold */
345 ret = wl1271_acx_frag_threshold(wl);
346 if (ret < 0)
347 goto out_free_memmap;
348
349 /* Default TID configuration */
350 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
351 conf_tid = &wl->conf.tx.tid_conf[i];
352 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
353 conf_tid->channel_type,
354 conf_tid->tsid,
355 conf_tid->ps_scheme,
356 conf_tid->ack_policy,
357 conf_tid->apsd_conf[0],
358 conf_tid->apsd_conf[1]);
359 if (ret < 0)
360 goto out_free_memmap;
361 }
362
363 /* Default AC configuration */
364 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
365 conf_ac = &wl->conf.tx.ac_conf[i];
366 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
367 conf_ac->cw_max, conf_ac->aifsn,
368 conf_ac->tx_op_limit);
369 if (ret < 0)
370 goto out_free_memmap;
371 }
372
373 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200374 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300375 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200376 goto out_free_memmap;
377
378 /* Configure for CAM power saving (ie. always active) */
379 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
380 if (ret < 0)
381 goto out_free_memmap;
382
383 /* configure PM */
384 ret = wl1271_acx_pm_config(wl);
385 if (ret < 0)
386 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
388 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200389
390 out_free_memmap:
391 kfree(wl->target_mem_map);
392 wl->target_mem_map = NULL;
393
394 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300395}
396
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300397static void wl1271_fw_status(struct wl1271 *wl,
398 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200400 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300401 u32 total = 0;
402 int i;
403
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200404 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405
406 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
407 "drv_rx_counter = %d, tx_results_counter = %d)",
408 status->intr,
409 status->fw_rx_counter,
410 status->drv_rx_counter,
411 status->tx_results_counter);
412
413 /* update number of available TX blocks */
414 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300415 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
416 wl->tx_blocks_freed[i];
417
418 wl->tx_blocks_freed[i] =
419 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420 wl->tx_blocks_available += cnt;
421 total += cnt;
422 }
423
424 /* if more blocks are available now, schedule some tx work */
425 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300426 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427
428 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200429 getnstimeofday(&ts);
430 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
431 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432}
433
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200434#define WL1271_IRQ_MAX_LOOPS 10
435
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436static void wl1271_irq_work(struct work_struct *work)
437{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300438 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300439 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200440 int loopcount = WL1271_IRQ_MAX_LOOPS;
441 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 struct wl1271 *wl =
443 container_of(work, struct wl1271, irq_work);
444
445 mutex_lock(&wl->mutex);
446
447 wl1271_debug(DEBUG_IRQ, "IRQ work");
448
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200449 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450 goto out;
451
452 ret = wl1271_ps_elp_wakeup(wl, true);
453 if (ret < 0)
454 goto out;
455
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200456 spin_lock_irqsave(&wl->wl_lock, flags);
457 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
458 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
459 spin_unlock_irqrestore(&wl->wl_lock, flags);
460 loopcount--;
461
462 wl1271_fw_status(wl, wl->fw_status);
463 intr = le32_to_cpu(wl->fw_status->intr);
464 if (!intr) {
465 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200466 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200467 continue;
468 }
469
470 intr &= WL1271_INTR_MASK;
471
472 if (intr & WL1271_ACX_INTR_DATA) {
473 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
474
475 /* check for tx results */
476 if (wl->fw_status->tx_results_counter !=
477 (wl->tx_results_count & 0xff))
478 wl1271_tx_complete(wl);
479
480 wl1271_rx(wl, wl->fw_status);
481 }
482
483 if (intr & WL1271_ACX_INTR_EVENT_A) {
484 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
485 wl1271_event_handle(wl, 0);
486 }
487
488 if (intr & WL1271_ACX_INTR_EVENT_B) {
489 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
490 wl1271_event_handle(wl, 1);
491 }
492
493 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
494 wl1271_debug(DEBUG_IRQ,
495 "WL1271_ACX_INTR_INIT_COMPLETE");
496
497 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
498 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
499
500 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300501 }
502
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200503 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
504 ieee80211_queue_work(wl->hw, &wl->irq_work);
505 else
506 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
507 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300508
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300509 wl1271_ps_elp_sleep(wl);
510
511out:
512 mutex_unlock(&wl->mutex);
513}
514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515static int wl1271_fetch_firmware(struct wl1271 *wl)
516{
517 const struct firmware *fw;
518 int ret;
519
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200520 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521
522 if (ret < 0) {
523 wl1271_error("could not get firmware: %d", ret);
524 return ret;
525 }
526
527 if (fw->size % 4) {
528 wl1271_error("firmware size is not multiple of 32 bits: %zu",
529 fw->size);
530 ret = -EILSEQ;
531 goto out;
532 }
533
534 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300535 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300536
537 if (!wl->fw) {
538 wl1271_error("could not allocate memory for the firmware");
539 ret = -ENOMEM;
540 goto out;
541 }
542
543 memcpy(wl->fw, fw->data, wl->fw_len);
544
545 ret = 0;
546
547out:
548 release_firmware(fw);
549
550 return ret;
551}
552
553static int wl1271_fetch_nvs(struct wl1271 *wl)
554{
555 const struct firmware *fw;
556 int ret;
557
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200558 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559
560 if (ret < 0) {
561 wl1271_error("could not get nvs file: %d", ret);
562 return ret;
563 }
564
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300565 /*
566 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
567 * configurations) can be removed when those NVS files stop floating
568 * around.
569 */
570 if (fw->size != sizeof(struct wl1271_nvs_file) &&
571 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
572 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200573 wl1271_error("nvs size is not as expected: %zu != %zu",
574 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575 ret = -EILSEQ;
576 goto out;
577 }
578
Julia Lawall929ebd32010-05-15 23:16:39 +0200579 wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580
581 if (!wl->nvs) {
582 wl1271_error("could not allocate memory for the nvs file");
583 ret = -ENOMEM;
584 goto out;
585 }
586
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587out:
588 release_firmware(fw);
589
590 return ret;
591}
592
593static void wl1271_fw_wakeup(struct wl1271 *wl)
594{
595 u32 elp_reg;
596
597 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300598 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300599}
600
601static int wl1271_setup(struct wl1271 *wl)
602{
603 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
604 if (!wl->fw_status)
605 return -ENOMEM;
606
607 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
608 if (!wl->tx_res_if) {
609 kfree(wl->fw_status);
610 return -ENOMEM;
611 }
612
613 INIT_WORK(&wl->irq_work, wl1271_irq_work);
614 INIT_WORK(&wl->tx_work, wl1271_tx_work);
615 return 0;
616}
617
618static int wl1271_chip_wakeup(struct wl1271 *wl)
619{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300620 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621 int ret = 0;
622
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200623 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300624 wl1271_power_on(wl);
625 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200626 wl1271_io_reset(wl);
627 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628
629 /* We don't need a real memory partition here, because we only want
630 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300631 memset(&partition, 0, sizeof(partition));
632 partition.reg.start = REGISTERS_BASE;
633 partition.reg.size = REGISTERS_DOWN_SIZE;
634 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635
636 /* ELP module wake up */
637 wl1271_fw_wakeup(wl);
638
639 /* whal_FwCtrl_BootSm() */
640
641 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200642 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300643
644 /* 1. check if chip id is valid */
645
646 switch (wl->chip.id) {
647 case CHIP_ID_1271_PG10:
648 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
649 wl->chip.id);
650
651 ret = wl1271_setup(wl);
652 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200653 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300654 break;
655 case CHIP_ID_1271_PG20:
656 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
657 wl->chip.id);
658
659 ret = wl1271_setup(wl);
660 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200661 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 break;
663 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200664 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 }
668
669 if (wl->fw == NULL) {
670 ret = wl1271_fetch_firmware(wl);
671 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200672 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
675 /* No NVS from netlink, try to get it from the filesystem */
676 if (wl->nvs == NULL) {
677 ret = wl1271_fetch_nvs(wl);
678 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 }
681
682out:
683 return ret;
684}
685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686int wl1271_plt_start(struct wl1271 *wl)
687{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200688 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 int ret;
690
691 mutex_lock(&wl->mutex);
692
693 wl1271_notice("power up");
694
695 if (wl->state != WL1271_STATE_OFF) {
696 wl1271_error("cannot go into PLT state because not "
697 "in off state: %d", wl->state);
698 ret = -EBUSY;
699 goto out;
700 }
701
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200702 while (retries) {
703 retries--;
704 ret = wl1271_chip_wakeup(wl);
705 if (ret < 0)
706 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300707
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200708 ret = wl1271_boot(wl);
709 if (ret < 0)
710 goto power_off;
711
712 ret = wl1271_plt_init(wl);
713 if (ret < 0)
714 goto irq_disable;
715
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200716 wl->state = WL1271_STATE_PLT;
717 wl1271_notice("firmware booted in PLT mode (%s)",
718 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300719 goto out;
720
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200721irq_disable:
722 wl1271_disable_interrupts(wl);
723 mutex_unlock(&wl->mutex);
724 /* Unlocking the mutex in the middle of handling is
725 inherently unsafe. In this case we deem it safe to do,
726 because we need to let any possibly pending IRQ out of
727 the system (and while we are WL1271_STATE_OFF the IRQ
728 work function will not do anything.) Also, any other
729 possible concurrent operations will fail due to the
730 current state, hence the wl1271 struct should be safe. */
731 cancel_work_sync(&wl->irq_work);
732 mutex_lock(&wl->mutex);
733power_off:
734 wl1271_power_off(wl);
735 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200737 wl1271_error("firmware boot in PLT mode failed despite %d retries",
738 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300739out:
740 mutex_unlock(&wl->mutex);
741
742 return ret;
743}
744
745int wl1271_plt_stop(struct wl1271 *wl)
746{
747 int ret = 0;
748
749 mutex_lock(&wl->mutex);
750
751 wl1271_notice("power down");
752
753 if (wl->state != WL1271_STATE_PLT) {
754 wl1271_error("cannot power down because not in PLT "
755 "state: %d", wl->state);
756 ret = -EBUSY;
757 goto out;
758 }
759
760 wl1271_disable_interrupts(wl);
761 wl1271_power_off(wl);
762
763 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300764 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765
766out:
767 mutex_unlock(&wl->mutex);
768
769 return ret;
770}
771
772
773static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
774{
775 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200776 struct ieee80211_conf *conf = &hw->conf;
777 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
778 struct ieee80211_sta *sta = txinfo->control.sta;
779 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200781 /* peek into the rates configured in the STA entry */
782 spin_lock_irqsave(&wl->wl_lock, flags);
783 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
784 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
785 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
786 }
787 spin_unlock_irqrestore(&wl->wl_lock, flags);
788
789 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 skb_queue_tail(&wl->tx_queue, skb);
791
792 /*
793 * The chip specific setup must run before the first TX packet -
794 * before that, the tx_work will not be initialized!
795 */
796
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300797 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300798
799 /*
800 * The workqueue is slow to process the tx_queue and we need stop
801 * the queue here, otherwise the queue will get too long.
802 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200803 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
804 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200806 spin_lock_irqsave(&wl->wl_lock, flags);
807 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200808 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200809 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810 }
811
812 return NETDEV_TX_OK;
813}
814
815static int wl1271_op_start(struct ieee80211_hw *hw)
816{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200817 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
818
819 /*
820 * We have to delay the booting of the hardware because
821 * we need to know the local MAC address before downloading and
822 * initializing the firmware. The MAC address cannot be changed
823 * after boot, and without the proper MAC address, the firmware
824 * will not function properly.
825 *
826 * The MAC address is first known when the corresponding interface
827 * is added. That is where we will initialize the hardware.
828 */
829
830 return 0;
831}
832
833static void wl1271_op_stop(struct ieee80211_hw *hw)
834{
835 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
836}
837
838static int wl1271_op_add_interface(struct ieee80211_hw *hw,
839 struct ieee80211_vif *vif)
840{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200842 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 int ret = 0;
844
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200845 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
846 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300847
848 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200849 if (wl->vif) {
850 ret = -EBUSY;
851 goto out;
852 }
853
854 wl->vif = vif;
855
856 switch (vif->type) {
857 case NL80211_IFTYPE_STATION:
858 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200859 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200860 break;
861 case NL80211_IFTYPE_ADHOC:
862 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200863 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200864 break;
865 default:
866 ret = -EOPNOTSUPP;
867 goto out;
868 }
869
870 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871
872 if (wl->state != WL1271_STATE_OFF) {
873 wl1271_error("cannot start because not in off state: %d",
874 wl->state);
875 ret = -EBUSY;
876 goto out;
877 }
878
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200879 while (retries) {
880 retries--;
881 ret = wl1271_chip_wakeup(wl);
882 if (ret < 0)
883 goto power_off;
884
885 ret = wl1271_boot(wl);
886 if (ret < 0)
887 goto power_off;
888
889 ret = wl1271_hw_init(wl);
890 if (ret < 0)
891 goto irq_disable;
892
893 wl->state = WL1271_STATE_ON;
894 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300895 goto out;
896
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200897irq_disable:
898 wl1271_disable_interrupts(wl);
899 mutex_unlock(&wl->mutex);
900 /* Unlocking the mutex in the middle of handling is
901 inherently unsafe. In this case we deem it safe to do,
902 because we need to let any possibly pending IRQ out of
903 the system (and while we are WL1271_STATE_OFF the IRQ
904 work function will not do anything.) Also, any other
905 possible concurrent operations will fail due to the
906 current state, hence the wl1271 struct should be safe. */
907 cancel_work_sync(&wl->irq_work);
908 mutex_lock(&wl->mutex);
909power_off:
910 wl1271_power_off(wl);
911 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200913 wl1271_error("firmware boot failed despite %d retries",
914 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300915out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916 mutex_unlock(&wl->mutex);
917
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300918 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300919 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300920
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 return ret;
922}
923
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200924static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
925 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926{
927 struct wl1271 *wl = hw->priv;
928 int i;
929
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200930 mutex_lock(&wl->mutex);
931 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200933 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300935 list_del(&wl->list);
936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 WARN_ON(wl->state != WL1271_STATE_ON);
938
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300939 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300940 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300941 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300942
Luciano Coelho08688d62010-07-08 17:50:07 +0300943 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 mutex_unlock(&wl->mutex);
945 ieee80211_scan_completed(wl->hw, true);
946 mutex_lock(&wl->mutex);
Luciano Coelho08688d62010-07-08 17:50:07 +0300947 wl->scan.state = WL1271_SCAN_STATE_IDLE;
948 kfree(wl->scan.scanned_ch);
949 wl->scan.scanned_ch = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 }
951
952 wl->state = WL1271_STATE_OFF;
953
954 wl1271_disable_interrupts(wl);
955
956 mutex_unlock(&wl->mutex);
957
958 cancel_work_sync(&wl->irq_work);
959 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300960 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961
962 mutex_lock(&wl->mutex);
963
964 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300965 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966 wl1271_power_off(wl);
967
968 memset(wl->bssid, 0, ETH_ALEN);
969 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
970 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200972 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300973 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974
975 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200976 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
978 wl->tx_blocks_available = 0;
979 wl->tx_results_count = 0;
980 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300981 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200982 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 wl->time_offset = 0;
984 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200985 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
986 wl->sta_rate_set = 0;
987 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200988 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200989 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 for (i = 0; i < NUM_TX_QUEUES; i++)
992 wl->tx_blocks_freed[i] = 0;
993
994 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300995
996 kfree(wl->fw_status);
997 wl->fw_status = NULL;
998 kfree(wl->tx_res_if);
999 wl->tx_res_if = NULL;
1000 kfree(wl->target_mem_map);
1001 wl->target_mem_map = NULL;
1002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003 mutex_unlock(&wl->mutex);
1004}
1005
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001006static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1007{
1008 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1009 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1010
1011 /* combine requested filters with current filter config */
1012 filters = wl->filters | filters;
1013
1014 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1015
1016 if (filters & FIF_PROMISC_IN_BSS) {
1017 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1018 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1019 wl->rx_config |= CFG_BSSID_FILTER_EN;
1020 }
1021 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1022 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1023 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1024 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1025 }
1026 if (filters & FIF_OTHER_BSS) {
1027 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1028 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1029 }
1030 if (filters & FIF_CONTROL) {
1031 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1032 wl->rx_filter |= CFG_RX_CTL_EN;
1033 }
1034 if (filters & FIF_FCSFAIL) {
1035 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1036 wl->rx_filter |= CFG_RX_FCS_ERROR;
1037 }
1038}
1039
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001040static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001041{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001042 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001043 /* we need to use a dummy BSSID for now */
1044 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1045 0xad, 0xbe, 0xef };
1046
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001047 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1048
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001049 /* pass through frames from all BSS */
1050 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1051
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001052 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001053 if (ret < 0)
1054 goto out;
1055
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001056 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001057
1058out:
1059 return ret;
1060}
1061
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001062static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001063{
1064 int ret;
1065
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001066 /*
1067 * One of the side effects of the JOIN command is that is clears
1068 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1069 * to a WPA/WPA2 access point will therefore kill the data-path.
1070 * Currently there is no supported scenario for JOIN during
1071 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1072 * must be handled somehow.
1073 *
1074 */
1075 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1076 wl1271_info("JOIN while associated.");
1077
1078 if (set_assoc)
1079 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1080
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001081 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1082 if (ret < 0)
1083 goto out;
1084
1085 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1086
1087 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1088 goto out;
1089
1090 /*
1091 * The join command disable the keep-alive mode, shut down its process,
1092 * and also clear the template config, so we need to reset it all after
1093 * the join. The acx_aid starts the keep-alive process, and the order
1094 * of the commands below is relevant.
1095 */
1096 ret = wl1271_acx_keep_alive_mode(wl, true);
1097 if (ret < 0)
1098 goto out;
1099
1100 ret = wl1271_acx_aid(wl, wl->aid);
1101 if (ret < 0)
1102 goto out;
1103
1104 ret = wl1271_cmd_build_klv_null_data(wl);
1105 if (ret < 0)
1106 goto out;
1107
1108 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1109 ACX_KEEP_ALIVE_TPL_VALID);
1110 if (ret < 0)
1111 goto out;
1112
1113out:
1114 return ret;
1115}
1116
1117static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001118{
1119 int ret;
1120
1121 /* to stop listening to a channel, we disconnect */
1122 ret = wl1271_cmd_disconnect(wl);
1123 if (ret < 0)
1124 goto out;
1125
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001126 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001127 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001128
1129 /* stop filterting packets based on bssid */
1130 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001131
1132out:
1133 return ret;
1134}
1135
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001136static void wl1271_set_band_rate(struct wl1271 *wl)
1137{
1138 if (wl->band == IEEE80211_BAND_2GHZ)
1139 wl->basic_rate_set = wl->conf.tx.basic_rate;
1140 else
1141 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1142}
1143
1144static u32 wl1271_min_rate_get(struct wl1271 *wl)
1145{
1146 int i;
1147 u32 rate = 0;
1148
1149 if (!wl->basic_rate_set) {
1150 WARN_ON(1);
1151 wl->basic_rate_set = wl->conf.tx.basic_rate;
1152 }
1153
1154 for (i = 0; !rate; i++) {
1155 if ((wl->basic_rate_set >> i) & 0x1)
1156 rate = 1 << i;
1157 }
1158
1159 return rate;
1160}
1161
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001162static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1163{
1164 int ret;
1165
1166 if (idle) {
1167 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1168 ret = wl1271_unjoin(wl);
1169 if (ret < 0)
1170 goto out;
1171 }
1172 wl->rate_set = wl1271_min_rate_get(wl);
1173 wl->sta_rate_set = 0;
1174 ret = wl1271_acx_rate_policies(wl);
1175 if (ret < 0)
1176 goto out;
1177 ret = wl1271_acx_keep_alive_config(
1178 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1179 ACX_KEEP_ALIVE_TPL_INVALID);
1180 if (ret < 0)
1181 goto out;
1182 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1183 } else {
1184 /* increment the session counter */
1185 wl->session_counter++;
1186 if (wl->session_counter >= SESSION_COUNTER_MAX)
1187 wl->session_counter = 0;
1188 ret = wl1271_dummy_join(wl);
1189 if (ret < 0)
1190 goto out;
1191 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1192 }
1193
1194out:
1195 return ret;
1196}
1197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1199{
1200 struct wl1271 *wl = hw->priv;
1201 struct ieee80211_conf *conf = &hw->conf;
1202 int channel, ret = 0;
1203
1204 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1205
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001206 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 channel,
1208 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001209 conf->power_level,
1210 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001212 /*
1213 * mac80211 will go to idle nearly immediately after transmitting some
1214 * frames, such as the deauth. To make sure those frames reach the air,
1215 * wait here until the TX queue is fully flushed.
1216 */
1217 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1218 (conf->flags & IEEE80211_CONF_IDLE))
1219 wl1271_tx_flush(wl);
1220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001221 mutex_lock(&wl->mutex);
1222
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001223 if (unlikely(wl->state == WL1271_STATE_OFF))
1224 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 ret = wl1271_ps_elp_wakeup(wl, false);
1227 if (ret < 0)
1228 goto out;
1229
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001230 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001231 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1232 ((wl->band != conf->channel->band) ||
1233 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001234 wl->band = conf->channel->band;
1235 wl->channel = channel;
1236
1237 /*
1238 * FIXME: the mac80211 should really provide a fixed rate
1239 * to use here. for now, just use the smallest possible rate
1240 * for the band as a fixed rate for association frames and
1241 * other control messages.
1242 */
1243 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1244 wl1271_set_band_rate(wl);
1245
1246 wl->basic_rate = wl1271_min_rate_get(wl);
1247 ret = wl1271_acx_rate_policies(wl);
1248 if (ret < 0)
1249 wl1271_warning("rate policy for update channel "
1250 "failed %d", ret);
1251
1252 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001253 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001254 if (ret < 0)
1255 wl1271_warning("cmd join to update channel "
1256 "failed %d", ret);
1257 }
1258 }
1259
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001260 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001261 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1262 if (ret < 0)
1263 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264 }
1265
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001266 /*
1267 * if mac80211 changes the PSM mode, make sure the mode is not
1268 * incorrectly changed after the pspoll failure active window.
1269 */
1270 if (changed & IEEE80211_CONF_CHANGE_PS)
1271 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1272
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001273 if (conf->flags & IEEE80211_CONF_PS &&
1274 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1275 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276
1277 /*
1278 * We enter PSM only if we're already associated.
1279 * If we're not, we'll enter it when joining an SSID,
1280 * through the bss_info_changed() hook.
1281 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001282 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001283 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001284 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1285 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001286 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001288 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001289 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001291 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001293 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001294 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1295 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 }
1297
1298 if (conf->power_level != wl->power_level) {
1299 ret = wl1271_acx_tx_power(wl, conf->power_level);
1300 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001301 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302
1303 wl->power_level = conf->power_level;
1304 }
1305
1306out_sleep:
1307 wl1271_ps_elp_sleep(wl);
1308
1309out:
1310 mutex_unlock(&wl->mutex);
1311
1312 return ret;
1313}
1314
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001315struct wl1271_filter_params {
1316 bool enabled;
1317 int mc_list_length;
1318 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1319};
1320
Jiri Pirko22bedad32010-04-01 21:22:57 +00001321static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1322 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001324 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001325 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001326 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001327
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001328 if (unlikely(wl->state == WL1271_STATE_OFF))
1329 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001330
Juuso Oikarinen74441132009-10-13 12:47:53 +03001331 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001332 if (!fp) {
1333 wl1271_error("Out of memory setting filters.");
1334 return 0;
1335 }
1336
1337 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001338 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001339 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1340 fp->enabled = false;
1341 } else {
1342 fp->enabled = true;
1343 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001344 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001345 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001347 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001348 }
1349
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001350 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001351}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001353#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1354 FIF_ALLMULTI | \
1355 FIF_FCSFAIL | \
1356 FIF_BCN_PRBRESP_PROMISC | \
1357 FIF_CONTROL | \
1358 FIF_OTHER_BSS)
1359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1361 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001362 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001364 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001366 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367
1368 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1369
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001370 mutex_lock(&wl->mutex);
1371
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001372 *total &= WL1271_SUPPORTED_FILTERS;
1373 changed &= WL1271_SUPPORTED_FILTERS;
1374
1375 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001376 goto out;
1377
1378 ret = wl1271_ps_elp_wakeup(wl, false);
1379 if (ret < 0)
1380 goto out;
1381
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383 if (*total & FIF_ALLMULTI)
1384 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1385 else if (fp)
1386 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1387 fp->mc_list,
1388 fp->mc_list_length);
1389 if (ret < 0)
1390 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001391
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001392 /* determine, whether supported filter values have changed */
1393 if (changed == 0)
1394 goto out_sleep;
1395
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001396 /* configure filters */
1397 wl->filters = *total;
1398 wl1271_configure_filters(wl, 0);
1399
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001400 /* apply configured filters */
1401 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1402 if (ret < 0)
1403 goto out_sleep;
1404
1405out_sleep:
1406 wl1271_ps_elp_sleep(wl);
1407
1408out:
1409 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001410 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411}
1412
1413static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1414 struct ieee80211_vif *vif,
1415 struct ieee80211_sta *sta,
1416 struct ieee80211_key_conf *key_conf)
1417{
1418 struct wl1271 *wl = hw->priv;
1419 const u8 *addr;
1420 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001421 u32 tx_seq_32 = 0;
1422 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001423 u8 key_type;
1424
1425 static const u8 bcast_addr[ETH_ALEN] =
1426 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1427
1428 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1429
1430 addr = sta ? sta->addr : bcast_addr;
1431
1432 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1433 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1434 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1435 key_conf->alg, key_conf->keyidx,
1436 key_conf->keylen, key_conf->flags);
1437 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1438
1439 if (is_zero_ether_addr(addr)) {
1440 /* We dont support TX only encryption */
1441 ret = -EOPNOTSUPP;
1442 goto out;
1443 }
1444
1445 mutex_lock(&wl->mutex);
1446
1447 ret = wl1271_ps_elp_wakeup(wl, false);
1448 if (ret < 0)
1449 goto out_unlock;
1450
1451 switch (key_conf->alg) {
1452 case ALG_WEP:
1453 key_type = KEY_WEP;
1454
1455 key_conf->hw_key_idx = key_conf->keyidx;
1456 break;
1457 case ALG_TKIP:
1458 key_type = KEY_TKIP;
1459
1460 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001461 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1462 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463 break;
1464 case ALG_CCMP:
1465 key_type = KEY_AES;
1466
1467 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001468 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1469 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 break;
1471 default:
1472 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1473
1474 ret = -EOPNOTSUPP;
1475 goto out_sleep;
1476 }
1477
1478 switch (cmd) {
1479 case SET_KEY:
1480 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1481 key_conf->keyidx, key_type,
1482 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001483 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484 if (ret < 0) {
1485 wl1271_error("Could not add or replace key");
1486 goto out_sleep;
1487 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001488
1489 /* the default WEP key needs to be configured at least once */
1490 if (key_type == KEY_WEP) {
1491 ret = wl1271_cmd_set_default_wep_key(wl,
1492 wl->default_key);
1493 if (ret < 0)
1494 goto out_sleep;
1495 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496 break;
1497
1498 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001499 /* The wl1271 does not allow to remove unicast keys - they
1500 will be cleared automatically on next CMD_JOIN. Ignore the
1501 request silently, as we dont want the mac80211 to emit
1502 an error message. */
1503 if (!is_broadcast_ether_addr(addr))
1504 break;
1505
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1507 key_conf->keyidx, key_type,
1508 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001509 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510 if (ret < 0) {
1511 wl1271_error("Could not remove key");
1512 goto out_sleep;
1513 }
1514 break;
1515
1516 default:
1517 wl1271_error("Unsupported key cmd 0x%x", cmd);
1518 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519 break;
1520 }
1521
1522out_sleep:
1523 wl1271_ps_elp_sleep(wl);
1524
1525out_unlock:
1526 mutex_unlock(&wl->mutex);
1527
1528out:
1529 return ret;
1530}
1531
1532static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001533 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534 struct cfg80211_scan_request *req)
1535{
1536 struct wl1271 *wl = hw->priv;
1537 int ret;
1538 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001539 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540
1541 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1542
1543 if (req->n_ssids) {
1544 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001545 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001546 }
1547
1548 mutex_lock(&wl->mutex);
1549
1550 ret = wl1271_ps_elp_wakeup(wl, false);
1551 if (ret < 0)
1552 goto out;
1553
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001554 if (wl1271_11a_enabled())
Luciano Coelho08688d62010-07-08 17:50:07 +03001555 ret = wl1271_scan(hw->priv, ssid, len, req);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001556 else
Luciano Coelho08688d62010-07-08 17:50:07 +03001557 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558
1559 wl1271_ps_elp_sleep(wl);
1560
1561out:
1562 mutex_unlock(&wl->mutex);
1563
1564 return ret;
1565}
1566
1567static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1568{
1569 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001570 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571
1572 mutex_lock(&wl->mutex);
1573
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001574 if (unlikely(wl->state == WL1271_STATE_OFF))
1575 goto out;
1576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 ret = wl1271_ps_elp_wakeup(wl, false);
1578 if (ret < 0)
1579 goto out;
1580
1581 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1582 if (ret < 0)
1583 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1584
1585 wl1271_ps_elp_sleep(wl);
1586
1587out:
1588 mutex_unlock(&wl->mutex);
1589
1590 return ret;
1591}
1592
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001593static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1594{
1595 u8 *ptr = beacon->data +
1596 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1597
1598 /* find the location of the ssid in the beacon */
1599 while (ptr < beacon->data + beacon->len) {
1600 if (ptr[0] == WLAN_EID_SSID) {
1601 wl->ssid_len = ptr[1];
1602 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1603 return;
1604 }
1605 ptr += ptr[1];
1606 }
1607 wl1271_error("ad-hoc beacon template has no SSID!\n");
1608}
1609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1611 struct ieee80211_vif *vif,
1612 struct ieee80211_bss_conf *bss_conf,
1613 u32 changed)
1614{
1615 enum wl1271_cmd_ps_mode mode;
1616 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001617 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001618 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001619 int ret;
1620
1621 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1622
1623 mutex_lock(&wl->mutex);
1624
1625 ret = wl1271_ps_elp_wakeup(wl, false);
1626 if (ret < 0)
1627 goto out;
1628
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001629 if ((changed && BSS_CHANGED_BEACON_INT) &&
1630 (wl->bss_type == BSS_TYPE_IBSS)) {
1631 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1632 bss_conf->beacon_int);
1633
1634 wl->beacon_int = bss_conf->beacon_int;
1635 do_join = true;
1636 }
1637
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001638 if ((changed && BSS_CHANGED_BEACON) &&
1639 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001640 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1641
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001642 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1643
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 if (beacon) {
1645 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001646
1647 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1649 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001650 beacon->len, 0,
1651 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001652
1653 if (ret < 0) {
1654 dev_kfree_skb(beacon);
1655 goto out_sleep;
1656 }
1657
1658 hdr = (struct ieee80211_hdr *) beacon->data;
1659 hdr->frame_control = cpu_to_le16(
1660 IEEE80211_FTYPE_MGMT |
1661 IEEE80211_STYPE_PROBE_RESP);
1662
1663 ret = wl1271_cmd_template_set(wl,
1664 CMD_TEMPL_PROBE_RESPONSE,
1665 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001666 beacon->len, 0,
1667 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001668 dev_kfree_skb(beacon);
1669 if (ret < 0)
1670 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001671
1672 /* Need to update the SSID (for filtering etc) */
1673 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001674 }
1675 }
1676
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001677 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1678 (wl->bss_type == BSS_TYPE_IBSS)) {
1679 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1680 bss_conf->enable_beacon ? "enabled" : "disabled");
1681
1682 if (bss_conf->enable_beacon)
1683 wl->set_bss_type = BSS_TYPE_IBSS;
1684 else
1685 wl->set_bss_type = BSS_TYPE_STA_BSS;
1686 do_join = true;
1687 }
1688
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001689 if (changed & BSS_CHANGED_CQM) {
1690 bool enable = false;
1691 if (bss_conf->cqm_rssi_thold)
1692 enable = true;
1693 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1694 bss_conf->cqm_rssi_thold,
1695 bss_conf->cqm_rssi_hyst);
1696 if (ret < 0)
1697 goto out;
1698 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1699 }
1700
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001701 if ((changed & BSS_CHANGED_BSSID) &&
1702 /*
1703 * Now we know the correct bssid, so we send a new join command
1704 * and enable the BSSID filter
1705 */
1706 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001707 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001708
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001709 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001710 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001711 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001712
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001713 ret = wl1271_build_qos_null_data(wl);
1714 if (ret < 0)
1715 goto out_sleep;
1716
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001717 /* filter out all packets not from this BSSID */
1718 wl1271_configure_filters(wl, 0);
1719
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001720 /* Need to update the BSSID (for filtering etc) */
1721 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001722 }
1723
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001724 if (changed & BSS_CHANGED_ASSOC) {
1725 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001726 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001728 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001730 wl->ps_poll_failures = 0;
1731
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001732 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001733 * use basic rates from AP, and determine lowest rate
1734 * to use with control frames.
1735 */
1736 rates = bss_conf->basic_rates;
1737 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1738 rates);
1739 wl->basic_rate = wl1271_min_rate_get(wl);
1740 ret = wl1271_acx_rate_policies(wl);
1741 if (ret < 0)
1742 goto out_sleep;
1743
1744 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001745 * with wl1271, we don't need to update the
1746 * beacon_int and dtim_period, because the firmware
1747 * updates it by itself when the first beacon is
1748 * received after a join.
1749 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001750 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1751 if (ret < 0)
1752 goto out_sleep;
1753
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001754 /*
1755 * The SSID is intentionally set to NULL here - the
1756 * firmware will set the probe request with a
1757 * broadcast SSID regardless of what we set in the
1758 * template.
1759 */
1760 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1761 NULL, 0, wl->band);
1762
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001763 /* enable the connection monitoring feature */
1764 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001765 if (ret < 0)
1766 goto out_sleep;
1767
1768 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001769 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1770 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001772 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773 if (ret < 0)
1774 goto out_sleep;
1775 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001776 } else {
1777 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001778 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001779 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001780
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001781 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001782 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001783
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001784 /* revert back to minimum rates for the current band */
1785 wl1271_set_band_rate(wl);
1786 wl->basic_rate = wl1271_min_rate_get(wl);
1787 ret = wl1271_acx_rate_policies(wl);
1788 if (ret < 0)
1789 goto out_sleep;
1790
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001791 /* disable connection monitor features */
1792 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001793
1794 /* Disable the keep-alive feature */
1795 ret = wl1271_acx_keep_alive_mode(wl, false);
1796
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001797 if (ret < 0)
1798 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 if (changed & BSS_CHANGED_ERP_SLOT) {
1804 if (bss_conf->use_short_slot)
1805 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1806 else
1807 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1808 if (ret < 0) {
1809 wl1271_warning("Set slot time failed %d", ret);
1810 goto out_sleep;
1811 }
1812 }
1813
1814 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1815 if (bss_conf->use_short_preamble)
1816 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1817 else
1818 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1819 }
1820
1821 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1822 if (bss_conf->use_cts_prot)
1823 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1824 else
1825 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1826 if (ret < 0) {
1827 wl1271_warning("Set ctsprotect failed %d", ret);
1828 goto out_sleep;
1829 }
1830 }
1831
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001832 if (changed & BSS_CHANGED_ARP_FILTER) {
1833 __be32 addr = bss_conf->arp_addr_list[0];
1834 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1835
1836 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1837 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1838 else
1839 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1840
1841 if (ret < 0)
1842 goto out_sleep;
1843 }
1844
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001845 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001846 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001847 if (ret < 0) {
1848 wl1271_warning("cmd join failed %d", ret);
1849 goto out_sleep;
1850 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001851 }
1852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853out_sleep:
1854 wl1271_ps_elp_sleep(wl);
1855
1856out:
1857 mutex_unlock(&wl->mutex);
1858}
1859
Kalle Valoc6999d82010-02-18 13:25:41 +02001860static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1861 const struct ieee80211_tx_queue_params *params)
1862{
1863 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001864 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001865 int ret;
1866
1867 mutex_lock(&wl->mutex);
1868
1869 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1870
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001871 ret = wl1271_ps_elp_wakeup(wl, false);
1872 if (ret < 0)
1873 goto out;
1874
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001875 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001876 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1877 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001878 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001879 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001880 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001881
Kalle Valo4695dc92010-03-18 12:26:38 +02001882 if (params->uapsd)
1883 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1884 else
1885 ps_scheme = CONF_PS_SCHEME_LEGACY;
1886
Kalle Valoc6999d82010-02-18 13:25:41 +02001887 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1888 CONF_CHANNEL_TYPE_EDCF,
1889 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001890 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001891 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001892 goto out_sleep;
1893
1894out_sleep:
1895 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001896
1897out:
1898 mutex_unlock(&wl->mutex);
1899
1900 return ret;
1901}
1902
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001903static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1904{
1905
1906 struct wl1271 *wl = hw->priv;
1907 u64 mactime = ULLONG_MAX;
1908 int ret;
1909
1910 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1911
1912 mutex_lock(&wl->mutex);
1913
1914 ret = wl1271_ps_elp_wakeup(wl, false);
1915 if (ret < 0)
1916 goto out;
1917
1918 ret = wl1271_acx_tsf_info(wl, &mactime);
1919 if (ret < 0)
1920 goto out_sleep;
1921
1922out_sleep:
1923 wl1271_ps_elp_sleep(wl);
1924
1925out:
1926 mutex_unlock(&wl->mutex);
1927 return mactime;
1928}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929
John W. Linvilleece550d2010-07-28 16:41:06 -04001930static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
1931 struct survey_info *survey)
1932{
1933 struct wl1271 *wl = hw->priv;
1934 struct ieee80211_conf *conf = &hw->conf;
1935
1936 if (idx != 0)
1937 return -ENOENT;
1938
1939 survey->channel = conf->channel;
1940 survey->filled = SURVEY_INFO_NOISE_DBM;
1941 survey->noise = wl->noise;
1942
1943 return 0;
1944}
1945
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001946/* can't be const, mac80211 writes to this */
1947static struct ieee80211_rate wl1271_rates[] = {
1948 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001949 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1950 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001952 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1953 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1955 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001956 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1957 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1959 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1963 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001964 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1965 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001967 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1968 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001970 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1971 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001973 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1974 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001976 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1977 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001978 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001979 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1980 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001982 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1983 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001984 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001985 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1986 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987};
1988
1989/* can't be const, mac80211 writes to this */
1990static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001991 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1992 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1993 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1994 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1995 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1996 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1997 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1998 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1999 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
2000 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
2001 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2002 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2003 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004};
2005
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002006/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002007static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002008 /* MCS rates are used only with 11n */
2009 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2010 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2011 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2012 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2013 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2014 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2015 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2016 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2017
2018 11, /* CONF_HW_RXTX_RATE_54 */
2019 10, /* CONF_HW_RXTX_RATE_48 */
2020 9, /* CONF_HW_RXTX_RATE_36 */
2021 8, /* CONF_HW_RXTX_RATE_24 */
2022
2023 /* TI-specific rate */
2024 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2025
2026 7, /* CONF_HW_RXTX_RATE_18 */
2027 6, /* CONF_HW_RXTX_RATE_12 */
2028 3, /* CONF_HW_RXTX_RATE_11 */
2029 5, /* CONF_HW_RXTX_RATE_9 */
2030 4, /* CONF_HW_RXTX_RATE_6 */
2031 2, /* CONF_HW_RXTX_RATE_5_5 */
2032 1, /* CONF_HW_RXTX_RATE_2 */
2033 0 /* CONF_HW_RXTX_RATE_1 */
2034};
2035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002036/* can't be const, mac80211 writes to this */
2037static struct ieee80211_supported_band wl1271_band_2ghz = {
2038 .channels = wl1271_channels,
2039 .n_channels = ARRAY_SIZE(wl1271_channels),
2040 .bitrates = wl1271_rates,
2041 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2042};
2043
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002044/* 5 GHz data rates for WL1273 */
2045static struct ieee80211_rate wl1271_rates_5ghz[] = {
2046 { .bitrate = 60,
2047 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2048 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2049 { .bitrate = 90,
2050 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2051 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2052 { .bitrate = 120,
2053 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2054 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2055 { .bitrate = 180,
2056 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2057 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2058 { .bitrate = 240,
2059 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2060 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2061 { .bitrate = 360,
2062 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2063 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2064 { .bitrate = 480,
2065 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2066 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2067 { .bitrate = 540,
2068 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2069 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2070};
2071
2072/* 5 GHz band channels for WL1273 */
2073static struct ieee80211_channel wl1271_channels_5ghz[] = {
2074 { .hw_value = 183, .center_freq = 4915},
2075 { .hw_value = 184, .center_freq = 4920},
2076 { .hw_value = 185, .center_freq = 4925},
2077 { .hw_value = 187, .center_freq = 4935},
2078 { .hw_value = 188, .center_freq = 4940},
2079 { .hw_value = 189, .center_freq = 4945},
2080 { .hw_value = 192, .center_freq = 4960},
2081 { .hw_value = 196, .center_freq = 4980},
2082 { .hw_value = 7, .center_freq = 5035},
2083 { .hw_value = 8, .center_freq = 5040},
2084 { .hw_value = 9, .center_freq = 5045},
2085 { .hw_value = 11, .center_freq = 5055},
2086 { .hw_value = 12, .center_freq = 5060},
2087 { .hw_value = 16, .center_freq = 5080},
2088 { .hw_value = 34, .center_freq = 5170},
2089 { .hw_value = 36, .center_freq = 5180},
2090 { .hw_value = 38, .center_freq = 5190},
2091 { .hw_value = 40, .center_freq = 5200},
2092 { .hw_value = 42, .center_freq = 5210},
2093 { .hw_value = 44, .center_freq = 5220},
2094 { .hw_value = 46, .center_freq = 5230},
2095 { .hw_value = 48, .center_freq = 5240},
2096 { .hw_value = 52, .center_freq = 5260},
2097 { .hw_value = 56, .center_freq = 5280},
2098 { .hw_value = 60, .center_freq = 5300},
2099 { .hw_value = 64, .center_freq = 5320},
2100 { .hw_value = 100, .center_freq = 5500},
2101 { .hw_value = 104, .center_freq = 5520},
2102 { .hw_value = 108, .center_freq = 5540},
2103 { .hw_value = 112, .center_freq = 5560},
2104 { .hw_value = 116, .center_freq = 5580},
2105 { .hw_value = 120, .center_freq = 5600},
2106 { .hw_value = 124, .center_freq = 5620},
2107 { .hw_value = 128, .center_freq = 5640},
2108 { .hw_value = 132, .center_freq = 5660},
2109 { .hw_value = 136, .center_freq = 5680},
2110 { .hw_value = 140, .center_freq = 5700},
2111 { .hw_value = 149, .center_freq = 5745},
2112 { .hw_value = 153, .center_freq = 5765},
2113 { .hw_value = 157, .center_freq = 5785},
2114 { .hw_value = 161, .center_freq = 5805},
2115 { .hw_value = 165, .center_freq = 5825},
2116};
2117
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002118/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002119static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002120 /* MCS rates are used only with 11n */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2122 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2123 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2124 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2125 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2129
2130 7, /* CONF_HW_RXTX_RATE_54 */
2131 6, /* CONF_HW_RXTX_RATE_48 */
2132 5, /* CONF_HW_RXTX_RATE_36 */
2133 4, /* CONF_HW_RXTX_RATE_24 */
2134
2135 /* TI-specific rate */
2136 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2137
2138 3, /* CONF_HW_RXTX_RATE_18 */
2139 2, /* CONF_HW_RXTX_RATE_12 */
2140 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2141 1, /* CONF_HW_RXTX_RATE_9 */
2142 0, /* CONF_HW_RXTX_RATE_6 */
2143 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2144 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2145 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2146};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002147
2148static struct ieee80211_supported_band wl1271_band_5ghz = {
2149 .channels = wl1271_channels_5ghz,
2150 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2151 .bitrates = wl1271_rates_5ghz,
2152 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2153};
2154
Tobias Klausera0ea9492010-05-20 10:38:11 +02002155static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002156 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2157 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2158};
2159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160static const struct ieee80211_ops wl1271_ops = {
2161 .start = wl1271_op_start,
2162 .stop = wl1271_op_stop,
2163 .add_interface = wl1271_op_add_interface,
2164 .remove_interface = wl1271_op_remove_interface,
2165 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002166 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002167 .configure_filter = wl1271_op_configure_filter,
2168 .tx = wl1271_op_tx,
2169 .set_key = wl1271_op_set_key,
2170 .hw_scan = wl1271_op_hw_scan,
2171 .bss_info_changed = wl1271_op_bss_info_changed,
2172 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002173 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002174 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04002175 .get_survey = wl1271_op_get_survey,
Kalle Valoc8c90872010-02-18 13:25:53 +02002176 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177};
2178
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002179
2180u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2181{
2182 u8 idx;
2183
2184 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2185
2186 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2187 wl1271_error("Illegal RX rate from HW: %d", rate);
2188 return 0;
2189 }
2190
2191 idx = wl1271_band_rate_to_idx[wl->band][rate];
2192 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2193 wl1271_error("Unsupported RX rate from HW: %d", rate);
2194 return 0;
2195 }
2196
2197 return idx;
2198}
2199
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002200static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2201 struct device_attribute *attr,
2202 char *buf)
2203{
2204 struct wl1271 *wl = dev_get_drvdata(dev);
2205 ssize_t len;
2206
2207 /* FIXME: what's the maximum length of buf? page size?*/
2208 len = 500;
2209
2210 mutex_lock(&wl->mutex);
2211 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2212 wl->sg_enabled);
2213 mutex_unlock(&wl->mutex);
2214
2215 return len;
2216
2217}
2218
2219static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2220 struct device_attribute *attr,
2221 const char *buf, size_t count)
2222{
2223 struct wl1271 *wl = dev_get_drvdata(dev);
2224 unsigned long res;
2225 int ret;
2226
2227 ret = strict_strtoul(buf, 10, &res);
2228
2229 if (ret < 0) {
2230 wl1271_warning("incorrect value written to bt_coex_mode");
2231 return count;
2232 }
2233
2234 mutex_lock(&wl->mutex);
2235
2236 res = !!res;
2237
2238 if (res == wl->sg_enabled)
2239 goto out;
2240
2241 wl->sg_enabled = res;
2242
2243 if (wl->state == WL1271_STATE_OFF)
2244 goto out;
2245
2246 ret = wl1271_ps_elp_wakeup(wl, false);
2247 if (ret < 0)
2248 goto out;
2249
2250 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2251 wl1271_ps_elp_sleep(wl);
2252
2253 out:
2254 mutex_unlock(&wl->mutex);
2255 return count;
2256}
2257
2258static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2259 wl1271_sysfs_show_bt_coex_state,
2260 wl1271_sysfs_store_bt_coex_state);
2261
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002262static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2263 struct device_attribute *attr,
2264 char *buf)
2265{
2266 struct wl1271 *wl = dev_get_drvdata(dev);
2267 ssize_t len;
2268
2269 /* FIXME: what's the maximum length of buf? page size?*/
2270 len = 500;
2271
2272 mutex_lock(&wl->mutex);
2273 if (wl->hw_pg_ver >= 0)
2274 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2275 else
2276 len = snprintf(buf, len, "n/a\n");
2277 mutex_unlock(&wl->mutex);
2278
2279 return len;
2280}
2281
2282static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2283 wl1271_sysfs_show_hw_pg_ver, NULL);
2284
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002285int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002286{
2287 int ret;
2288
2289 if (wl->mac80211_registered)
2290 return 0;
2291
2292 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2293
2294 ret = ieee80211_register_hw(wl->hw);
2295 if (ret < 0) {
2296 wl1271_error("unable to register mac80211 hw: %d", ret);
2297 return ret;
2298 }
2299
2300 wl->mac80211_registered = true;
2301
2302 wl1271_notice("loaded");
2303
2304 return 0;
2305}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002306EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002307
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002308void wl1271_unregister_hw(struct wl1271 *wl)
2309{
2310 ieee80211_unregister_hw(wl->hw);
2311 wl->mac80211_registered = false;
2312
2313}
2314EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2315
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002316int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002318 /* The tx descriptor buffer and the TKIP space. */
2319 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2320 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002321
2322 /* unit us */
2323 /* FIXME: find a proper value */
2324 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002325 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002326
2327 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002328 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002329 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002330 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002331 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002332 IEEE80211_HW_CONNECTION_MONITOR |
2333 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002335 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2336 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 wl->hw->wiphy->max_scan_ssids = 1;
2338 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2339
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002340 if (wl1271_11a_enabled())
2341 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2342
Kalle Valo12bd8942010-03-18 12:26:33 +02002343 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002344 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002345
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002346 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347
2348 return 0;
2349}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002350EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002353
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002354struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002357 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002359 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360
2361 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2362 if (!hw) {
2363 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002364 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002365 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 }
2367
Julia Lawall929ebd32010-05-15 23:16:39 +02002368 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002369 if (!plat_dev) {
2370 wl1271_error("could not allocate platform_device");
2371 ret = -ENOMEM;
2372 goto err_plat_alloc;
2373 }
2374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 wl = hw->priv;
2376 memset(wl, 0, sizeof(*wl));
2377
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002378 INIT_LIST_HEAD(&wl->list);
2379
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002381 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382
2383 skb_queue_head_init(&wl->tx_queue);
2384
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002385 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002386 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002388 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 wl->rx_counter = 0;
2391 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2392 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002393 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002395 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002397 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2398 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002399 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002400 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002401 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002402 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002403 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002405 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002406 wl->tx_frames[i] = NULL;
2407
2408 spin_lock_init(&wl->wl_lock);
2409
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002410 wl->state = WL1271_STATE_OFF;
2411 mutex_init(&wl->mutex);
2412
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002413 /* Apply default driver configuration. */
2414 wl1271_conf_init(wl);
2415
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002416 wl1271_debugfs_init(wl);
2417
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002418 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002419 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002420 if (ret) {
2421 wl1271_error("couldn't register platform device");
2422 goto err_hw;
2423 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002424 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002425
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002426 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002427 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002428 if (ret < 0) {
2429 wl1271_error("failed to create sysfs file bt_coex_state");
2430 goto err_platform;
2431 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002432
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002433 /* Create sysfs file to get HW PG version */
2434 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2435 if (ret < 0) {
2436 wl1271_error("failed to create sysfs file hw_pg_ver");
2437 goto err_bt_coex_state;
2438 }
2439
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002440 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002441
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002442err_bt_coex_state:
2443 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2444
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002445err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002446 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002447
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002448err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002449 wl1271_debugfs_exit(wl);
2450 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002451
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002452err_plat_alloc:
2453 ieee80211_free_hw(hw);
2454
2455err_hw_alloc:
2456
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002457 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002458}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002459EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002460
2461int wl1271_free_hw(struct wl1271 *wl)
2462{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002463 platform_device_unregister(wl->plat_dev);
2464 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002465
2466 wl1271_debugfs_exit(wl);
2467
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002468 vfree(wl->fw);
2469 wl->fw = NULL;
2470 kfree(wl->nvs);
2471 wl->nvs = NULL;
2472
2473 kfree(wl->fw_status);
2474 kfree(wl->tx_res_if);
2475
2476 ieee80211_free_hw(wl->hw);
2477
2478 return 0;
2479}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002480EXPORT_SYMBOL_GPL(wl1271_free_hw);
2481
2482MODULE_LICENSE("GPL");
2483MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2484MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");