blob: a37244c88fee7275292e21fa44df7741645ee267 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030047
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020048#define WL1271_BOOT_RETRIES 3
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020052 .params = {
53 [CONF_SG_BT_PER_THRESHOLD] = 7500,
54 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
55 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
56 [CONF_SG_BT_LOAD_RATIO] = 50,
57 [CONF_SG_AUTO_PS_MODE] = 0,
58 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
59 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
60 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
61 [CONF_SG_BEACON_MISS_PERCENT] = 60,
62 [CONF_SG_RATE_ADAPT_THRESH] = 12,
63 [CONF_SG_RATE_ADAPT_SNR] = 0,
64 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
66 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
67 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
69 /* Note: with UPSD, this should be 4 */
70 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
71 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
74 /* Note: with UPDS, this should be 15 */
75 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
76 /* Note: with UPDS, this should be 50 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
78 /* Note: with UPDS, this should be 10 */
79 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
80 [CONF_SG_RXT] = 1200,
81 [CONF_SG_TXT] = 1000,
82 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
83 [CONF_SG_PS_POLL_TIMEOUT] = 10,
84 [CONF_SG_UPSD_TIMEOUT] = 10,
85 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
87 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
94 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
96 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
97 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
98 [CONF_SG_HV3_MAX_SERVED] = 6,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
101 },
102 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300103 },
104 .rx = {
105 .rx_msdu_life_time = 512000,
106 .packet_detection_threshold = 0,
107 .ps_poll_timeout = 15,
108 .upsd_timeout = 15,
109 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200110 .rx_cca_threshold = 0,
111 .irq_blk_threshold = 0xFFFF,
112 .irq_pkt_threshold = 0,
113 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300114 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
115 },
116 .tx = {
117 .tx_energy_detection = 0,
118 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300119 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 .short_retry_limit = 10,
121 .long_retry_limit = 10,
122 .aflags = 0
123 },
124 .ac_conf_count = 4,
125 .ac_conf = {
126 [0] = {
127 .ac = CONF_TX_AC_BE,
128 .cw_min = 15,
129 .cw_max = 63,
130 .aifsn = 3,
131 .tx_op_limit = 0,
132 },
133 [1] = {
134 .ac = CONF_TX_AC_BK,
135 .cw_min = 15,
136 .cw_max = 63,
137 .aifsn = 7,
138 .tx_op_limit = 0,
139 },
140 [2] = {
141 .ac = CONF_TX_AC_VI,
142 .cw_min = 15,
143 .cw_max = 63,
144 .aifsn = CONF_TX_AIFS_PIFS,
145 .tx_op_limit = 3008,
146 },
147 [3] = {
148 .ac = CONF_TX_AC_VO,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = CONF_TX_AIFS_PIFS,
152 .tx_op_limit = 1504,
153 },
154 },
155 .tid_conf_count = 7,
156 .tid_conf = {
157 [0] = {
158 .queue_id = 0,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [1] = {
166 .queue_id = 1,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 },
173 [2] = {
174 .queue_id = 2,
175 .channel_type = CONF_CHANNEL_TYPE_DCF,
176 .tsid = CONF_TX_AC_BE,
177 .ps_scheme = CONF_PS_SCHEME_LEGACY,
178 .ack_policy = CONF_ACK_POLICY_LEGACY,
179 .apsd_conf = {0, 0},
180 },
181 [3] = {
182 .queue_id = 3,
183 .channel_type = CONF_CHANNEL_TYPE_DCF,
184 .tsid = CONF_TX_AC_BE,
185 .ps_scheme = CONF_PS_SCHEME_LEGACY,
186 .ack_policy = CONF_ACK_POLICY_LEGACY,
187 .apsd_conf = {0, 0},
188 },
189 [4] = {
190 .queue_id = 4,
191 .channel_type = CONF_CHANNEL_TYPE_DCF,
192 .tsid = CONF_TX_AC_BE,
193 .ps_scheme = CONF_PS_SCHEME_LEGACY,
194 .ack_policy = CONF_ACK_POLICY_LEGACY,
195 .apsd_conf = {0, 0},
196 },
197 [5] = {
198 .queue_id = 5,
199 .channel_type = CONF_CHANNEL_TYPE_DCF,
200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
205 [6] = {
206 .queue_id = 6,
207 .channel_type = CONF_CHANNEL_TYPE_DCF,
208 .tsid = CONF_TX_AC_BE,
209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 }
213 },
214 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200215 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300216 .tx_compl_threshold = 4,
217 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
218 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 },
220 .conn = {
221 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300222 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300223 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
224 .bcn_filt_ie_count = 1,
225 .bcn_filt_ie = {
226 [0] = {
227 .ie = WLAN_EID_CHANNEL_SWITCH,
228 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
229 }
230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200236 .ps_poll_threshold = 20,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200238 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200239 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .keep_alive_interval = 55000,
241 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300242 },
243 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200245 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 },
248 .itrim = {
249 .enable = false,
250 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200251 },
252 .pm_config = {
253 .host_clk_settling_time = 5000,
254 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 },
256 .roam_trigger = {
257 /* FIXME: due to firmware bug, must use value 1 for now */
258 .trigger_pacing = 1,
259 .avg_weight_rssi_beacon = 20,
260 .avg_weight_rssi_data = 10,
261 .avg_weight_snr_beacon = 20,
262 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 }
264};
265
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200266static void wl1271_device_release(struct device *dev)
267{
268
269}
270
271static struct platform_device wl1271_device = {
272 .name = "wl1271",
273 .id = -1,
274
275 /* device model insists to have a release function */
276 .dev = {
277 .release = wl1271_device_release,
278 },
279};
280
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300281static LIST_HEAD(wl_list);
282
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300283static void wl1271_conf_init(struct wl1271 *wl)
284{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300285
286 /*
287 * This function applies the default configuration to the driver. This
288 * function is invoked upon driver load (spi probe.)
289 *
290 * The configuration is stored in a run-time structure in order to
291 * facilitate for run-time adjustment of any of the parameters. Making
292 * changes to the configuration structure will apply the new values on
293 * the next interface up (wl1271_op_start.)
294 */
295
296 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300297 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300298}
299
300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300301static int wl1271_plt_init(struct wl1271 *wl)
302{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200303 struct conf_tx_ac_category *conf_ac;
304 struct conf_tx_tid *conf_tid;
305 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300306
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200307 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200308 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200309 return ret;
310
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200311 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200312 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200313 return ret;
314
Luciano Coelho12419cc2010-02-18 13:25:44 +0200315 ret = wl1271_init_templates_config(wl);
316 if (ret < 0)
317 return ret;
318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300319 ret = wl1271_acx_init_mem_config(wl);
320 if (ret < 0)
321 return ret;
322
Luciano Coelho12419cc2010-02-18 13:25:44 +0200323 /* PHY layer config */
324 ret = wl1271_init_phy_config(wl);
325 if (ret < 0)
326 goto out_free_memmap;
327
328 ret = wl1271_acx_dco_itrim_params(wl);
329 if (ret < 0)
330 goto out_free_memmap;
331
332 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200333 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200334 if (ret < 0)
335 goto out_free_memmap;
336
337 /* Bluetooth WLAN coexistence */
338 ret = wl1271_init_pta(wl);
339 if (ret < 0)
340 goto out_free_memmap;
341
342 /* Energy detection */
343 ret = wl1271_init_energy_detection(wl);
344 if (ret < 0)
345 goto out_free_memmap;
346
347 /* Default fragmentation threshold */
348 ret = wl1271_acx_frag_threshold(wl);
349 if (ret < 0)
350 goto out_free_memmap;
351
352 /* Default TID configuration */
353 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
354 conf_tid = &wl->conf.tx.tid_conf[i];
355 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
356 conf_tid->channel_type,
357 conf_tid->tsid,
358 conf_tid->ps_scheme,
359 conf_tid->ack_policy,
360 conf_tid->apsd_conf[0],
361 conf_tid->apsd_conf[1]);
362 if (ret < 0)
363 goto out_free_memmap;
364 }
365
366 /* Default AC configuration */
367 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
368 conf_ac = &wl->conf.tx.ac_conf[i];
369 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
370 conf_ac->cw_max, conf_ac->aifsn,
371 conf_ac->tx_op_limit);
372 if (ret < 0)
373 goto out_free_memmap;
374 }
375
376 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200377 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200379 goto out_free_memmap;
380
381 /* Configure for CAM power saving (ie. always active) */
382 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
383 if (ret < 0)
384 goto out_free_memmap;
385
386 /* configure PM */
387 ret = wl1271_acx_pm_config(wl);
388 if (ret < 0)
389 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300390
391 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200392
393 out_free_memmap:
394 kfree(wl->target_mem_map);
395 wl->target_mem_map = NULL;
396
397 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398}
399
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300400static void wl1271_fw_status(struct wl1271 *wl,
401 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300402{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200403 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404 u32 total = 0;
405 int i;
406
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200407 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300408
409 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
410 "drv_rx_counter = %d, tx_results_counter = %d)",
411 status->intr,
412 status->fw_rx_counter,
413 status->drv_rx_counter,
414 status->tx_results_counter);
415
416 /* update number of available TX blocks */
417 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300418 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
419 wl->tx_blocks_freed[i];
420
421 wl->tx_blocks_freed[i] =
422 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423 wl->tx_blocks_available += cnt;
424 total += cnt;
425 }
426
427 /* if more blocks are available now, schedule some tx work */
428 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300429 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430
431 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200432 getnstimeofday(&ts);
433 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
434 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435}
436
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200437#define WL1271_IRQ_MAX_LOOPS 10
438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439static void wl1271_irq_work(struct work_struct *work)
440{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300442 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200443 int loopcount = WL1271_IRQ_MAX_LOOPS;
444 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445 struct wl1271 *wl =
446 container_of(work, struct wl1271, irq_work);
447
448 mutex_lock(&wl->mutex);
449
450 wl1271_debug(DEBUG_IRQ, "IRQ work");
451
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200452 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453 goto out;
454
455 ret = wl1271_ps_elp_wakeup(wl, true);
456 if (ret < 0)
457 goto out;
458
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200459 spin_lock_irqsave(&wl->wl_lock, flags);
460 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
461 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
462 spin_unlock_irqrestore(&wl->wl_lock, flags);
463 loopcount--;
464
465 wl1271_fw_status(wl, wl->fw_status);
466 intr = le32_to_cpu(wl->fw_status->intr);
467 if (!intr) {
468 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200469 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200470 continue;
471 }
472
473 intr &= WL1271_INTR_MASK;
474
475 if (intr & WL1271_ACX_INTR_DATA) {
476 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
477
478 /* check for tx results */
479 if (wl->fw_status->tx_results_counter !=
480 (wl->tx_results_count & 0xff))
481 wl1271_tx_complete(wl);
482
483 wl1271_rx(wl, wl->fw_status);
484 }
485
486 if (intr & WL1271_ACX_INTR_EVENT_A) {
487 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
488 wl1271_event_handle(wl, 0);
489 }
490
491 if (intr & WL1271_ACX_INTR_EVENT_B) {
492 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
493 wl1271_event_handle(wl, 1);
494 }
495
496 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
497 wl1271_debug(DEBUG_IRQ,
498 "WL1271_ACX_INTR_INIT_COMPLETE");
499
500 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
501 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
502
503 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 }
505
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200506 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
507 ieee80211_queue_work(wl->hw, &wl->irq_work);
508 else
509 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
510 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512 wl1271_ps_elp_sleep(wl);
513
514out:
515 mutex_unlock(&wl->mutex);
516}
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518static int wl1271_fetch_firmware(struct wl1271 *wl)
519{
520 const struct firmware *fw;
521 int ret;
522
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200523 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524
525 if (ret < 0) {
526 wl1271_error("could not get firmware: %d", ret);
527 return ret;
528 }
529
530 if (fw->size % 4) {
531 wl1271_error("firmware size is not multiple of 32 bits: %zu",
532 fw->size);
533 ret = -EILSEQ;
534 goto out;
535 }
536
537 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300538 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300539
540 if (!wl->fw) {
541 wl1271_error("could not allocate memory for the firmware");
542 ret = -ENOMEM;
543 goto out;
544 }
545
546 memcpy(wl->fw, fw->data, wl->fw_len);
547
548 ret = 0;
549
550out:
551 release_firmware(fw);
552
553 return ret;
554}
555
556static int wl1271_fetch_nvs(struct wl1271 *wl)
557{
558 const struct firmware *fw;
559 int ret;
560
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200561 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562
563 if (ret < 0) {
564 wl1271_error("could not get nvs file: %d", ret);
565 return ret;
566 }
567
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300568 /*
569 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
570 * configurations) can be removed when those NVS files stop floating
571 * around.
572 */
573 if (fw->size != sizeof(struct wl1271_nvs_file) &&
574 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
575 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200576 wl1271_error("nvs size is not as expected: %zu != %zu",
577 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300578 ret = -EILSEQ;
579 goto out;
580 }
581
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300582 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583
584 if (!wl->nvs) {
585 wl1271_error("could not allocate memory for the nvs file");
586 ret = -ENOMEM;
587 goto out;
588 }
589
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300590 memcpy(wl->nvs, fw->data, fw->size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300592out:
593 release_firmware(fw);
594
595 return ret;
596}
597
598static void wl1271_fw_wakeup(struct wl1271 *wl)
599{
600 u32 elp_reg;
601
602 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300603 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300604}
605
606static int wl1271_setup(struct wl1271 *wl)
607{
608 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
609 if (!wl->fw_status)
610 return -ENOMEM;
611
612 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
613 if (!wl->tx_res_if) {
614 kfree(wl->fw_status);
615 return -ENOMEM;
616 }
617
618 INIT_WORK(&wl->irq_work, wl1271_irq_work);
619 INIT_WORK(&wl->tx_work, wl1271_tx_work);
620 return 0;
621}
622
623static int wl1271_chip_wakeup(struct wl1271 *wl)
624{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300625 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626 int ret = 0;
627
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200628 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300629 wl1271_power_on(wl);
630 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200631 wl1271_io_reset(wl);
632 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633
634 /* We don't need a real memory partition here, because we only want
635 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300636 memset(&partition, 0, sizeof(partition));
637 partition.reg.start = REGISTERS_BASE;
638 partition.reg.size = REGISTERS_DOWN_SIZE;
639 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640
641 /* ELP module wake up */
642 wl1271_fw_wakeup(wl);
643
644 /* whal_FwCtrl_BootSm() */
645
646 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200647 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648
649 /* 1. check if chip id is valid */
650
651 switch (wl->chip.id) {
652 case CHIP_ID_1271_PG10:
653 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
654 wl->chip.id);
655
656 ret = wl1271_setup(wl);
657 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200658 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 break;
660 case CHIP_ID_1271_PG20:
661 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
662 wl->chip.id);
663
664 ret = wl1271_setup(wl);
665 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 break;
668 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200671 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 }
673
674 if (wl->fw == NULL) {
675 ret = wl1271_fetch_firmware(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 }
679
680 /* No NVS from netlink, try to get it from the filesystem */
681 if (wl->nvs == NULL) {
682 ret = wl1271_fetch_nvs(wl);
683 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200684 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300685 }
686
687out:
688 return ret;
689}
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691int wl1271_plt_start(struct wl1271 *wl)
692{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200693 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694 int ret;
695
696 mutex_lock(&wl->mutex);
697
698 wl1271_notice("power up");
699
700 if (wl->state != WL1271_STATE_OFF) {
701 wl1271_error("cannot go into PLT state because not "
702 "in off state: %d", wl->state);
703 ret = -EBUSY;
704 goto out;
705 }
706
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200707 while (retries) {
708 retries--;
709 ret = wl1271_chip_wakeup(wl);
710 if (ret < 0)
711 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200713 ret = wl1271_boot(wl);
714 if (ret < 0)
715 goto power_off;
716
717 ret = wl1271_plt_init(wl);
718 if (ret < 0)
719 goto irq_disable;
720
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200721 wl->state = WL1271_STATE_PLT;
722 wl1271_notice("firmware booted in PLT mode (%s)",
723 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 goto out;
725
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200726irq_disable:
727 wl1271_disable_interrupts(wl);
728 mutex_unlock(&wl->mutex);
729 /* Unlocking the mutex in the middle of handling is
730 inherently unsafe. In this case we deem it safe to do,
731 because we need to let any possibly pending IRQ out of
732 the system (and while we are WL1271_STATE_OFF the IRQ
733 work function will not do anything.) Also, any other
734 possible concurrent operations will fail due to the
735 current state, hence the wl1271 struct should be safe. */
736 cancel_work_sync(&wl->irq_work);
737 mutex_lock(&wl->mutex);
738power_off:
739 wl1271_power_off(wl);
740 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200742 wl1271_error("firmware boot in PLT mode failed despite %d retries",
743 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300744out:
745 mutex_unlock(&wl->mutex);
746
747 return ret;
748}
749
750int wl1271_plt_stop(struct wl1271 *wl)
751{
752 int ret = 0;
753
754 mutex_lock(&wl->mutex);
755
756 wl1271_notice("power down");
757
758 if (wl->state != WL1271_STATE_PLT) {
759 wl1271_error("cannot power down because not in PLT "
760 "state: %d", wl->state);
761 ret = -EBUSY;
762 goto out;
763 }
764
765 wl1271_disable_interrupts(wl);
766 wl1271_power_off(wl);
767
768 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300769 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770
771out:
772 mutex_unlock(&wl->mutex);
773
774 return ret;
775}
776
777
778static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
779{
780 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200781 struct ieee80211_conf *conf = &hw->conf;
782 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
783 struct ieee80211_sta *sta = txinfo->control.sta;
784 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200786 /* peek into the rates configured in the STA entry */
787 spin_lock_irqsave(&wl->wl_lock, flags);
788 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
789 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
790 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
791 }
792 spin_unlock_irqrestore(&wl->wl_lock, flags);
793
794 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795 skb_queue_tail(&wl->tx_queue, skb);
796
797 /*
798 * The chip specific setup must run before the first TX packet -
799 * before that, the tx_work will not be initialized!
800 */
801
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300802 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300803
804 /*
805 * The workqueue is slow to process the tx_queue and we need stop
806 * the queue here, otherwise the queue will get too long.
807 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200808 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
809 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300810
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200811 spin_lock_irqsave(&wl->wl_lock, flags);
812 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200813 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200814 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300815 }
816
817 return NETDEV_TX_OK;
818}
819
820static int wl1271_op_start(struct ieee80211_hw *hw)
821{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200822 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
823
824 /*
825 * We have to delay the booting of the hardware because
826 * we need to know the local MAC address before downloading and
827 * initializing the firmware. The MAC address cannot be changed
828 * after boot, and without the proper MAC address, the firmware
829 * will not function properly.
830 *
831 * The MAC address is first known when the corresponding interface
832 * is added. That is where we will initialize the hardware.
833 */
834
835 return 0;
836}
837
838static void wl1271_op_stop(struct ieee80211_hw *hw)
839{
840 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
841}
842
843static int wl1271_op_add_interface(struct ieee80211_hw *hw,
844 struct ieee80211_vif *vif)
845{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200847 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300848 int ret = 0;
849
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200850 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
851 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300852
853 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200854 if (wl->vif) {
855 ret = -EBUSY;
856 goto out;
857 }
858
859 wl->vif = vif;
860
861 switch (vif->type) {
862 case NL80211_IFTYPE_STATION:
863 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200864 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200865 break;
866 case NL80211_IFTYPE_ADHOC:
867 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200868 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200869 break;
870 default:
871 ret = -EOPNOTSUPP;
872 goto out;
873 }
874
875 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876
877 if (wl->state != WL1271_STATE_OFF) {
878 wl1271_error("cannot start because not in off state: %d",
879 wl->state);
880 ret = -EBUSY;
881 goto out;
882 }
883
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200884 while (retries) {
885 retries--;
886 ret = wl1271_chip_wakeup(wl);
887 if (ret < 0)
888 goto power_off;
889
890 ret = wl1271_boot(wl);
891 if (ret < 0)
892 goto power_off;
893
894 ret = wl1271_hw_init(wl);
895 if (ret < 0)
896 goto irq_disable;
897
898 wl->state = WL1271_STATE_ON;
899 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900 goto out;
901
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200902irq_disable:
903 wl1271_disable_interrupts(wl);
904 mutex_unlock(&wl->mutex);
905 /* Unlocking the mutex in the middle of handling is
906 inherently unsafe. In this case we deem it safe to do,
907 because we need to let any possibly pending IRQ out of
908 the system (and while we are WL1271_STATE_OFF the IRQ
909 work function will not do anything.) Also, any other
910 possible concurrent operations will fail due to the
911 current state, hence the wl1271 struct should be safe. */
912 cancel_work_sync(&wl->irq_work);
913 mutex_lock(&wl->mutex);
914power_off:
915 wl1271_power_off(wl);
916 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200918 wl1271_error("firmware boot failed despite %d retries",
919 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300920out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921 mutex_unlock(&wl->mutex);
922
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300923 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300924 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 return ret;
927}
928
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200929static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
930 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931{
932 struct wl1271 *wl = hw->priv;
933 int i;
934
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200935 mutex_lock(&wl->mutex);
936 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200938 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300940 list_del(&wl->list);
941
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 WARN_ON(wl->state != WL1271_STATE_ON);
943
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200944 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 mutex_unlock(&wl->mutex);
946 ieee80211_scan_completed(wl->hw, true);
947 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 }
949
950 wl->state = WL1271_STATE_OFF;
951
952 wl1271_disable_interrupts(wl);
953
954 mutex_unlock(&wl->mutex);
955
956 cancel_work_sync(&wl->irq_work);
957 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
959 mutex_lock(&wl->mutex);
960
961 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300962 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963 wl1271_power_off(wl);
964
965 memset(wl->bssid, 0, ETH_ALEN);
966 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
967 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200969 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300970 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971
972 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200973 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
975 wl->tx_blocks_available = 0;
976 wl->tx_results_count = 0;
977 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300978 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200979 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl->time_offset = 0;
981 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200982 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
983 wl->sta_rate_set = 0;
984 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200985 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200986 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +0300987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 for (i = 0; i < NUM_TX_QUEUES; i++)
989 wl->tx_blocks_freed[i] = 0;
990
991 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300992
993 kfree(wl->fw_status);
994 wl->fw_status = NULL;
995 kfree(wl->tx_res_if);
996 wl->tx_res_if = NULL;
997 kfree(wl->target_mem_map);
998 wl->target_mem_map = NULL;
999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 mutex_unlock(&wl->mutex);
1001}
1002
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001003static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1004{
1005 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1006 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1007
1008 /* combine requested filters with current filter config */
1009 filters = wl->filters | filters;
1010
1011 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1012
1013 if (filters & FIF_PROMISC_IN_BSS) {
1014 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1015 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1016 wl->rx_config |= CFG_BSSID_FILTER_EN;
1017 }
1018 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1019 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1020 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1021 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1022 }
1023 if (filters & FIF_OTHER_BSS) {
1024 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1025 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1026 }
1027 if (filters & FIF_CONTROL) {
1028 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1029 wl->rx_filter |= CFG_RX_CTL_EN;
1030 }
1031 if (filters & FIF_FCSFAIL) {
1032 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1033 wl->rx_filter |= CFG_RX_FCS_ERROR;
1034 }
1035}
1036
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001037static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001038{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001039 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001040 /* we need to use a dummy BSSID for now */
1041 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1042 0xad, 0xbe, 0xef };
1043
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001044 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1045
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001046 /* pass through frames from all BSS */
1047 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1048
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001049 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001050 if (ret < 0)
1051 goto out;
1052
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001053 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001054
1055out:
1056 return ret;
1057}
1058
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001059static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001060{
1061 int ret;
1062
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001063 /*
1064 * One of the side effects of the JOIN command is that is clears
1065 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1066 * to a WPA/WPA2 access point will therefore kill the data-path.
1067 * Currently there is no supported scenario for JOIN during
1068 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1069 * must be handled somehow.
1070 *
1071 */
1072 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1073 wl1271_info("JOIN while associated.");
1074
1075 if (set_assoc)
1076 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1077
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001078 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1079 if (ret < 0)
1080 goto out;
1081
1082 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1083
1084 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1085 goto out;
1086
1087 /*
1088 * The join command disable the keep-alive mode, shut down its process,
1089 * and also clear the template config, so we need to reset it all after
1090 * the join. The acx_aid starts the keep-alive process, and the order
1091 * of the commands below is relevant.
1092 */
1093 ret = wl1271_acx_keep_alive_mode(wl, true);
1094 if (ret < 0)
1095 goto out;
1096
1097 ret = wl1271_acx_aid(wl, wl->aid);
1098 if (ret < 0)
1099 goto out;
1100
1101 ret = wl1271_cmd_build_klv_null_data(wl);
1102 if (ret < 0)
1103 goto out;
1104
1105 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1106 ACX_KEEP_ALIVE_TPL_VALID);
1107 if (ret < 0)
1108 goto out;
1109
1110out:
1111 return ret;
1112}
1113
1114static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001115{
1116 int ret;
1117
1118 /* to stop listening to a channel, we disconnect */
1119 ret = wl1271_cmd_disconnect(wl);
1120 if (ret < 0)
1121 goto out;
1122
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001123 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001124 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001125
1126 /* stop filterting packets based on bssid */
1127 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001128
1129out:
1130 return ret;
1131}
1132
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001133static void wl1271_set_band_rate(struct wl1271 *wl)
1134{
1135 if (wl->band == IEEE80211_BAND_2GHZ)
1136 wl->basic_rate_set = wl->conf.tx.basic_rate;
1137 else
1138 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1139}
1140
1141static u32 wl1271_min_rate_get(struct wl1271 *wl)
1142{
1143 int i;
1144 u32 rate = 0;
1145
1146 if (!wl->basic_rate_set) {
1147 WARN_ON(1);
1148 wl->basic_rate_set = wl->conf.tx.basic_rate;
1149 }
1150
1151 for (i = 0; !rate; i++) {
1152 if ((wl->basic_rate_set >> i) & 0x1)
1153 rate = 1 << i;
1154 }
1155
1156 return rate;
1157}
1158
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001159static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1160{
1161 int ret;
1162
1163 if (idle) {
1164 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1165 ret = wl1271_unjoin(wl);
1166 if (ret < 0)
1167 goto out;
1168 }
1169 wl->rate_set = wl1271_min_rate_get(wl);
1170 wl->sta_rate_set = 0;
1171 ret = wl1271_acx_rate_policies(wl);
1172 if (ret < 0)
1173 goto out;
1174 ret = wl1271_acx_keep_alive_config(
1175 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1176 ACX_KEEP_ALIVE_TPL_INVALID);
1177 if (ret < 0)
1178 goto out;
1179 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1180 } else {
1181 /* increment the session counter */
1182 wl->session_counter++;
1183 if (wl->session_counter >= SESSION_COUNTER_MAX)
1184 wl->session_counter = 0;
1185 ret = wl1271_dummy_join(wl);
1186 if (ret < 0)
1187 goto out;
1188 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1189 }
1190
1191out:
1192 return ret;
1193}
1194
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001195static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1196{
1197 struct wl1271 *wl = hw->priv;
1198 struct ieee80211_conf *conf = &hw->conf;
1199 int channel, ret = 0;
1200
1201 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001203 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204 channel,
1205 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001206 conf->power_level,
1207 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001209 /*
1210 * mac80211 will go to idle nearly immediately after transmitting some
1211 * frames, such as the deauth. To make sure those frames reach the air,
1212 * wait here until the TX queue is fully flushed.
1213 */
1214 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1215 (conf->flags & IEEE80211_CONF_IDLE))
1216 wl1271_tx_flush(wl);
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 mutex_lock(&wl->mutex);
1219
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001220 if (unlikely(wl->state == WL1271_STATE_OFF))
1221 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 ret = wl1271_ps_elp_wakeup(wl, false);
1224 if (ret < 0)
1225 goto out;
1226
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001227 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001228 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1229 ((wl->band != conf->channel->band) ||
1230 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001231 wl->band = conf->channel->band;
1232 wl->channel = channel;
1233
1234 /*
1235 * FIXME: the mac80211 should really provide a fixed rate
1236 * to use here. for now, just use the smallest possible rate
1237 * for the band as a fixed rate for association frames and
1238 * other control messages.
1239 */
1240 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1241 wl1271_set_band_rate(wl);
1242
1243 wl->basic_rate = wl1271_min_rate_get(wl);
1244 ret = wl1271_acx_rate_policies(wl);
1245 if (ret < 0)
1246 wl1271_warning("rate policy for update channel "
1247 "failed %d", ret);
1248
1249 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001250 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001251 if (ret < 0)
1252 wl1271_warning("cmd join to update channel "
1253 "failed %d", ret);
1254 }
1255 }
1256
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001257 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001258 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1259 if (ret < 0)
1260 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261 }
1262
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001263 if (conf->flags & IEEE80211_CONF_PS &&
1264 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1265 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266
1267 /*
1268 * We enter PSM only if we're already associated.
1269 * If we're not, we'll enter it when joining an SSID,
1270 * through the bss_info_changed() hook.
1271 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001272 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001273 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001274 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1275 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001276 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001277 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001278 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001279 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001281 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001283 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001284 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1285 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 }
1287
1288 if (conf->power_level != wl->power_level) {
1289 ret = wl1271_acx_tx_power(wl, conf->power_level);
1290 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001291 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292
1293 wl->power_level = conf->power_level;
1294 }
1295
1296out_sleep:
1297 wl1271_ps_elp_sleep(wl);
1298
1299out:
1300 mutex_unlock(&wl->mutex);
1301
1302 return ret;
1303}
1304
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001305struct wl1271_filter_params {
1306 bool enabled;
1307 int mc_list_length;
1308 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1309};
1310
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001311static int wl1271_op_configure_arp_filter(struct ieee80211_hw *hw,
1312 struct ieee80211_vif *vif,
1313 struct in_ifaddr *ifa_list)
1314{
1315 struct wl1271 *wl = hw->priv;
1316 int ret = 0;
1317
1318 WARN_ON(vif != wl->vif);
1319
1320 /* disable filtering if there are multiple addresses */
1321 if (ifa_list && ifa_list->ifa_next)
1322 ifa_list = NULL;
1323
1324 mutex_lock(&wl->mutex);
1325
1326 if (wl->state == WL1271_STATE_OFF)
1327 goto out;
1328
1329 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1330
1331 ret = wl1271_ps_elp_wakeup(wl, false);
1332 if (ret < 0)
1333 goto out;
1334
1335 if (ifa_list) {
1336 ret = wl1271_cmd_build_arp_reply(wl, &ifa_list->ifa_address);
1337 if (ret < 0)
1338 goto out_sleep;
1339 ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_FILTER_AND_REPLY,
1340 (u8 *)&ifa_list->ifa_address);
1341 if (ret < 0)
1342 goto out_sleep;
1343 } else {
1344 ret = wl1271_acx_arp_ip_filter(wl, ACX_ARP_DISABLE, NULL);
1345 if (ret < 0)
1346 goto out_sleep;
1347 }
1348
1349out_sleep:
1350 wl1271_ps_elp_sleep(wl);
1351
1352out:
1353 mutex_unlock(&wl->mutex);
1354
1355 return ret;
1356}
1357
Jiri Pirko22bedad2010-04-01 21:22:57 +00001358static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1359 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001360{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001361 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001362 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001363 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001365 if (unlikely(wl->state == WL1271_STATE_OFF))
1366 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001367
Juuso Oikarinen74441132009-10-13 12:47:53 +03001368 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001369 if (!fp) {
1370 wl1271_error("Out of memory setting filters.");
1371 return 0;
1372 }
1373
1374 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001375 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001376 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1377 fp->enabled = false;
1378 } else {
1379 fp->enabled = true;
1380 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001381 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001382 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001383 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001384 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001385 }
1386
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001387 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001388}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001390#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1391 FIF_ALLMULTI | \
1392 FIF_FCSFAIL | \
1393 FIF_BCN_PRBRESP_PROMISC | \
1394 FIF_CONTROL | \
1395 FIF_OTHER_BSS)
1396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1398 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001399 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001401 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001403 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404
1405 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1406
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001407 mutex_lock(&wl->mutex);
1408
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001409 *total &= WL1271_SUPPORTED_FILTERS;
1410 changed &= WL1271_SUPPORTED_FILTERS;
1411
1412 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001413 goto out;
1414
1415 ret = wl1271_ps_elp_wakeup(wl, false);
1416 if (ret < 0)
1417 goto out;
1418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001420 if (*total & FIF_ALLMULTI)
1421 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1422 else if (fp)
1423 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1424 fp->mc_list,
1425 fp->mc_list_length);
1426 if (ret < 0)
1427 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001428
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001429 /* determine, whether supported filter values have changed */
1430 if (changed == 0)
1431 goto out_sleep;
1432
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001433 /* configure filters */
1434 wl->filters = *total;
1435 wl1271_configure_filters(wl, 0);
1436
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001437 /* apply configured filters */
1438 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1439 if (ret < 0)
1440 goto out_sleep;
1441
1442out_sleep:
1443 wl1271_ps_elp_sleep(wl);
1444
1445out:
1446 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001447 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448}
1449
1450static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1451 struct ieee80211_vif *vif,
1452 struct ieee80211_sta *sta,
1453 struct ieee80211_key_conf *key_conf)
1454{
1455 struct wl1271 *wl = hw->priv;
1456 const u8 *addr;
1457 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001458 u32 tx_seq_32 = 0;
1459 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 u8 key_type;
1461
1462 static const u8 bcast_addr[ETH_ALEN] =
1463 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1464
1465 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1466
1467 addr = sta ? sta->addr : bcast_addr;
1468
1469 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1470 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1471 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1472 key_conf->alg, key_conf->keyidx,
1473 key_conf->keylen, key_conf->flags);
1474 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1475
1476 if (is_zero_ether_addr(addr)) {
1477 /* We dont support TX only encryption */
1478 ret = -EOPNOTSUPP;
1479 goto out;
1480 }
1481
1482 mutex_lock(&wl->mutex);
1483
1484 ret = wl1271_ps_elp_wakeup(wl, false);
1485 if (ret < 0)
1486 goto out_unlock;
1487
1488 switch (key_conf->alg) {
1489 case ALG_WEP:
1490 key_type = KEY_WEP;
1491
1492 key_conf->hw_key_idx = key_conf->keyidx;
1493 break;
1494 case ALG_TKIP:
1495 key_type = KEY_TKIP;
1496
1497 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001498 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1499 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 break;
1501 case ALG_CCMP:
1502 key_type = KEY_AES;
1503
1504 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001505 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1506 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 break;
1508 default:
1509 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1510
1511 ret = -EOPNOTSUPP;
1512 goto out_sleep;
1513 }
1514
1515 switch (cmd) {
1516 case SET_KEY:
1517 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1518 key_conf->keyidx, key_type,
1519 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001520 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521 if (ret < 0) {
1522 wl1271_error("Could not add or replace key");
1523 goto out_sleep;
1524 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001525
1526 /* the default WEP key needs to be configured at least once */
1527 if (key_type == KEY_WEP) {
1528 ret = wl1271_cmd_set_default_wep_key(wl,
1529 wl->default_key);
1530 if (ret < 0)
1531 goto out_sleep;
1532 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533 break;
1534
1535 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001536 /* The wl1271 does not allow to remove unicast keys - they
1537 will be cleared automatically on next CMD_JOIN. Ignore the
1538 request silently, as we dont want the mac80211 to emit
1539 an error message. */
1540 if (!is_broadcast_ether_addr(addr))
1541 break;
1542
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1544 key_conf->keyidx, key_type,
1545 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001546 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547 if (ret < 0) {
1548 wl1271_error("Could not remove key");
1549 goto out_sleep;
1550 }
1551 break;
1552
1553 default:
1554 wl1271_error("Unsupported key cmd 0x%x", cmd);
1555 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001556 break;
1557 }
1558
1559out_sleep:
1560 wl1271_ps_elp_sleep(wl);
1561
1562out_unlock:
1563 mutex_unlock(&wl->mutex);
1564
1565out:
1566 return ret;
1567}
1568
1569static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001570 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571 struct cfg80211_scan_request *req)
1572{
1573 struct wl1271 *wl = hw->priv;
1574 int ret;
1575 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001576 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577
1578 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1579
1580 if (req->n_ssids) {
1581 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001582 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 }
1584
1585 mutex_lock(&wl->mutex);
1586
1587 ret = wl1271_ps_elp_wakeup(wl, false);
1588 if (ret < 0)
1589 goto out;
1590
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001591 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001592 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1593 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001594 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001595 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1596 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597
1598 wl1271_ps_elp_sleep(wl);
1599
1600out:
1601 mutex_unlock(&wl->mutex);
1602
1603 return ret;
1604}
1605
1606static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1607{
1608 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001609 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610
1611 mutex_lock(&wl->mutex);
1612
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001613 if (unlikely(wl->state == WL1271_STATE_OFF))
1614 goto out;
1615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616 ret = wl1271_ps_elp_wakeup(wl, false);
1617 if (ret < 0)
1618 goto out;
1619
1620 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1621 if (ret < 0)
1622 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1623
1624 wl1271_ps_elp_sleep(wl);
1625
1626out:
1627 mutex_unlock(&wl->mutex);
1628
1629 return ret;
1630}
1631
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001632static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1633{
1634 u8 *ptr = beacon->data +
1635 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1636
1637 /* find the location of the ssid in the beacon */
1638 while (ptr < beacon->data + beacon->len) {
1639 if (ptr[0] == WLAN_EID_SSID) {
1640 wl->ssid_len = ptr[1];
1641 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1642 return;
1643 }
1644 ptr += ptr[1];
1645 }
1646 wl1271_error("ad-hoc beacon template has no SSID!\n");
1647}
1648
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001649static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1650 struct ieee80211_vif *vif,
1651 struct ieee80211_bss_conf *bss_conf,
1652 u32 changed)
1653{
1654 enum wl1271_cmd_ps_mode mode;
1655 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001656 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001657 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658 int ret;
1659
1660 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1661
1662 mutex_lock(&wl->mutex);
1663
1664 ret = wl1271_ps_elp_wakeup(wl, false);
1665 if (ret < 0)
1666 goto out;
1667
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001668 if ((changed && BSS_CHANGED_BEACON_INT) &&
1669 (wl->bss_type == BSS_TYPE_IBSS)) {
1670 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1671 bss_conf->beacon_int);
1672
1673 wl->beacon_int = bss_conf->beacon_int;
1674 do_join = true;
1675 }
1676
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001677 if ((changed && BSS_CHANGED_BEACON) &&
1678 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001679 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1680
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001681 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1682
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683 if (beacon) {
1684 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001685
1686 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001687 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1688 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001689 beacon->len, 0,
1690 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001691
1692 if (ret < 0) {
1693 dev_kfree_skb(beacon);
1694 goto out_sleep;
1695 }
1696
1697 hdr = (struct ieee80211_hdr *) beacon->data;
1698 hdr->frame_control = cpu_to_le16(
1699 IEEE80211_FTYPE_MGMT |
1700 IEEE80211_STYPE_PROBE_RESP);
1701
1702 ret = wl1271_cmd_template_set(wl,
1703 CMD_TEMPL_PROBE_RESPONSE,
1704 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001705 beacon->len, 0,
1706 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001707 dev_kfree_skb(beacon);
1708 if (ret < 0)
1709 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001710
1711 /* Need to update the SSID (for filtering etc) */
1712 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001713 }
1714 }
1715
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001716 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1717 (wl->bss_type == BSS_TYPE_IBSS)) {
1718 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1719 bss_conf->enable_beacon ? "enabled" : "disabled");
1720
1721 if (bss_conf->enable_beacon)
1722 wl->set_bss_type = BSS_TYPE_IBSS;
1723 else
1724 wl->set_bss_type = BSS_TYPE_STA_BSS;
1725 do_join = true;
1726 }
1727
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001728 if (changed & BSS_CHANGED_CQM) {
1729 bool enable = false;
1730 if (bss_conf->cqm_rssi_thold)
1731 enable = true;
1732 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1733 bss_conf->cqm_rssi_thold,
1734 bss_conf->cqm_rssi_hyst);
1735 if (ret < 0)
1736 goto out;
1737 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1738 }
1739
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001740 if ((changed & BSS_CHANGED_BSSID) &&
1741 /*
1742 * Now we know the correct bssid, so we send a new join command
1743 * and enable the BSSID filter
1744 */
1745 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001746 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001747
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001748 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001749 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001750 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001751
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001752 ret = wl1271_build_qos_null_data(wl);
1753 if (ret < 0)
1754 goto out_sleep;
1755
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001756 /* filter out all packets not from this BSSID */
1757 wl1271_configure_filters(wl, 0);
1758
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001759 /* Need to update the BSSID (for filtering etc) */
1760 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001761 }
1762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001763 if (changed & BSS_CHANGED_ASSOC) {
1764 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001765 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001767 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001769 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001770 * use basic rates from AP, and determine lowest rate
1771 * to use with control frames.
1772 */
1773 rates = bss_conf->basic_rates;
1774 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1775 rates);
1776 wl->basic_rate = wl1271_min_rate_get(wl);
1777 ret = wl1271_acx_rate_policies(wl);
1778 if (ret < 0)
1779 goto out_sleep;
1780
1781 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001782 * with wl1271, we don't need to update the
1783 * beacon_int and dtim_period, because the firmware
1784 * updates it by itself when the first beacon is
1785 * received after a join.
1786 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001787 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1788 if (ret < 0)
1789 goto out_sleep;
1790
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001791 /*
1792 * The SSID is intentionally set to NULL here - the
1793 * firmware will set the probe request with a
1794 * broadcast SSID regardless of what we set in the
1795 * template.
1796 */
1797 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1798 NULL, 0, wl->band);
1799
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001800 /* enable the connection monitoring feature */
1801 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 if (ret < 0)
1803 goto out_sleep;
1804
1805 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001806 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1807 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001809 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 if (ret < 0)
1811 goto out_sleep;
1812 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001813 } else {
1814 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001815 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001816 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001817
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001818 /* revert back to minimum rates for the current band */
1819 wl1271_set_band_rate(wl);
1820 wl->basic_rate = wl1271_min_rate_get(wl);
1821 ret = wl1271_acx_rate_policies(wl);
1822 if (ret < 0)
1823 goto out_sleep;
1824
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001825 /* disable connection monitor features */
1826 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001827
1828 /* Disable the keep-alive feature */
1829 ret = wl1271_acx_keep_alive_mode(wl, false);
1830
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001831 if (ret < 0)
1832 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001834
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001836
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 if (changed & BSS_CHANGED_ERP_SLOT) {
1838 if (bss_conf->use_short_slot)
1839 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1840 else
1841 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1842 if (ret < 0) {
1843 wl1271_warning("Set slot time failed %d", ret);
1844 goto out_sleep;
1845 }
1846 }
1847
1848 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1849 if (bss_conf->use_short_preamble)
1850 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1851 else
1852 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1853 }
1854
1855 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1856 if (bss_conf->use_cts_prot)
1857 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1858 else
1859 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1860 if (ret < 0) {
1861 wl1271_warning("Set ctsprotect failed %d", ret);
1862 goto out_sleep;
1863 }
1864 }
1865
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001866 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001867 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001868 if (ret < 0) {
1869 wl1271_warning("cmd join failed %d", ret);
1870 goto out_sleep;
1871 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001872 }
1873
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001874out_sleep:
1875 wl1271_ps_elp_sleep(wl);
1876
1877out:
1878 mutex_unlock(&wl->mutex);
1879}
1880
Kalle Valoc6999d82010-02-18 13:25:41 +02001881static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1882 const struct ieee80211_tx_queue_params *params)
1883{
1884 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001885 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001886 int ret;
1887
1888 mutex_lock(&wl->mutex);
1889
1890 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1891
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001892 ret = wl1271_ps_elp_wakeup(wl, false);
1893 if (ret < 0)
1894 goto out;
1895
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001896 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001897 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1898 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001899 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001900 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001901 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001902
Kalle Valo4695dc92010-03-18 12:26:38 +02001903 if (params->uapsd)
1904 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1905 else
1906 ps_scheme = CONF_PS_SCHEME_LEGACY;
1907
Kalle Valoc6999d82010-02-18 13:25:41 +02001908 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1909 CONF_CHANNEL_TYPE_EDCF,
1910 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001911 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001912 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001913 goto out_sleep;
1914
1915out_sleep:
1916 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001917
1918out:
1919 mutex_unlock(&wl->mutex);
1920
1921 return ret;
1922}
1923
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001924static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1925{
1926
1927 struct wl1271 *wl = hw->priv;
1928 u64 mactime = ULLONG_MAX;
1929 int ret;
1930
1931 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1932
1933 mutex_lock(&wl->mutex);
1934
1935 ret = wl1271_ps_elp_wakeup(wl, false);
1936 if (ret < 0)
1937 goto out;
1938
1939 ret = wl1271_acx_tsf_info(wl, &mactime);
1940 if (ret < 0)
1941 goto out_sleep;
1942
1943out_sleep:
1944 wl1271_ps_elp_sleep(wl);
1945
1946out:
1947 mutex_unlock(&wl->mutex);
1948 return mactime;
1949}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950
1951/* can't be const, mac80211 writes to this */
1952static struct ieee80211_rate wl1271_rates[] = {
1953 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001954 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1955 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001957 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1958 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1960 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001961 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1962 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1964 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001965 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1966 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1968 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001969 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1970 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001972 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1973 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001975 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1976 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001978 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1979 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001981 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1982 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001984 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1985 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001986 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001987 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1988 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001990 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1991 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992};
1993
1994/* can't be const, mac80211 writes to this */
1995static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001996 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1997 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1998 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1999 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2000 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
2001 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2002 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2003 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2004 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
2005 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
2006 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2007 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2008 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009};
2010
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002011/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002012static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002013 /* MCS rates are used only with 11n */
2014 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2015 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2016 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2017 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2018 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2019 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2020 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2021 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2022
2023 11, /* CONF_HW_RXTX_RATE_54 */
2024 10, /* CONF_HW_RXTX_RATE_48 */
2025 9, /* CONF_HW_RXTX_RATE_36 */
2026 8, /* CONF_HW_RXTX_RATE_24 */
2027
2028 /* TI-specific rate */
2029 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2030
2031 7, /* CONF_HW_RXTX_RATE_18 */
2032 6, /* CONF_HW_RXTX_RATE_12 */
2033 3, /* CONF_HW_RXTX_RATE_11 */
2034 5, /* CONF_HW_RXTX_RATE_9 */
2035 4, /* CONF_HW_RXTX_RATE_6 */
2036 2, /* CONF_HW_RXTX_RATE_5_5 */
2037 1, /* CONF_HW_RXTX_RATE_2 */
2038 0 /* CONF_HW_RXTX_RATE_1 */
2039};
2040
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041/* can't be const, mac80211 writes to this */
2042static struct ieee80211_supported_band wl1271_band_2ghz = {
2043 .channels = wl1271_channels,
2044 .n_channels = ARRAY_SIZE(wl1271_channels),
2045 .bitrates = wl1271_rates,
2046 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2047};
2048
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002049/* 5 GHz data rates for WL1273 */
2050static struct ieee80211_rate wl1271_rates_5ghz[] = {
2051 { .bitrate = 60,
2052 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2053 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2054 { .bitrate = 90,
2055 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2056 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2057 { .bitrate = 120,
2058 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2059 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2060 { .bitrate = 180,
2061 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2062 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2063 { .bitrate = 240,
2064 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2065 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2066 { .bitrate = 360,
2067 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2068 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2069 { .bitrate = 480,
2070 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2071 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2072 { .bitrate = 540,
2073 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2074 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2075};
2076
2077/* 5 GHz band channels for WL1273 */
2078static struct ieee80211_channel wl1271_channels_5ghz[] = {
2079 { .hw_value = 183, .center_freq = 4915},
2080 { .hw_value = 184, .center_freq = 4920},
2081 { .hw_value = 185, .center_freq = 4925},
2082 { .hw_value = 187, .center_freq = 4935},
2083 { .hw_value = 188, .center_freq = 4940},
2084 { .hw_value = 189, .center_freq = 4945},
2085 { .hw_value = 192, .center_freq = 4960},
2086 { .hw_value = 196, .center_freq = 4980},
2087 { .hw_value = 7, .center_freq = 5035},
2088 { .hw_value = 8, .center_freq = 5040},
2089 { .hw_value = 9, .center_freq = 5045},
2090 { .hw_value = 11, .center_freq = 5055},
2091 { .hw_value = 12, .center_freq = 5060},
2092 { .hw_value = 16, .center_freq = 5080},
2093 { .hw_value = 34, .center_freq = 5170},
2094 { .hw_value = 36, .center_freq = 5180},
2095 { .hw_value = 38, .center_freq = 5190},
2096 { .hw_value = 40, .center_freq = 5200},
2097 { .hw_value = 42, .center_freq = 5210},
2098 { .hw_value = 44, .center_freq = 5220},
2099 { .hw_value = 46, .center_freq = 5230},
2100 { .hw_value = 48, .center_freq = 5240},
2101 { .hw_value = 52, .center_freq = 5260},
2102 { .hw_value = 56, .center_freq = 5280},
2103 { .hw_value = 60, .center_freq = 5300},
2104 { .hw_value = 64, .center_freq = 5320},
2105 { .hw_value = 100, .center_freq = 5500},
2106 { .hw_value = 104, .center_freq = 5520},
2107 { .hw_value = 108, .center_freq = 5540},
2108 { .hw_value = 112, .center_freq = 5560},
2109 { .hw_value = 116, .center_freq = 5580},
2110 { .hw_value = 120, .center_freq = 5600},
2111 { .hw_value = 124, .center_freq = 5620},
2112 { .hw_value = 128, .center_freq = 5640},
2113 { .hw_value = 132, .center_freq = 5660},
2114 { .hw_value = 136, .center_freq = 5680},
2115 { .hw_value = 140, .center_freq = 5700},
2116 { .hw_value = 149, .center_freq = 5745},
2117 { .hw_value = 153, .center_freq = 5765},
2118 { .hw_value = 157, .center_freq = 5785},
2119 { .hw_value = 161, .center_freq = 5805},
2120 { .hw_value = 165, .center_freq = 5825},
2121};
2122
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002123/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002124static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002125 /* MCS rates are used only with 11n */
2126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2127 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2128 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2129 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2130 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2131 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2132 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2133 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2134
2135 7, /* CONF_HW_RXTX_RATE_54 */
2136 6, /* CONF_HW_RXTX_RATE_48 */
2137 5, /* CONF_HW_RXTX_RATE_36 */
2138 4, /* CONF_HW_RXTX_RATE_24 */
2139
2140 /* TI-specific rate */
2141 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2142
2143 3, /* CONF_HW_RXTX_RATE_18 */
2144 2, /* CONF_HW_RXTX_RATE_12 */
2145 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2146 1, /* CONF_HW_RXTX_RATE_9 */
2147 0, /* CONF_HW_RXTX_RATE_6 */
2148 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2149 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2150 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2151};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002152
2153static struct ieee80211_supported_band wl1271_band_5ghz = {
2154 .channels = wl1271_channels_5ghz,
2155 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2156 .bitrates = wl1271_rates_5ghz,
2157 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2158};
2159
Tobias Klausera0ea9492010-05-20 10:38:11 +02002160static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002161 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2162 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2163};
2164
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165static const struct ieee80211_ops wl1271_ops = {
2166 .start = wl1271_op_start,
2167 .stop = wl1271_op_stop,
2168 .add_interface = wl1271_op_add_interface,
2169 .remove_interface = wl1271_op_remove_interface,
2170 .config = wl1271_op_config,
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002171 .configure_arp_filter = wl1271_op_configure_arp_filter,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002172 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173 .configure_filter = wl1271_op_configure_filter,
2174 .tx = wl1271_op_tx,
2175 .set_key = wl1271_op_set_key,
2176 .hw_scan = wl1271_op_hw_scan,
2177 .bss_info_changed = wl1271_op_bss_info_changed,
2178 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002179 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002180 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002181 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182};
2183
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002184
2185u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2186{
2187 u8 idx;
2188
2189 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2190
2191 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2192 wl1271_error("Illegal RX rate from HW: %d", rate);
2193 return 0;
2194 }
2195
2196 idx = wl1271_band_rate_to_idx[wl->band][rate];
2197 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2198 wl1271_error("Unsupported RX rate from HW: %d", rate);
2199 return 0;
2200 }
2201
2202 return idx;
2203}
2204
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002205static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2206 struct device_attribute *attr,
2207 char *buf)
2208{
2209 struct wl1271 *wl = dev_get_drvdata(dev);
2210 ssize_t len;
2211
2212 /* FIXME: what's the maximum length of buf? page size?*/
2213 len = 500;
2214
2215 mutex_lock(&wl->mutex);
2216 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2217 wl->sg_enabled);
2218 mutex_unlock(&wl->mutex);
2219
2220 return len;
2221
2222}
2223
2224static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2225 struct device_attribute *attr,
2226 const char *buf, size_t count)
2227{
2228 struct wl1271 *wl = dev_get_drvdata(dev);
2229 unsigned long res;
2230 int ret;
2231
2232 ret = strict_strtoul(buf, 10, &res);
2233
2234 if (ret < 0) {
2235 wl1271_warning("incorrect value written to bt_coex_mode");
2236 return count;
2237 }
2238
2239 mutex_lock(&wl->mutex);
2240
2241 res = !!res;
2242
2243 if (res == wl->sg_enabled)
2244 goto out;
2245
2246 wl->sg_enabled = res;
2247
2248 if (wl->state == WL1271_STATE_OFF)
2249 goto out;
2250
2251 ret = wl1271_ps_elp_wakeup(wl, false);
2252 if (ret < 0)
2253 goto out;
2254
2255 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2256 wl1271_ps_elp_sleep(wl);
2257
2258 out:
2259 mutex_unlock(&wl->mutex);
2260 return count;
2261}
2262
2263static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2264 wl1271_sysfs_show_bt_coex_state,
2265 wl1271_sysfs_store_bt_coex_state);
2266
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002267static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2268 struct device_attribute *attr,
2269 char *buf)
2270{
2271 struct wl1271 *wl = dev_get_drvdata(dev);
2272 ssize_t len;
2273
2274 /* FIXME: what's the maximum length of buf? page size?*/
2275 len = 500;
2276
2277 mutex_lock(&wl->mutex);
2278 if (wl->hw_pg_ver >= 0)
2279 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2280 else
2281 len = snprintf(buf, len, "n/a\n");
2282 mutex_unlock(&wl->mutex);
2283
2284 return len;
2285}
2286
2287static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2288 wl1271_sysfs_show_hw_pg_ver, NULL);
2289
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002290int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291{
2292 int ret;
2293
2294 if (wl->mac80211_registered)
2295 return 0;
2296
2297 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2298
2299 ret = ieee80211_register_hw(wl->hw);
2300 if (ret < 0) {
2301 wl1271_error("unable to register mac80211 hw: %d", ret);
2302 return ret;
2303 }
2304
2305 wl->mac80211_registered = true;
2306
2307 wl1271_notice("loaded");
2308
2309 return 0;
2310}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002311EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002313void wl1271_unregister_hw(struct wl1271 *wl)
2314{
2315 ieee80211_unregister_hw(wl->hw);
2316 wl->mac80211_registered = false;
2317
2318}
2319EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2320
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002321int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002323 /* The tx descriptor buffer and the TKIP space. */
2324 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2325 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002326
2327 /* unit us */
2328 /* FIXME: find a proper value */
2329 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002330 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002331
2332 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002333 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002334 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002335 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002336 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002337 IEEE80211_HW_CONNECTION_MONITOR |
2338 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002339
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002340 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2341 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342 wl->hw->wiphy->max_scan_ssids = 1;
2343 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2344
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002345 if (wl1271_11a_enabled())
2346 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2347
Kalle Valo12bd8942010-03-18 12:26:33 +02002348 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002349 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002350
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002351 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352
2353 return 0;
2354}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002355EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002357#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002358
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002359struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002362 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002364 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365
2366 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2367 if (!hw) {
2368 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002369 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002370 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371 }
2372
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002373 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2374 if (!plat_dev) {
2375 wl1271_error("could not allocate platform_device");
2376 ret = -ENOMEM;
2377 goto err_plat_alloc;
2378 }
2379
2380 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2381
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382 wl = hw->priv;
2383 memset(wl, 0, sizeof(*wl));
2384
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002385 INIT_LIST_HEAD(&wl->list);
2386
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002388 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002389
2390 skb_queue_head_init(&wl->tx_queue);
2391
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002392 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002394 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396 wl->rx_counter = 0;
2397 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2398 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002399 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002401 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002402 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002403 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2404 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002405 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002406 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002407 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002408 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002409 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002410
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002411 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002412 wl->tx_frames[i] = NULL;
2413
2414 spin_lock_init(&wl->wl_lock);
2415
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002416 wl->state = WL1271_STATE_OFF;
2417 mutex_init(&wl->mutex);
2418
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002419 /* Apply default driver configuration. */
2420 wl1271_conf_init(wl);
2421
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002422 wl1271_debugfs_init(wl);
2423
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002424 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002425 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002426 if (ret) {
2427 wl1271_error("couldn't register platform device");
2428 goto err_hw;
2429 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002430 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002431
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002432 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002433 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002434 if (ret < 0) {
2435 wl1271_error("failed to create sysfs file bt_coex_state");
2436 goto err_platform;
2437 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002438
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002439 /* Create sysfs file to get HW PG version */
2440 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2441 if (ret < 0) {
2442 wl1271_error("failed to create sysfs file hw_pg_ver");
2443 goto err_bt_coex_state;
2444 }
2445
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002446 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002447
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002448err_bt_coex_state:
2449 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2450
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002451err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002452 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002453
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002454err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002455 wl1271_debugfs_exit(wl);
2456 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002457
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002458err_plat_alloc:
2459 ieee80211_free_hw(hw);
2460
2461err_hw_alloc:
2462
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002463 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002464}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002465EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002466
2467int wl1271_free_hw(struct wl1271 *wl)
2468{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002469 platform_device_unregister(wl->plat_dev);
2470 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002471
2472 wl1271_debugfs_exit(wl);
2473
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002474 vfree(wl->fw);
2475 wl->fw = NULL;
2476 kfree(wl->nvs);
2477 wl->nvs = NULL;
2478
2479 kfree(wl->fw_status);
2480 kfree(wl->tx_res_if);
2481
2482 ieee80211_free_hw(wl->hw);
2483
2484 return 0;
2485}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002486EXPORT_SYMBOL_GPL(wl1271_free_hw);
2487
2488MODULE_LICENSE("GPL");
2489MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2490MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");