blob: cdfcc054efe4cec9f6fb30235f43e0fd427e0958 [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
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300579 wl->nvs = kzalloc(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
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300587 memcpy(wl->nvs, fw->data, fw->size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300588
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300589out:
590 release_firmware(fw);
591
592 return ret;
593}
594
595static void wl1271_fw_wakeup(struct wl1271 *wl)
596{
597 u32 elp_reg;
598
599 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300600 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601}
602
603static int wl1271_setup(struct wl1271 *wl)
604{
605 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
606 if (!wl->fw_status)
607 return -ENOMEM;
608
609 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
610 if (!wl->tx_res_if) {
611 kfree(wl->fw_status);
612 return -ENOMEM;
613 }
614
615 INIT_WORK(&wl->irq_work, wl1271_irq_work);
616 INIT_WORK(&wl->tx_work, wl1271_tx_work);
617 return 0;
618}
619
620static int wl1271_chip_wakeup(struct wl1271 *wl)
621{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300622 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623 int ret = 0;
624
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200625 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626 wl1271_power_on(wl);
627 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200628 wl1271_io_reset(wl);
629 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300630
631 /* We don't need a real memory partition here, because we only want
632 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300633 memset(&partition, 0, sizeof(partition));
634 partition.reg.start = REGISTERS_BASE;
635 partition.reg.size = REGISTERS_DOWN_SIZE;
636 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637
638 /* ELP module wake up */
639 wl1271_fw_wakeup(wl);
640
641 /* whal_FwCtrl_BootSm() */
642
643 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200644 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645
646 /* 1. check if chip id is valid */
647
648 switch (wl->chip.id) {
649 case CHIP_ID_1271_PG10:
650 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
651 wl->chip.id);
652
653 ret = wl1271_setup(wl);
654 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200655 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 break;
657 case CHIP_ID_1271_PG20:
658 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
659 wl->chip.id);
660
661 ret = wl1271_setup(wl);
662 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 break;
665 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200668 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 }
670
671 if (wl->fw == NULL) {
672 ret = wl1271_fetch_firmware(wl);
673 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200674 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675 }
676
677 /* No NVS from netlink, try to get it from the filesystem */
678 if (wl->nvs == NULL) {
679 ret = wl1271_fetch_nvs(wl);
680 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200681 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 }
683
684out:
685 return ret;
686}
687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688int wl1271_plt_start(struct wl1271 *wl)
689{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 int ret;
692
693 mutex_lock(&wl->mutex);
694
695 wl1271_notice("power up");
696
697 if (wl->state != WL1271_STATE_OFF) {
698 wl1271_error("cannot go into PLT state because not "
699 "in off state: %d", wl->state);
700 ret = -EBUSY;
701 goto out;
702 }
703
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200704 while (retries) {
705 retries--;
706 ret = wl1271_chip_wakeup(wl);
707 if (ret < 0)
708 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200710 ret = wl1271_boot(wl);
711 if (ret < 0)
712 goto power_off;
713
714 ret = wl1271_plt_init(wl);
715 if (ret < 0)
716 goto irq_disable;
717
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718 wl->state = WL1271_STATE_PLT;
719 wl1271_notice("firmware booted in PLT mode (%s)",
720 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 goto out;
722
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723irq_disable:
724 wl1271_disable_interrupts(wl);
725 mutex_unlock(&wl->mutex);
726 /* Unlocking the mutex in the middle of handling is
727 inherently unsafe. In this case we deem it safe to do,
728 because we need to let any possibly pending IRQ out of
729 the system (and while we are WL1271_STATE_OFF the IRQ
730 work function will not do anything.) Also, any other
731 possible concurrent operations will fail due to the
732 current state, hence the wl1271 struct should be safe. */
733 cancel_work_sync(&wl->irq_work);
734 mutex_lock(&wl->mutex);
735power_off:
736 wl1271_power_off(wl);
737 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200739 wl1271_error("firmware boot in PLT mode failed despite %d retries",
740 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741out:
742 mutex_unlock(&wl->mutex);
743
744 return ret;
745}
746
747int wl1271_plt_stop(struct wl1271 *wl)
748{
749 int ret = 0;
750
751 mutex_lock(&wl->mutex);
752
753 wl1271_notice("power down");
754
755 if (wl->state != WL1271_STATE_PLT) {
756 wl1271_error("cannot power down because not in PLT "
757 "state: %d", wl->state);
758 ret = -EBUSY;
759 goto out;
760 }
761
762 wl1271_disable_interrupts(wl);
763 wl1271_power_off(wl);
764
765 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300766 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768out:
769 mutex_unlock(&wl->mutex);
770
771 return ret;
772}
773
774
775static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
776{
777 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200778 struct ieee80211_conf *conf = &hw->conf;
779 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
780 struct ieee80211_sta *sta = txinfo->control.sta;
781 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200783 /* peek into the rates configured in the STA entry */
784 spin_lock_irqsave(&wl->wl_lock, flags);
785 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
786 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
787 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
788 }
789 spin_unlock_irqrestore(&wl->wl_lock, flags);
790
791 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792 skb_queue_tail(&wl->tx_queue, skb);
793
794 /*
795 * The chip specific setup must run before the first TX packet -
796 * before that, the tx_work will not be initialized!
797 */
798
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300799 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 /*
802 * The workqueue is slow to process the tx_queue and we need stop
803 * the queue here, otherwise the queue will get too long.
804 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200805 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
806 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200808 spin_lock_irqsave(&wl->wl_lock, flags);
809 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200810 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200811 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812 }
813
814 return NETDEV_TX_OK;
815}
816
817static int wl1271_op_start(struct ieee80211_hw *hw)
818{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200819 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
820
821 /*
822 * We have to delay the booting of the hardware because
823 * we need to know the local MAC address before downloading and
824 * initializing the firmware. The MAC address cannot be changed
825 * after boot, and without the proper MAC address, the firmware
826 * will not function properly.
827 *
828 * The MAC address is first known when the corresponding interface
829 * is added. That is where we will initialize the hardware.
830 */
831
832 return 0;
833}
834
835static void wl1271_op_stop(struct ieee80211_hw *hw)
836{
837 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
838}
839
840static int wl1271_op_add_interface(struct ieee80211_hw *hw,
841 struct ieee80211_vif *vif)
842{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200844 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845 int ret = 0;
846
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200847 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
848 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849
850 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200851 if (wl->vif) {
852 ret = -EBUSY;
853 goto out;
854 }
855
856 wl->vif = vif;
857
858 switch (vif->type) {
859 case NL80211_IFTYPE_STATION:
860 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200861 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200862 break;
863 case NL80211_IFTYPE_ADHOC:
864 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200865 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200866 break;
867 default:
868 ret = -EOPNOTSUPP;
869 goto out;
870 }
871
872 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873
874 if (wl->state != WL1271_STATE_OFF) {
875 wl1271_error("cannot start because not in off state: %d",
876 wl->state);
877 ret = -EBUSY;
878 goto out;
879 }
880
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200881 while (retries) {
882 retries--;
883 ret = wl1271_chip_wakeup(wl);
884 if (ret < 0)
885 goto power_off;
886
887 ret = wl1271_boot(wl);
888 if (ret < 0)
889 goto power_off;
890
891 ret = wl1271_hw_init(wl);
892 if (ret < 0)
893 goto irq_disable;
894
895 wl->state = WL1271_STATE_ON;
896 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 goto out;
898
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200899irq_disable:
900 wl1271_disable_interrupts(wl);
901 mutex_unlock(&wl->mutex);
902 /* Unlocking the mutex in the middle of handling is
903 inherently unsafe. In this case we deem it safe to do,
904 because we need to let any possibly pending IRQ out of
905 the system (and while we are WL1271_STATE_OFF the IRQ
906 work function will not do anything.) Also, any other
907 possible concurrent operations will fail due to the
908 current state, hence the wl1271 struct should be safe. */
909 cancel_work_sync(&wl->irq_work);
910 mutex_lock(&wl->mutex);
911power_off:
912 wl1271_power_off(wl);
913 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200915 wl1271_error("firmware boot failed despite %d retries",
916 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300917out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918 mutex_unlock(&wl->mutex);
919
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300920 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300921 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923 return ret;
924}
925
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200926static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
927 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928{
929 struct wl1271 *wl = hw->priv;
930 int i;
931
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200932 mutex_lock(&wl->mutex);
933 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200935 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300937 list_del(&wl->list);
938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 WARN_ON(wl->state != WL1271_STATE_ON);
940
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300941 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300942 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300943 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300944
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200945 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 mutex_unlock(&wl->mutex);
947 ieee80211_scan_completed(wl->hw, true);
948 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 }
950
951 wl->state = WL1271_STATE_OFF;
952
953 wl1271_disable_interrupts(wl);
954
955 mutex_unlock(&wl->mutex);
956
957 cancel_work_sync(&wl->irq_work);
958 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300959 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300960
961 mutex_lock(&wl->mutex);
962
963 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300964 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300965 wl1271_power_off(wl);
966
967 memset(wl->bssid, 0, ETH_ALEN);
968 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
969 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200971 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300972 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973
974 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200975 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
977 wl->tx_blocks_available = 0;
978 wl->tx_results_count = 0;
979 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300980 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200981 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982 wl->time_offset = 0;
983 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200984 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
985 wl->sta_rate_set = 0;
986 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200987 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200988 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 for (i = 0; i < NUM_TX_QUEUES; i++)
991 wl->tx_blocks_freed[i] = 0;
992
993 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300994
995 kfree(wl->fw_status);
996 wl->fw_status = NULL;
997 kfree(wl->tx_res_if);
998 wl->tx_res_if = NULL;
999 kfree(wl->target_mem_map);
1000 wl->target_mem_map = NULL;
1001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002 mutex_unlock(&wl->mutex);
1003}
1004
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001005static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1006{
1007 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1008 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1009
1010 /* combine requested filters with current filter config */
1011 filters = wl->filters | filters;
1012
1013 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1014
1015 if (filters & FIF_PROMISC_IN_BSS) {
1016 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1017 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1018 wl->rx_config |= CFG_BSSID_FILTER_EN;
1019 }
1020 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1021 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1022 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1023 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1024 }
1025 if (filters & FIF_OTHER_BSS) {
1026 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1027 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1028 }
1029 if (filters & FIF_CONTROL) {
1030 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1031 wl->rx_filter |= CFG_RX_CTL_EN;
1032 }
1033 if (filters & FIF_FCSFAIL) {
1034 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1035 wl->rx_filter |= CFG_RX_FCS_ERROR;
1036 }
1037}
1038
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001039static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001040{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001041 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001042 /* we need to use a dummy BSSID for now */
1043 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1044 0xad, 0xbe, 0xef };
1045
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001046 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1047
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001048 /* pass through frames from all BSS */
1049 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1050
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001051 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001052 if (ret < 0)
1053 goto out;
1054
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001055 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001056
1057out:
1058 return ret;
1059}
1060
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001061static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001062{
1063 int ret;
1064
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001065 /*
1066 * One of the side effects of the JOIN command is that is clears
1067 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1068 * to a WPA/WPA2 access point will therefore kill the data-path.
1069 * Currently there is no supported scenario for JOIN during
1070 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1071 * must be handled somehow.
1072 *
1073 */
1074 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1075 wl1271_info("JOIN while associated.");
1076
1077 if (set_assoc)
1078 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1079
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001080 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1081 if (ret < 0)
1082 goto out;
1083
1084 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1085
1086 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1087 goto out;
1088
1089 /*
1090 * The join command disable the keep-alive mode, shut down its process,
1091 * and also clear the template config, so we need to reset it all after
1092 * the join. The acx_aid starts the keep-alive process, and the order
1093 * of the commands below is relevant.
1094 */
1095 ret = wl1271_acx_keep_alive_mode(wl, true);
1096 if (ret < 0)
1097 goto out;
1098
1099 ret = wl1271_acx_aid(wl, wl->aid);
1100 if (ret < 0)
1101 goto out;
1102
1103 ret = wl1271_cmd_build_klv_null_data(wl);
1104 if (ret < 0)
1105 goto out;
1106
1107 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1108 ACX_KEEP_ALIVE_TPL_VALID);
1109 if (ret < 0)
1110 goto out;
1111
1112out:
1113 return ret;
1114}
1115
1116static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001117{
1118 int ret;
1119
1120 /* to stop listening to a channel, we disconnect */
1121 ret = wl1271_cmd_disconnect(wl);
1122 if (ret < 0)
1123 goto out;
1124
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001125 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001126 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001127
1128 /* stop filterting packets based on bssid */
1129 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001130
1131out:
1132 return ret;
1133}
1134
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001135static void wl1271_set_band_rate(struct wl1271 *wl)
1136{
1137 if (wl->band == IEEE80211_BAND_2GHZ)
1138 wl->basic_rate_set = wl->conf.tx.basic_rate;
1139 else
1140 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1141}
1142
1143static u32 wl1271_min_rate_get(struct wl1271 *wl)
1144{
1145 int i;
1146 u32 rate = 0;
1147
1148 if (!wl->basic_rate_set) {
1149 WARN_ON(1);
1150 wl->basic_rate_set = wl->conf.tx.basic_rate;
1151 }
1152
1153 for (i = 0; !rate; i++) {
1154 if ((wl->basic_rate_set >> i) & 0x1)
1155 rate = 1 << i;
1156 }
1157
1158 return rate;
1159}
1160
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001161static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1162{
1163 int ret;
1164
1165 if (idle) {
1166 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1167 ret = wl1271_unjoin(wl);
1168 if (ret < 0)
1169 goto out;
1170 }
1171 wl->rate_set = wl1271_min_rate_get(wl);
1172 wl->sta_rate_set = 0;
1173 ret = wl1271_acx_rate_policies(wl);
1174 if (ret < 0)
1175 goto out;
1176 ret = wl1271_acx_keep_alive_config(
1177 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1178 ACX_KEEP_ALIVE_TPL_INVALID);
1179 if (ret < 0)
1180 goto out;
1181 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1182 } else {
1183 /* increment the session counter */
1184 wl->session_counter++;
1185 if (wl->session_counter >= SESSION_COUNTER_MAX)
1186 wl->session_counter = 0;
1187 ret = wl1271_dummy_join(wl);
1188 if (ret < 0)
1189 goto out;
1190 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1191 }
1192
1193out:
1194 return ret;
1195}
1196
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001197static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1198{
1199 struct wl1271 *wl = hw->priv;
1200 struct ieee80211_conf *conf = &hw->conf;
1201 int channel, ret = 0;
1202
1203 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1204
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001205 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 channel,
1207 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 conf->power_level,
1209 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001211 /*
1212 * mac80211 will go to idle nearly immediately after transmitting some
1213 * frames, such as the deauth. To make sure those frames reach the air,
1214 * wait here until the TX queue is fully flushed.
1215 */
1216 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1217 (conf->flags & IEEE80211_CONF_IDLE))
1218 wl1271_tx_flush(wl);
1219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 mutex_lock(&wl->mutex);
1221
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001222 if (unlikely(wl->state == WL1271_STATE_OFF))
1223 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001224
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225 ret = wl1271_ps_elp_wakeup(wl, false);
1226 if (ret < 0)
1227 goto out;
1228
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001229 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001230 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1231 ((wl->band != conf->channel->band) ||
1232 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001233 wl->band = conf->channel->band;
1234 wl->channel = channel;
1235
1236 /*
1237 * FIXME: the mac80211 should really provide a fixed rate
1238 * to use here. for now, just use the smallest possible rate
1239 * for the band as a fixed rate for association frames and
1240 * other control messages.
1241 */
1242 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1243 wl1271_set_band_rate(wl);
1244
1245 wl->basic_rate = wl1271_min_rate_get(wl);
1246 ret = wl1271_acx_rate_policies(wl);
1247 if (ret < 0)
1248 wl1271_warning("rate policy for update channel "
1249 "failed %d", ret);
1250
1251 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001252 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001253 if (ret < 0)
1254 wl1271_warning("cmd join to update channel "
1255 "failed %d", ret);
1256 }
1257 }
1258
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001259 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001260 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1261 if (ret < 0)
1262 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 }
1264
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001265 /*
1266 * if mac80211 changes the PSM mode, make sure the mode is not
1267 * incorrectly changed after the pspoll failure active window.
1268 */
1269 if (changed & IEEE80211_CONF_CHANGE_PS)
1270 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1271
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001272 if (conf->flags & IEEE80211_CONF_PS &&
1273 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1274 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275
1276 /*
1277 * We enter PSM only if we're already associated.
1278 * If we're not, we'll enter it when joining an SSID,
1279 * through the bss_info_changed() hook.
1280 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001281 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001282 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001283 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1284 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001285 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001287 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001288 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001290 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001292 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001293 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1294 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295 }
1296
1297 if (conf->power_level != wl->power_level) {
1298 ret = wl1271_acx_tx_power(wl, conf->power_level);
1299 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001300 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
1302 wl->power_level = conf->power_level;
1303 }
1304
1305out_sleep:
1306 wl1271_ps_elp_sleep(wl);
1307
1308out:
1309 mutex_unlock(&wl->mutex);
1310
1311 return ret;
1312}
1313
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001314struct wl1271_filter_params {
1315 bool enabled;
1316 int mc_list_length;
1317 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1318};
1319
Jiri Pirko22bedad32010-04-01 21:22:57 +00001320static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1321 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001322{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001323 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001324 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001325 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001327 if (unlikely(wl->state == WL1271_STATE_OFF))
1328 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329
Juuso Oikarinen74441132009-10-13 12:47:53 +03001330 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001331 if (!fp) {
1332 wl1271_error("Out of memory setting filters.");
1333 return 0;
1334 }
1335
1336 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001337 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001338 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1339 fp->enabled = false;
1340 } else {
1341 fp->enabled = true;
1342 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001343 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001344 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001345 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001346 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001347 }
1348
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001349 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001350}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1353 FIF_ALLMULTI | \
1354 FIF_FCSFAIL | \
1355 FIF_BCN_PRBRESP_PROMISC | \
1356 FIF_CONTROL | \
1357 FIF_OTHER_BSS)
1358
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1360 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001361 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001366
1367 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1368
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001369 mutex_lock(&wl->mutex);
1370
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001371 *total &= WL1271_SUPPORTED_FILTERS;
1372 changed &= WL1271_SUPPORTED_FILTERS;
1373
1374 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001375 goto out;
1376
1377 ret = wl1271_ps_elp_wakeup(wl, false);
1378 if (ret < 0)
1379 goto out;
1380
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001381
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001382 if (*total & FIF_ALLMULTI)
1383 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1384 else if (fp)
1385 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1386 fp->mc_list,
1387 fp->mc_list_length);
1388 if (ret < 0)
1389 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001391 /* determine, whether supported filter values have changed */
1392 if (changed == 0)
1393 goto out_sleep;
1394
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001395 /* configure filters */
1396 wl->filters = *total;
1397 wl1271_configure_filters(wl, 0);
1398
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001399 /* apply configured filters */
1400 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1401 if (ret < 0)
1402 goto out_sleep;
1403
1404out_sleep:
1405 wl1271_ps_elp_sleep(wl);
1406
1407out:
1408 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001409 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410}
1411
1412static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1413 struct ieee80211_vif *vif,
1414 struct ieee80211_sta *sta,
1415 struct ieee80211_key_conf *key_conf)
1416{
1417 struct wl1271 *wl = hw->priv;
1418 const u8 *addr;
1419 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001420 u32 tx_seq_32 = 0;
1421 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422 u8 key_type;
1423
1424 static const u8 bcast_addr[ETH_ALEN] =
1425 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1426
1427 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1428
1429 addr = sta ? sta->addr : bcast_addr;
1430
1431 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1432 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1433 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1434 key_conf->alg, key_conf->keyidx,
1435 key_conf->keylen, key_conf->flags);
1436 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1437
1438 if (is_zero_ether_addr(addr)) {
1439 /* We dont support TX only encryption */
1440 ret = -EOPNOTSUPP;
1441 goto out;
1442 }
1443
1444 mutex_lock(&wl->mutex);
1445
1446 ret = wl1271_ps_elp_wakeup(wl, false);
1447 if (ret < 0)
1448 goto out_unlock;
1449
1450 switch (key_conf->alg) {
1451 case ALG_WEP:
1452 key_type = KEY_WEP;
1453
1454 key_conf->hw_key_idx = key_conf->keyidx;
1455 break;
1456 case ALG_TKIP:
1457 key_type = KEY_TKIP;
1458
1459 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001460 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1461 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 break;
1463 case ALG_CCMP:
1464 key_type = KEY_AES;
1465
1466 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001467 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1468 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469 break;
1470 default:
1471 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1472
1473 ret = -EOPNOTSUPP;
1474 goto out_sleep;
1475 }
1476
1477 switch (cmd) {
1478 case SET_KEY:
1479 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1480 key_conf->keyidx, key_type,
1481 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001482 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 if (ret < 0) {
1484 wl1271_error("Could not add or replace key");
1485 goto out_sleep;
1486 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001487
1488 /* the default WEP key needs to be configured at least once */
1489 if (key_type == KEY_WEP) {
1490 ret = wl1271_cmd_set_default_wep_key(wl,
1491 wl->default_key);
1492 if (ret < 0)
1493 goto out_sleep;
1494 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 break;
1496
1497 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001498 /* The wl1271 does not allow to remove unicast keys - they
1499 will be cleared automatically on next CMD_JOIN. Ignore the
1500 request silently, as we dont want the mac80211 to emit
1501 an error message. */
1502 if (!is_broadcast_ether_addr(addr))
1503 break;
1504
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1506 key_conf->keyidx, key_type,
1507 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001508 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 if (ret < 0) {
1510 wl1271_error("Could not remove key");
1511 goto out_sleep;
1512 }
1513 break;
1514
1515 default:
1516 wl1271_error("Unsupported key cmd 0x%x", cmd);
1517 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 break;
1519 }
1520
1521out_sleep:
1522 wl1271_ps_elp_sleep(wl);
1523
1524out_unlock:
1525 mutex_unlock(&wl->mutex);
1526
1527out:
1528 return ret;
1529}
1530
1531static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001532 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533 struct cfg80211_scan_request *req)
1534{
1535 struct wl1271 *wl = hw->priv;
1536 int ret;
1537 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001538 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539
1540 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1541
1542 if (req->n_ssids) {
1543 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001544 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545 }
1546
1547 mutex_lock(&wl->mutex);
1548
1549 ret = wl1271_ps_elp_wakeup(wl, false);
1550 if (ret < 0)
1551 goto out;
1552
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001553 if (wl1271_11a_enabled())
Luciano Coelho34dd2aa2010-07-08 17:50:06 +03001554 ret = wl1271_scan(hw->priv, ssid, len, req,
1555 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001556 else
Luciano Coelho34dd2aa2010-07-08 17:50:06 +03001557 ret = wl1271_scan(hw->priv, ssid, len, req,
1558 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559
1560 wl1271_ps_elp_sleep(wl);
1561
1562out:
1563 mutex_unlock(&wl->mutex);
1564
1565 return ret;
1566}
1567
1568static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1569{
1570 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001571 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001572
1573 mutex_lock(&wl->mutex);
1574
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001575 if (unlikely(wl->state == WL1271_STATE_OFF))
1576 goto out;
1577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 ret = wl1271_ps_elp_wakeup(wl, false);
1579 if (ret < 0)
1580 goto out;
1581
1582 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1583 if (ret < 0)
1584 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1585
1586 wl1271_ps_elp_sleep(wl);
1587
1588out:
1589 mutex_unlock(&wl->mutex);
1590
1591 return ret;
1592}
1593
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001594static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1595{
1596 u8 *ptr = beacon->data +
1597 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1598
1599 /* find the location of the ssid in the beacon */
1600 while (ptr < beacon->data + beacon->len) {
1601 if (ptr[0] == WLAN_EID_SSID) {
1602 wl->ssid_len = ptr[1];
1603 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1604 return;
1605 }
1606 ptr += ptr[1];
1607 }
1608 wl1271_error("ad-hoc beacon template has no SSID!\n");
1609}
1610
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1612 struct ieee80211_vif *vif,
1613 struct ieee80211_bss_conf *bss_conf,
1614 u32 changed)
1615{
1616 enum wl1271_cmd_ps_mode mode;
1617 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001618 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001619 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620 int ret;
1621
1622 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1623
1624 mutex_lock(&wl->mutex);
1625
1626 ret = wl1271_ps_elp_wakeup(wl, false);
1627 if (ret < 0)
1628 goto out;
1629
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001630 if ((changed && BSS_CHANGED_BEACON_INT) &&
1631 (wl->bss_type == BSS_TYPE_IBSS)) {
1632 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1633 bss_conf->beacon_int);
1634
1635 wl->beacon_int = bss_conf->beacon_int;
1636 do_join = true;
1637 }
1638
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001639 if ((changed && BSS_CHANGED_BEACON) &&
1640 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001641 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1642
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001643 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1644
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001645 if (beacon) {
1646 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001647
1648 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001649 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1650 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001651 beacon->len, 0,
1652 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001653
1654 if (ret < 0) {
1655 dev_kfree_skb(beacon);
1656 goto out_sleep;
1657 }
1658
1659 hdr = (struct ieee80211_hdr *) beacon->data;
1660 hdr->frame_control = cpu_to_le16(
1661 IEEE80211_FTYPE_MGMT |
1662 IEEE80211_STYPE_PROBE_RESP);
1663
1664 ret = wl1271_cmd_template_set(wl,
1665 CMD_TEMPL_PROBE_RESPONSE,
1666 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001667 beacon->len, 0,
1668 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001669 dev_kfree_skb(beacon);
1670 if (ret < 0)
1671 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001672
1673 /* Need to update the SSID (for filtering etc) */
1674 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001675 }
1676 }
1677
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001678 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1679 (wl->bss_type == BSS_TYPE_IBSS)) {
1680 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1681 bss_conf->enable_beacon ? "enabled" : "disabled");
1682
1683 if (bss_conf->enable_beacon)
1684 wl->set_bss_type = BSS_TYPE_IBSS;
1685 else
1686 wl->set_bss_type = BSS_TYPE_STA_BSS;
1687 do_join = true;
1688 }
1689
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001690 if (changed & BSS_CHANGED_CQM) {
1691 bool enable = false;
1692 if (bss_conf->cqm_rssi_thold)
1693 enable = true;
1694 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1695 bss_conf->cqm_rssi_thold,
1696 bss_conf->cqm_rssi_hyst);
1697 if (ret < 0)
1698 goto out;
1699 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1700 }
1701
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001702 if ((changed & BSS_CHANGED_BSSID) &&
1703 /*
1704 * Now we know the correct bssid, so we send a new join command
1705 * and enable the BSSID filter
1706 */
1707 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001708 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001709
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001710 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001711 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001712 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001713
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001714 ret = wl1271_build_qos_null_data(wl);
1715 if (ret < 0)
1716 goto out_sleep;
1717
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001718 /* filter out all packets not from this BSSID */
1719 wl1271_configure_filters(wl, 0);
1720
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001721 /* Need to update the BSSID (for filtering etc) */
1722 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001723 }
1724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725 if (changed & BSS_CHANGED_ASSOC) {
1726 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001727 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001728 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001729 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001730
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001731 wl->ps_poll_failures = 0;
1732
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001733 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001734 * use basic rates from AP, and determine lowest rate
1735 * to use with control frames.
1736 */
1737 rates = bss_conf->basic_rates;
1738 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1739 rates);
1740 wl->basic_rate = wl1271_min_rate_get(wl);
1741 ret = wl1271_acx_rate_policies(wl);
1742 if (ret < 0)
1743 goto out_sleep;
1744
1745 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001746 * with wl1271, we don't need to update the
1747 * beacon_int and dtim_period, because the firmware
1748 * updates it by itself when the first beacon is
1749 * received after a join.
1750 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1752 if (ret < 0)
1753 goto out_sleep;
1754
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001755 /*
1756 * The SSID is intentionally set to NULL here - the
1757 * firmware will set the probe request with a
1758 * broadcast SSID regardless of what we set in the
1759 * template.
1760 */
1761 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1762 NULL, 0, wl->band);
1763
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001764 /* enable the connection monitoring feature */
1765 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766 if (ret < 0)
1767 goto out_sleep;
1768
1769 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001770 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1771 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001773 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 if (ret < 0)
1775 goto out_sleep;
1776 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001777 } else {
1778 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001779 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001780 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001781
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001782 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001783 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001784
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001785 /* revert back to minimum rates for the current band */
1786 wl1271_set_band_rate(wl);
1787 wl->basic_rate = wl1271_min_rate_get(wl);
1788 ret = wl1271_acx_rate_policies(wl);
1789 if (ret < 0)
1790 goto out_sleep;
1791
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001792 /* disable connection monitor features */
1793 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001794
1795 /* Disable the keep-alive feature */
1796 ret = wl1271_acx_keep_alive_mode(wl, false);
1797
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001798 if (ret < 0)
1799 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001803
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804 if (changed & BSS_CHANGED_ERP_SLOT) {
1805 if (bss_conf->use_short_slot)
1806 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1807 else
1808 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1809 if (ret < 0) {
1810 wl1271_warning("Set slot time failed %d", ret);
1811 goto out_sleep;
1812 }
1813 }
1814
1815 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1816 if (bss_conf->use_short_preamble)
1817 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1818 else
1819 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1820 }
1821
1822 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1823 if (bss_conf->use_cts_prot)
1824 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1825 else
1826 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1827 if (ret < 0) {
1828 wl1271_warning("Set ctsprotect failed %d", ret);
1829 goto out_sleep;
1830 }
1831 }
1832
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001833 if (changed & BSS_CHANGED_ARP_FILTER) {
1834 __be32 addr = bss_conf->arp_addr_list[0];
1835 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1836
1837 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1838 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1839 else
1840 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1841
1842 if (ret < 0)
1843 goto out_sleep;
1844 }
1845
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001846 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001847 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001848 if (ret < 0) {
1849 wl1271_warning("cmd join failed %d", ret);
1850 goto out_sleep;
1851 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001852 }
1853
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001854out_sleep:
1855 wl1271_ps_elp_sleep(wl);
1856
1857out:
1858 mutex_unlock(&wl->mutex);
1859}
1860
Kalle Valoc6999d82010-02-18 13:25:41 +02001861static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1862 const struct ieee80211_tx_queue_params *params)
1863{
1864 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001865 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001866 int ret;
1867
1868 mutex_lock(&wl->mutex);
1869
1870 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1871
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001872 ret = wl1271_ps_elp_wakeup(wl, false);
1873 if (ret < 0)
1874 goto out;
1875
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001876 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001877 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1878 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001879 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001880 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001881 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001882
Kalle Valo4695dc92010-03-18 12:26:38 +02001883 if (params->uapsd)
1884 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1885 else
1886 ps_scheme = CONF_PS_SCHEME_LEGACY;
1887
Kalle Valoc6999d82010-02-18 13:25:41 +02001888 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1889 CONF_CHANNEL_TYPE_EDCF,
1890 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001891 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001892 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001893 goto out_sleep;
1894
1895out_sleep:
1896 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001897
1898out:
1899 mutex_unlock(&wl->mutex);
1900
1901 return ret;
1902}
1903
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001904static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1905{
1906
1907 struct wl1271 *wl = hw->priv;
1908 u64 mactime = ULLONG_MAX;
1909 int ret;
1910
1911 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1912
1913 mutex_lock(&wl->mutex);
1914
1915 ret = wl1271_ps_elp_wakeup(wl, false);
1916 if (ret < 0)
1917 goto out;
1918
1919 ret = wl1271_acx_tsf_info(wl, &mactime);
1920 if (ret < 0)
1921 goto out_sleep;
1922
1923out_sleep:
1924 wl1271_ps_elp_sleep(wl);
1925
1926out:
1927 mutex_unlock(&wl->mutex);
1928 return mactime;
1929}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930
1931/* can't be const, mac80211 writes to this */
1932static struct ieee80211_rate wl1271_rates[] = {
1933 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001934 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1935 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001937 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1938 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1940 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001941 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1942 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001943 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1944 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001945 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1946 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1948 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001949 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1950 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001952 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1953 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001955 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1956 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001958 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1959 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001961 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1962 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001964 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1965 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001967 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1968 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001970 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1971 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972};
1973
1974/* can't be const, mac80211 writes to this */
1975static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001976 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1977 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1978 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1979 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1980 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1981 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1982 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1983 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1984 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1985 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1986 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1987 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1988 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989};
1990
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001991/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02001992static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001993 /* MCS rates are used only with 11n */
1994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2000 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2001 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2002
2003 11, /* CONF_HW_RXTX_RATE_54 */
2004 10, /* CONF_HW_RXTX_RATE_48 */
2005 9, /* CONF_HW_RXTX_RATE_36 */
2006 8, /* CONF_HW_RXTX_RATE_24 */
2007
2008 /* TI-specific rate */
2009 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2010
2011 7, /* CONF_HW_RXTX_RATE_18 */
2012 6, /* CONF_HW_RXTX_RATE_12 */
2013 3, /* CONF_HW_RXTX_RATE_11 */
2014 5, /* CONF_HW_RXTX_RATE_9 */
2015 4, /* CONF_HW_RXTX_RATE_6 */
2016 2, /* CONF_HW_RXTX_RATE_5_5 */
2017 1, /* CONF_HW_RXTX_RATE_2 */
2018 0 /* CONF_HW_RXTX_RATE_1 */
2019};
2020
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021/* can't be const, mac80211 writes to this */
2022static struct ieee80211_supported_band wl1271_band_2ghz = {
2023 .channels = wl1271_channels,
2024 .n_channels = ARRAY_SIZE(wl1271_channels),
2025 .bitrates = wl1271_rates,
2026 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2027};
2028
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002029/* 5 GHz data rates for WL1273 */
2030static struct ieee80211_rate wl1271_rates_5ghz[] = {
2031 { .bitrate = 60,
2032 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2033 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2034 { .bitrate = 90,
2035 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2036 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2037 { .bitrate = 120,
2038 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2039 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2040 { .bitrate = 180,
2041 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2042 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2043 { .bitrate = 240,
2044 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2045 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2046 { .bitrate = 360,
2047 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2048 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2049 { .bitrate = 480,
2050 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2051 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2052 { .bitrate = 540,
2053 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2054 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2055};
2056
2057/* 5 GHz band channels for WL1273 */
2058static struct ieee80211_channel wl1271_channels_5ghz[] = {
2059 { .hw_value = 183, .center_freq = 4915},
2060 { .hw_value = 184, .center_freq = 4920},
2061 { .hw_value = 185, .center_freq = 4925},
2062 { .hw_value = 187, .center_freq = 4935},
2063 { .hw_value = 188, .center_freq = 4940},
2064 { .hw_value = 189, .center_freq = 4945},
2065 { .hw_value = 192, .center_freq = 4960},
2066 { .hw_value = 196, .center_freq = 4980},
2067 { .hw_value = 7, .center_freq = 5035},
2068 { .hw_value = 8, .center_freq = 5040},
2069 { .hw_value = 9, .center_freq = 5045},
2070 { .hw_value = 11, .center_freq = 5055},
2071 { .hw_value = 12, .center_freq = 5060},
2072 { .hw_value = 16, .center_freq = 5080},
2073 { .hw_value = 34, .center_freq = 5170},
2074 { .hw_value = 36, .center_freq = 5180},
2075 { .hw_value = 38, .center_freq = 5190},
2076 { .hw_value = 40, .center_freq = 5200},
2077 { .hw_value = 42, .center_freq = 5210},
2078 { .hw_value = 44, .center_freq = 5220},
2079 { .hw_value = 46, .center_freq = 5230},
2080 { .hw_value = 48, .center_freq = 5240},
2081 { .hw_value = 52, .center_freq = 5260},
2082 { .hw_value = 56, .center_freq = 5280},
2083 { .hw_value = 60, .center_freq = 5300},
2084 { .hw_value = 64, .center_freq = 5320},
2085 { .hw_value = 100, .center_freq = 5500},
2086 { .hw_value = 104, .center_freq = 5520},
2087 { .hw_value = 108, .center_freq = 5540},
2088 { .hw_value = 112, .center_freq = 5560},
2089 { .hw_value = 116, .center_freq = 5580},
2090 { .hw_value = 120, .center_freq = 5600},
2091 { .hw_value = 124, .center_freq = 5620},
2092 { .hw_value = 128, .center_freq = 5640},
2093 { .hw_value = 132, .center_freq = 5660},
2094 { .hw_value = 136, .center_freq = 5680},
2095 { .hw_value = 140, .center_freq = 5700},
2096 { .hw_value = 149, .center_freq = 5745},
2097 { .hw_value = 153, .center_freq = 5765},
2098 { .hw_value = 157, .center_freq = 5785},
2099 { .hw_value = 161, .center_freq = 5805},
2100 { .hw_value = 165, .center_freq = 5825},
2101};
2102
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002103/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002104static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002105 /* MCS rates are used only with 11n */
2106 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2107 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2112 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2114
2115 7, /* CONF_HW_RXTX_RATE_54 */
2116 6, /* CONF_HW_RXTX_RATE_48 */
2117 5, /* CONF_HW_RXTX_RATE_36 */
2118 4, /* CONF_HW_RXTX_RATE_24 */
2119
2120 /* TI-specific rate */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2122
2123 3, /* CONF_HW_RXTX_RATE_18 */
2124 2, /* CONF_HW_RXTX_RATE_12 */
2125 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2126 1, /* CONF_HW_RXTX_RATE_9 */
2127 0, /* CONF_HW_RXTX_RATE_6 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2129 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2130 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2131};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002132
2133static struct ieee80211_supported_band wl1271_band_5ghz = {
2134 .channels = wl1271_channels_5ghz,
2135 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2136 .bitrates = wl1271_rates_5ghz,
2137 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2138};
2139
Tobias Klausera0ea9492010-05-20 10:38:11 +02002140static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002141 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2142 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2143};
2144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145static const struct ieee80211_ops wl1271_ops = {
2146 .start = wl1271_op_start,
2147 .stop = wl1271_op_stop,
2148 .add_interface = wl1271_op_add_interface,
2149 .remove_interface = wl1271_op_remove_interface,
2150 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002151 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002152 .configure_filter = wl1271_op_configure_filter,
2153 .tx = wl1271_op_tx,
2154 .set_key = wl1271_op_set_key,
2155 .hw_scan = wl1271_op_hw_scan,
2156 .bss_info_changed = wl1271_op_bss_info_changed,
2157 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002158 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002159 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002160 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161};
2162
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002163
2164u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2165{
2166 u8 idx;
2167
2168 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2169
2170 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2171 wl1271_error("Illegal RX rate from HW: %d", rate);
2172 return 0;
2173 }
2174
2175 idx = wl1271_band_rate_to_idx[wl->band][rate];
2176 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2177 wl1271_error("Unsupported RX rate from HW: %d", rate);
2178 return 0;
2179 }
2180
2181 return idx;
2182}
2183
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002184static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2185 struct device_attribute *attr,
2186 char *buf)
2187{
2188 struct wl1271 *wl = dev_get_drvdata(dev);
2189 ssize_t len;
2190
2191 /* FIXME: what's the maximum length of buf? page size?*/
2192 len = 500;
2193
2194 mutex_lock(&wl->mutex);
2195 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2196 wl->sg_enabled);
2197 mutex_unlock(&wl->mutex);
2198
2199 return len;
2200
2201}
2202
2203static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2204 struct device_attribute *attr,
2205 const char *buf, size_t count)
2206{
2207 struct wl1271 *wl = dev_get_drvdata(dev);
2208 unsigned long res;
2209 int ret;
2210
2211 ret = strict_strtoul(buf, 10, &res);
2212
2213 if (ret < 0) {
2214 wl1271_warning("incorrect value written to bt_coex_mode");
2215 return count;
2216 }
2217
2218 mutex_lock(&wl->mutex);
2219
2220 res = !!res;
2221
2222 if (res == wl->sg_enabled)
2223 goto out;
2224
2225 wl->sg_enabled = res;
2226
2227 if (wl->state == WL1271_STATE_OFF)
2228 goto out;
2229
2230 ret = wl1271_ps_elp_wakeup(wl, false);
2231 if (ret < 0)
2232 goto out;
2233
2234 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2235 wl1271_ps_elp_sleep(wl);
2236
2237 out:
2238 mutex_unlock(&wl->mutex);
2239 return count;
2240}
2241
2242static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2243 wl1271_sysfs_show_bt_coex_state,
2244 wl1271_sysfs_store_bt_coex_state);
2245
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002246static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2247 struct device_attribute *attr,
2248 char *buf)
2249{
2250 struct wl1271 *wl = dev_get_drvdata(dev);
2251 ssize_t len;
2252
2253 /* FIXME: what's the maximum length of buf? page size?*/
2254 len = 500;
2255
2256 mutex_lock(&wl->mutex);
2257 if (wl->hw_pg_ver >= 0)
2258 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2259 else
2260 len = snprintf(buf, len, "n/a\n");
2261 mutex_unlock(&wl->mutex);
2262
2263 return len;
2264}
2265
2266static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2267 wl1271_sysfs_show_hw_pg_ver, NULL);
2268
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002269int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270{
2271 int ret;
2272
2273 if (wl->mac80211_registered)
2274 return 0;
2275
2276 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2277
2278 ret = ieee80211_register_hw(wl->hw);
2279 if (ret < 0) {
2280 wl1271_error("unable to register mac80211 hw: %d", ret);
2281 return ret;
2282 }
2283
2284 wl->mac80211_registered = true;
2285
2286 wl1271_notice("loaded");
2287
2288 return 0;
2289}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002290EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002292void wl1271_unregister_hw(struct wl1271 *wl)
2293{
2294 ieee80211_unregister_hw(wl->hw);
2295 wl->mac80211_registered = false;
2296
2297}
2298EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2299
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002300int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002302 /* The tx descriptor buffer and the TKIP space. */
2303 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2304 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305
2306 /* unit us */
2307 /* FIXME: find a proper value */
2308 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002309 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002310
2311 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002312 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002313 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002314 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002315 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002316 IEEE80211_HW_CONNECTION_MONITOR |
2317 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002319 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2320 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002321 wl->hw->wiphy->max_scan_ssids = 1;
2322 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2323
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002324 if (wl1271_11a_enabled())
2325 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2326
Kalle Valo12bd8942010-03-18 12:26:33 +02002327 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002328 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002329
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002330 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331
2332 return 0;
2333}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002334EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002337
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002338struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002339{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002341 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002343 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002344
2345 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2346 if (!hw) {
2347 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002348 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002349 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350 }
2351
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002352 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2353 if (!plat_dev) {
2354 wl1271_error("could not allocate platform_device");
2355 ret = -ENOMEM;
2356 goto err_plat_alloc;
2357 }
2358
2359 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 wl = hw->priv;
2362 memset(wl, 0, sizeof(*wl));
2363
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002364 INIT_LIST_HEAD(&wl->list);
2365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002367 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368
2369 skb_queue_head_init(&wl->tx_queue);
2370
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002371 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002372 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002374 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 wl->rx_counter = 0;
2377 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2378 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002379 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002381 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002382 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002383 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2384 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002385 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002386 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002387 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002388 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002389 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002391 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002392 wl->tx_frames[i] = NULL;
2393
2394 spin_lock_init(&wl->wl_lock);
2395
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396 wl->state = WL1271_STATE_OFF;
2397 mutex_init(&wl->mutex);
2398
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002399 /* Apply default driver configuration. */
2400 wl1271_conf_init(wl);
2401
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002402 wl1271_debugfs_init(wl);
2403
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002404 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002405 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002406 if (ret) {
2407 wl1271_error("couldn't register platform device");
2408 goto err_hw;
2409 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002410 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002411
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002412 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002413 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002414 if (ret < 0) {
2415 wl1271_error("failed to create sysfs file bt_coex_state");
2416 goto err_platform;
2417 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002418
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002419 /* Create sysfs file to get HW PG version */
2420 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2421 if (ret < 0) {
2422 wl1271_error("failed to create sysfs file hw_pg_ver");
2423 goto err_bt_coex_state;
2424 }
2425
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002426 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002427
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002428err_bt_coex_state:
2429 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2430
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002431err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002432 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002433
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002434err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002435 wl1271_debugfs_exit(wl);
2436 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002437
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002438err_plat_alloc:
2439 ieee80211_free_hw(hw);
2440
2441err_hw_alloc:
2442
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002443 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002444}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002445EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002446
2447int wl1271_free_hw(struct wl1271 *wl)
2448{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002449 platform_device_unregister(wl->plat_dev);
2450 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002451
2452 wl1271_debugfs_exit(wl);
2453
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002454 vfree(wl->fw);
2455 wl->fw = NULL;
2456 kfree(wl->nvs);
2457 wl->nvs = NULL;
2458
2459 kfree(wl->fw_status);
2460 kfree(wl->tx_res_if);
2461
2462 ieee80211_free_hw(wl->hw);
2463
2464 return 0;
2465}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002466EXPORT_SYMBOL_GPL(wl1271_free_hw);
2467
2468MODULE_LICENSE("GPL");
2469MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2470MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");