blob: 08ff6447dcd98599ff6dbdedf0c9d2bfaa476c34 [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 Oikarinen01c09162009-10-13 12:47:55 +030031#include <linux/inetdevice.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.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.");
469 continue;
470 }
471
472 intr &= WL1271_INTR_MASK;
473
474 if (intr & WL1271_ACX_INTR_DATA) {
475 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
476
477 /* check for tx results */
478 if (wl->fw_status->tx_results_counter !=
479 (wl->tx_results_count & 0xff))
480 wl1271_tx_complete(wl);
481
482 wl1271_rx(wl, wl->fw_status);
483 }
484
485 if (intr & WL1271_ACX_INTR_EVENT_A) {
486 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
487 wl1271_event_handle(wl, 0);
488 }
489
490 if (intr & WL1271_ACX_INTR_EVENT_B) {
491 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
492 wl1271_event_handle(wl, 1);
493 }
494
495 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
496 wl1271_debug(DEBUG_IRQ,
497 "WL1271_ACX_INTR_INIT_COMPLETE");
498
499 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
500 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
501
502 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300503 }
504
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200505 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
506 ieee80211_queue_work(wl->hw, &wl->irq_work);
507 else
508 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
509 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511 wl1271_ps_elp_sleep(wl);
512
513out:
514 mutex_unlock(&wl->mutex);
515}
516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300517static int wl1271_fetch_firmware(struct wl1271 *wl)
518{
519 const struct firmware *fw;
520 int ret;
521
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200522 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523
524 if (ret < 0) {
525 wl1271_error("could not get firmware: %d", ret);
526 return ret;
527 }
528
529 if (fw->size % 4) {
530 wl1271_error("firmware size is not multiple of 32 bits: %zu",
531 fw->size);
532 ret = -EILSEQ;
533 goto out;
534 }
535
536 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300537 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538
539 if (!wl->fw) {
540 wl1271_error("could not allocate memory for the firmware");
541 ret = -ENOMEM;
542 goto out;
543 }
544
545 memcpy(wl->fw, fw->data, wl->fw_len);
546
547 ret = 0;
548
549out:
550 release_firmware(fw);
551
552 return ret;
553}
554
555static int wl1271_fetch_nvs(struct wl1271 *wl)
556{
557 const struct firmware *fw;
558 int ret;
559
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200560 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561
562 if (ret < 0) {
563 wl1271_error("could not get nvs file: %d", ret);
564 return ret;
565 }
566
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200567 if (fw->size != sizeof(struct wl1271_nvs_file)) {
568 wl1271_error("nvs size is not as expected: %zu != %zu",
569 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570 ret = -EILSEQ;
571 goto out;
572 }
573
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200574 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575
576 if (!wl->nvs) {
577 wl1271_error("could not allocate memory for the nvs file");
578 ret = -ENOMEM;
579 goto out;
580 }
581
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200582 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584out:
585 release_firmware(fw);
586
587 return ret;
588}
589
590static void wl1271_fw_wakeup(struct wl1271 *wl)
591{
592 u32 elp_reg;
593
594 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300595 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596}
597
598static int wl1271_setup(struct wl1271 *wl)
599{
600 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
601 if (!wl->fw_status)
602 return -ENOMEM;
603
604 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
605 if (!wl->tx_res_if) {
606 kfree(wl->fw_status);
607 return -ENOMEM;
608 }
609
610 INIT_WORK(&wl->irq_work, wl1271_irq_work);
611 INIT_WORK(&wl->tx_work, wl1271_tx_work);
612 return 0;
613}
614
615static int wl1271_chip_wakeup(struct wl1271 *wl)
616{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300617 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618 int ret = 0;
619
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200620 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621 wl1271_power_on(wl);
622 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200623 wl1271_io_reset(wl);
624 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625
626 /* We don't need a real memory partition here, because we only want
627 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300628 memset(&partition, 0, sizeof(partition));
629 partition.reg.start = REGISTERS_BASE;
630 partition.reg.size = REGISTERS_DOWN_SIZE;
631 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632
633 /* ELP module wake up */
634 wl1271_fw_wakeup(wl);
635
636 /* whal_FwCtrl_BootSm() */
637
638 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200639 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640
641 /* 1. check if chip id is valid */
642
643 switch (wl->chip.id) {
644 case CHIP_ID_1271_PG10:
645 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
646 wl->chip.id);
647
648 ret = wl1271_setup(wl);
649 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200650 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 break;
652 case CHIP_ID_1271_PG20:
653 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
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 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200661 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
666 if (wl->fw == NULL) {
667 ret = wl1271_fetch_firmware(wl);
668 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 }
671
672 /* No NVS from netlink, try to get it from the filesystem */
673 if (wl->nvs == NULL) {
674 ret = wl1271_fetch_nvs(wl);
675 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200676 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 }
678
679out:
680 return ret;
681}
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683int wl1271_plt_start(struct wl1271 *wl)
684{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 int ret;
687
688 mutex_lock(&wl->mutex);
689
690 wl1271_notice("power up");
691
692 if (wl->state != WL1271_STATE_OFF) {
693 wl1271_error("cannot go into PLT state because not "
694 "in off state: %d", wl->state);
695 ret = -EBUSY;
696 goto out;
697 }
698
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200699 while (retries) {
700 retries--;
701 ret = wl1271_chip_wakeup(wl);
702 if (ret < 0)
703 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 ret = wl1271_boot(wl);
706 if (ret < 0)
707 goto power_off;
708
709 ret = wl1271_plt_init(wl);
710 if (ret < 0)
711 goto irq_disable;
712
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200713 wl->state = WL1271_STATE_PLT;
714 wl1271_notice("firmware booted in PLT mode (%s)",
715 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 goto out;
717
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718irq_disable:
719 wl1271_disable_interrupts(wl);
720 mutex_unlock(&wl->mutex);
721 /* Unlocking the mutex in the middle of handling is
722 inherently unsafe. In this case we deem it safe to do,
723 because we need to let any possibly pending IRQ out of
724 the system (and while we are WL1271_STATE_OFF the IRQ
725 work function will not do anything.) Also, any other
726 possible concurrent operations will fail due to the
727 current state, hence the wl1271 struct should be safe. */
728 cancel_work_sync(&wl->irq_work);
729 mutex_lock(&wl->mutex);
730power_off:
731 wl1271_power_off(wl);
732 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 wl1271_error("firmware boot in PLT mode failed despite %d retries",
735 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736out:
737 mutex_unlock(&wl->mutex);
738
739 return ret;
740}
741
742int wl1271_plt_stop(struct wl1271 *wl)
743{
744 int ret = 0;
745
746 mutex_lock(&wl->mutex);
747
748 wl1271_notice("power down");
749
750 if (wl->state != WL1271_STATE_PLT) {
751 wl1271_error("cannot power down because not in PLT "
752 "state: %d", wl->state);
753 ret = -EBUSY;
754 goto out;
755 }
756
757 wl1271_disable_interrupts(wl);
758 wl1271_power_off(wl);
759
760 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300761 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
763out:
764 mutex_unlock(&wl->mutex);
765
766 return ret;
767}
768
769
770static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
771{
772 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200773 struct ieee80211_conf *conf = &hw->conf;
774 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
775 struct ieee80211_sta *sta = txinfo->control.sta;
776 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200778 /* peek into the rates configured in the STA entry */
779 spin_lock_irqsave(&wl->wl_lock, flags);
780 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
781 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
782 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
783 }
784 spin_unlock_irqrestore(&wl->wl_lock, flags);
785
786 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787 skb_queue_tail(&wl->tx_queue, skb);
788
789 /*
790 * The chip specific setup must run before the first TX packet -
791 * before that, the tx_work will not be initialized!
792 */
793
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300794 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795
796 /*
797 * The workqueue is slow to process the tx_queue and we need stop
798 * the queue here, otherwise the queue will get too long.
799 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200800 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
801 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200803 spin_lock_irqsave(&wl->wl_lock, flags);
804 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200805 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200806 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807 }
808
809 return NETDEV_TX_OK;
810}
811
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300812static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
813 void *arg)
814{
815 struct net_device *dev;
816 struct wireless_dev *wdev;
817 struct wiphy *wiphy;
818 struct ieee80211_hw *hw;
819 struct wl1271 *wl;
820 struct wl1271 *wl_temp;
821 struct in_device *idev;
822 struct in_ifaddr *ifa = arg;
823 int ret = 0;
824
825 /* FIXME: this ugly function should probably be implemented in the
826 * mac80211, and here should only be a simple callback handling actual
827 * setting of the filters. Now we need to dig up references to
828 * various structures to gain access to what we need.
829 * Also, because of this, there is no "initial" setting of the filter
830 * in "op_start", because we don't want to dig up struct net_device
831 * there - the filter will be set upon first change of the interface
832 * IP address. */
833
834 dev = ifa->ifa_dev->dev;
835
836 wdev = dev->ieee80211_ptr;
837 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200838 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300839
840 wiphy = wdev->wiphy;
841 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200842 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300843
844 hw = wiphy_priv(wiphy);
845 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200846 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300847
848 /* Check that the interface is one supported by this driver. */
849 wl_temp = hw->priv;
850 list_for_each_entry(wl, &wl_list, list) {
851 if (wl == wl_temp)
852 break;
853 }
854 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200855 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300856
857 /* Get the interface IP address for the device. "ifa" will become
858 NULL if:
859 - there is no IPV4 protocol address configured
860 - there are multiple (virtual) IPV4 addresses configured
861 When "ifa" is NULL, filtering will be disabled.
862 */
863 ifa = NULL;
864 idev = dev->ip_ptr;
865 if (idev)
866 ifa = idev->ifa_list;
867
868 if (ifa && ifa->ifa_next)
869 ifa = NULL;
870
871 mutex_lock(&wl->mutex);
872
873 if (wl->state == WL1271_STATE_OFF)
874 goto out;
875
876 ret = wl1271_ps_elp_wakeup(wl, false);
877 if (ret < 0)
878 goto out;
879 if (ifa)
880 ret = wl1271_acx_arp_ip_filter(wl, true,
881 (u8 *)&ifa->ifa_address,
882 ACX_IPV4_VERSION);
883 else
884 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
885 ACX_IPV4_VERSION);
886 wl1271_ps_elp_sleep(wl);
887
888out:
889 mutex_unlock(&wl->mutex);
890
Luciano Coelho17d72652009-11-23 23:22:15 +0200891 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300892}
893
894static struct notifier_block wl1271_dev_notifier = {
895 .notifier_call = wl1271_dev_notify,
896};
897
898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899static int wl1271_op_start(struct ieee80211_hw *hw)
900{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200901 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
902
903 /*
904 * We have to delay the booting of the hardware because
905 * we need to know the local MAC address before downloading and
906 * initializing the firmware. The MAC address cannot be changed
907 * after boot, and without the proper MAC address, the firmware
908 * will not function properly.
909 *
910 * The MAC address is first known when the corresponding interface
911 * is added. That is where we will initialize the hardware.
912 */
913
914 return 0;
915}
916
917static void wl1271_op_stop(struct ieee80211_hw *hw)
918{
919 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
920}
921
922static int wl1271_op_add_interface(struct ieee80211_hw *hw,
923 struct ieee80211_vif *vif)
924{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200926 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 int ret = 0;
928
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200929 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
930 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931
932 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200933 if (wl->vif) {
934 ret = -EBUSY;
935 goto out;
936 }
937
938 wl->vif = vif;
939
940 switch (vif->type) {
941 case NL80211_IFTYPE_STATION:
942 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200943 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200944 break;
945 case NL80211_IFTYPE_ADHOC:
946 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200947 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200948 break;
949 default:
950 ret = -EOPNOTSUPP;
951 goto out;
952 }
953
954 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
956 if (wl->state != WL1271_STATE_OFF) {
957 wl1271_error("cannot start because not in off state: %d",
958 wl->state);
959 ret = -EBUSY;
960 goto out;
961 }
962
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963 while (retries) {
964 retries--;
965 ret = wl1271_chip_wakeup(wl);
966 if (ret < 0)
967 goto power_off;
968
969 ret = wl1271_boot(wl);
970 if (ret < 0)
971 goto power_off;
972
973 ret = wl1271_hw_init(wl);
974 if (ret < 0)
975 goto irq_disable;
976
977 wl->state = WL1271_STATE_ON;
978 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 goto out;
980
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981irq_disable:
982 wl1271_disable_interrupts(wl);
983 mutex_unlock(&wl->mutex);
984 /* Unlocking the mutex in the middle of handling is
985 inherently unsafe. In this case we deem it safe to do,
986 because we need to let any possibly pending IRQ out of
987 the system (and while we are WL1271_STATE_OFF the IRQ
988 work function will not do anything.) Also, any other
989 possible concurrent operations will fail due to the
990 current state, hence the wl1271 struct should be safe. */
991 cancel_work_sync(&wl->irq_work);
992 mutex_lock(&wl->mutex);
993power_off:
994 wl1271_power_off(wl);
995 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997 wl1271_error("firmware boot failed despite %d retries",
998 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300999out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 mutex_unlock(&wl->mutex);
1001
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001002 if (!ret) {
1003 list_add(&wl->list, &wl_list);
1004 register_inetaddr_notifier(&wl1271_dev_notifier);
1005 }
1006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 return ret;
1008}
1009
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001010static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1011 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012{
1013 struct wl1271 *wl = hw->priv;
1014 int i;
1015
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001016 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1017
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001018 mutex_lock(&wl->mutex);
1019 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001021 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001023 list_del(&wl->list);
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 WARN_ON(wl->state != WL1271_STATE_ON);
1026
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001027 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 mutex_unlock(&wl->mutex);
1029 ieee80211_scan_completed(wl->hw, true);
1030 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 }
1032
1033 wl->state = WL1271_STATE_OFF;
1034
1035 wl1271_disable_interrupts(wl);
1036
1037 mutex_unlock(&wl->mutex);
1038
1039 cancel_work_sync(&wl->irq_work);
1040 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
1042 mutex_lock(&wl->mutex);
1043
1044 /* let's notify MAC80211 about the remaining pending TX frames */
1045 wl1271_tx_flush(wl);
1046 wl1271_power_off(wl);
1047
1048 memset(wl->bssid, 0, ETH_ALEN);
1049 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1050 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001052 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001053 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
1055 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001056 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1058 wl->tx_blocks_available = 0;
1059 wl->tx_results_count = 0;
1060 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001061 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001062 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 wl->time_offset = 0;
1064 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001065 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1066 wl->sta_rate_set = 0;
1067 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001068 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001069 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 for (i = 0; i < NUM_TX_QUEUES; i++)
1072 wl->tx_blocks_freed[i] = 0;
1073
1074 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001075
1076 kfree(wl->fw_status);
1077 wl->fw_status = NULL;
1078 kfree(wl->tx_res_if);
1079 wl->tx_res_if = NULL;
1080 kfree(wl->target_mem_map);
1081 wl->target_mem_map = NULL;
1082
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 mutex_unlock(&wl->mutex);
1084}
1085
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001086static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1087{
1088 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1089 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1090
1091 /* combine requested filters with current filter config */
1092 filters = wl->filters | filters;
1093
1094 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1095
1096 if (filters & FIF_PROMISC_IN_BSS) {
1097 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1098 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1099 wl->rx_config |= CFG_BSSID_FILTER_EN;
1100 }
1101 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1102 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1103 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1104 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1105 }
1106 if (filters & FIF_OTHER_BSS) {
1107 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1108 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1109 }
1110 if (filters & FIF_CONTROL) {
1111 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1112 wl->rx_filter |= CFG_RX_CTL_EN;
1113 }
1114 if (filters & FIF_FCSFAIL) {
1115 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1116 wl->rx_filter |= CFG_RX_FCS_ERROR;
1117 }
1118}
1119
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001120static int wl1271_join_channel(struct wl1271 *wl, int channel)
1121{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001122 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001123 /* we need to use a dummy BSSID for now */
1124 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1125 0xad, 0xbe, 0xef };
1126
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001127 wl->channel = channel;
1128 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1129
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001130 /* pass through frames from all BSS */
1131 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1132
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001133 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001134 if (ret < 0)
1135 goto out;
1136
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001137 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001138
1139out:
1140 return ret;
1141}
1142
1143static int wl1271_unjoin_channel(struct wl1271 *wl)
1144{
1145 int ret;
1146
1147 /* to stop listening to a channel, we disconnect */
1148 ret = wl1271_cmd_disconnect(wl);
1149 if (ret < 0)
1150 goto out;
1151
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001152 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001153 wl->channel = 0;
1154 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001155
1156 /* stop filterting packets based on bssid */
1157 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001158
1159out:
1160 return ret;
1161}
1162
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001163static void wl1271_set_band_rate(struct wl1271 *wl)
1164{
1165 if (wl->band == IEEE80211_BAND_2GHZ)
1166 wl->basic_rate_set = wl->conf.tx.basic_rate;
1167 else
1168 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1169}
1170
1171static u32 wl1271_min_rate_get(struct wl1271 *wl)
1172{
1173 int i;
1174 u32 rate = 0;
1175
1176 if (!wl->basic_rate_set) {
1177 WARN_ON(1);
1178 wl->basic_rate_set = wl->conf.tx.basic_rate;
1179 }
1180
1181 for (i = 0; !rate; i++) {
1182 if ((wl->basic_rate_set >> i) & 0x1)
1183 rate = 1 << i;
1184 }
1185
1186 return rate;
1187}
1188
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1190{
1191 struct wl1271 *wl = hw->priv;
1192 struct ieee80211_conf *conf = &hw->conf;
1193 int channel, ret = 0;
1194
1195 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1196
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001197 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 channel,
1199 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001200 conf->power_level,
1201 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202
1203 mutex_lock(&wl->mutex);
1204
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001205 if (unlikely(wl->state == WL1271_STATE_OFF))
1206 goto out;
1207
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001208 ret = wl1271_ps_elp_wakeup(wl, false);
1209 if (ret < 0)
1210 goto out;
1211
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001212 /* if the channel changes while joined, join again */
1213 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1214 wl->band = conf->channel->band;
1215 wl->channel = channel;
1216
1217 /*
1218 * FIXME: the mac80211 should really provide a fixed rate
1219 * to use here. for now, just use the smallest possible rate
1220 * for the band as a fixed rate for association frames and
1221 * other control messages.
1222 */
1223 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1224 wl1271_set_band_rate(wl);
1225
1226 wl->basic_rate = wl1271_min_rate_get(wl);
1227 ret = wl1271_acx_rate_policies(wl);
1228 if (ret < 0)
1229 wl1271_warning("rate policy for update channel "
1230 "failed %d", ret);
1231
1232 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1233 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1234 if (ret < 0)
1235 wl1271_warning("cmd join to update channel "
1236 "failed %d", ret);
1237 }
1238 }
1239
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001240 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001241 if (conf->flags & IEEE80211_CONF_IDLE &&
1242 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001243 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001244 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001245 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001246
1247 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001248 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001249 wl->sta_rate_set = 0;
1250 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001251 wl1271_acx_keep_alive_config(
1252 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1253 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinene1972812010-04-09 11:07:29 +03001254 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1255 } else
1256 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257 }
1258
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001259 if (conf->flags & IEEE80211_CONF_PS &&
1260 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1261 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
1263 /*
1264 * We enter PSM only if we're already associated.
1265 * If we're not, we'll enter it when joining an SSID,
1266 * through the bss_info_changed() hook.
1267 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001268 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001269 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001270 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1271 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001272 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001274 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001275 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001277 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001279 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001280 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1281 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282 }
1283
1284 if (conf->power_level != wl->power_level) {
1285 ret = wl1271_acx_tx_power(wl, conf->power_level);
1286 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001287 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288
1289 wl->power_level = conf->power_level;
1290 }
1291
1292out_sleep:
1293 wl1271_ps_elp_sleep(wl);
1294
1295out:
1296 mutex_unlock(&wl->mutex);
1297
1298 return ret;
1299}
1300
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001301struct wl1271_filter_params {
1302 bool enabled;
1303 int mc_list_length;
1304 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1305};
1306
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001307static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1308 struct dev_addr_list *mc_list)
1309{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001310 struct wl1271_filter_params *fp;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001311 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001312 int i;
1313
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001314 if (unlikely(wl->state == WL1271_STATE_OFF))
1315 return 0;
1316
Juuso Oikarinen74441132009-10-13 12:47:53 +03001317 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001318 if (!fp) {
1319 wl1271_error("Out of memory setting filters.");
1320 return 0;
1321 }
1322
1323 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001324 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001325 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1326 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001327 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001328 }
1329
1330 fp->mc_list_length = 0;
1331 for (i = 0; i < mc_count; i++) {
1332 if (mc_list->da_addrlen == ETH_ALEN) {
1333 memcpy(fp->mc_list[fp->mc_list_length],
1334 mc_list->da_addr, ETH_ALEN);
1335 fp->mc_list_length++;
1336 } else
1337 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001338 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001339 }
1340
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001341 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001342}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1345 FIF_ALLMULTI | \
1346 FIF_FCSFAIL | \
1347 FIF_BCN_PRBRESP_PROMISC | \
1348 FIF_CONTROL | \
1349 FIF_OTHER_BSS)
1350
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001351static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1352 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001353 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001355 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001357 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358
1359 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1360
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001361 mutex_lock(&wl->mutex);
1362
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001363 *total &= WL1271_SUPPORTED_FILTERS;
1364 changed &= WL1271_SUPPORTED_FILTERS;
1365
1366 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001367 goto out;
1368
1369 ret = wl1271_ps_elp_wakeup(wl, false);
1370 if (ret < 0)
1371 goto out;
1372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001374 if (*total & FIF_ALLMULTI)
1375 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1376 else if (fp)
1377 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1378 fp->mc_list,
1379 fp->mc_list_length);
1380 if (ret < 0)
1381 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383 /* determine, whether supported filter values have changed */
1384 if (changed == 0)
1385 goto out_sleep;
1386
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001387 /* configure filters */
1388 wl->filters = *total;
1389 wl1271_configure_filters(wl, 0);
1390
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001391 /* apply configured filters */
1392 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1393 if (ret < 0)
1394 goto out_sleep;
1395
1396out_sleep:
1397 wl1271_ps_elp_sleep(wl);
1398
1399out:
1400 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001401 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402}
1403
1404static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1405 struct ieee80211_vif *vif,
1406 struct ieee80211_sta *sta,
1407 struct ieee80211_key_conf *key_conf)
1408{
1409 struct wl1271 *wl = hw->priv;
1410 const u8 *addr;
1411 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001412 u32 tx_seq_32 = 0;
1413 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 u8 key_type;
1415
1416 static const u8 bcast_addr[ETH_ALEN] =
1417 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1418
1419 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1420
1421 addr = sta ? sta->addr : bcast_addr;
1422
1423 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1424 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1425 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1426 key_conf->alg, key_conf->keyidx,
1427 key_conf->keylen, key_conf->flags);
1428 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1429
1430 if (is_zero_ether_addr(addr)) {
1431 /* We dont support TX only encryption */
1432 ret = -EOPNOTSUPP;
1433 goto out;
1434 }
1435
1436 mutex_lock(&wl->mutex);
1437
1438 ret = wl1271_ps_elp_wakeup(wl, false);
1439 if (ret < 0)
1440 goto out_unlock;
1441
1442 switch (key_conf->alg) {
1443 case ALG_WEP:
1444 key_type = KEY_WEP;
1445
1446 key_conf->hw_key_idx = key_conf->keyidx;
1447 break;
1448 case ALG_TKIP:
1449 key_type = KEY_TKIP;
1450
1451 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001452 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1453 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 break;
1455 case ALG_CCMP:
1456 key_type = KEY_AES;
1457
1458 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001459 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1460 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 break;
1462 default:
1463 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1464
1465 ret = -EOPNOTSUPP;
1466 goto out_sleep;
1467 }
1468
1469 switch (cmd) {
1470 case SET_KEY:
1471 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1472 key_conf->keyidx, key_type,
1473 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001474 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475 if (ret < 0) {
1476 wl1271_error("Could not add or replace key");
1477 goto out_sleep;
1478 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001479
1480 /* the default WEP key needs to be configured at least once */
1481 if (key_type == KEY_WEP) {
1482 ret = wl1271_cmd_set_default_wep_key(wl,
1483 wl->default_key);
1484 if (ret < 0)
1485 goto out_sleep;
1486 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001487 break;
1488
1489 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001490 /* The wl1271 does not allow to remove unicast keys - they
1491 will be cleared automatically on next CMD_JOIN. Ignore the
1492 request silently, as we dont want the mac80211 to emit
1493 an error message. */
1494 if (!is_broadcast_ether_addr(addr))
1495 break;
1496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1498 key_conf->keyidx, key_type,
1499 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001500 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 if (ret < 0) {
1502 wl1271_error("Could not remove key");
1503 goto out_sleep;
1504 }
1505 break;
1506
1507 default:
1508 wl1271_error("Unsupported key cmd 0x%x", cmd);
1509 ret = -EOPNOTSUPP;
1510 goto out_sleep;
1511
1512 break;
1513 }
1514
1515out_sleep:
1516 wl1271_ps_elp_sleep(wl);
1517
1518out_unlock:
1519 mutex_unlock(&wl->mutex);
1520
1521out:
1522 return ret;
1523}
1524
1525static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001526 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 struct cfg80211_scan_request *req)
1528{
1529 struct wl1271 *wl = hw->priv;
1530 int ret;
1531 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001532 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
1534 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1535
1536 if (req->n_ssids) {
1537 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001538 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539 }
1540
1541 mutex_lock(&wl->mutex);
1542
1543 ret = wl1271_ps_elp_wakeup(wl, false);
1544 if (ret < 0)
1545 goto out;
1546
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001547 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001548 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1549 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001550 WL1271_SCAN_BAND_DUAL, 3);
1551 else
Kalle Valo818e3062010-03-18 12:26:35 +02001552 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1553 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001554 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001555
1556 wl1271_ps_elp_sleep(wl);
1557
1558out:
1559 mutex_unlock(&wl->mutex);
1560
1561 return ret;
1562}
1563
1564static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1565{
1566 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001567 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001568
1569 mutex_lock(&wl->mutex);
1570
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001571 if (unlikely(wl->state == WL1271_STATE_OFF))
1572 goto out;
1573
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 ret = wl1271_ps_elp_wakeup(wl, false);
1575 if (ret < 0)
1576 goto out;
1577
1578 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1579 if (ret < 0)
1580 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1581
1582 wl1271_ps_elp_sleep(wl);
1583
1584out:
1585 mutex_unlock(&wl->mutex);
1586
1587 return ret;
1588}
1589
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001590static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1591{
1592 u8 *ptr = beacon->data +
1593 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1594
1595 /* find the location of the ssid in the beacon */
1596 while (ptr < beacon->data + beacon->len) {
1597 if (ptr[0] == WLAN_EID_SSID) {
1598 wl->ssid_len = ptr[1];
1599 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1600 return;
1601 }
1602 ptr += ptr[1];
1603 }
1604 wl1271_error("ad-hoc beacon template has no SSID!\n");
1605}
1606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1608 struct ieee80211_vif *vif,
1609 struct ieee80211_bss_conf *bss_conf,
1610 u32 changed)
1611{
1612 enum wl1271_cmd_ps_mode mode;
1613 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001614 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001615 bool do_keepalive = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616 int ret;
1617
1618 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1619
1620 mutex_lock(&wl->mutex);
1621
1622 ret = wl1271_ps_elp_wakeup(wl, false);
1623 if (ret < 0)
1624 goto out;
1625
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001626 if ((changed && BSS_CHANGED_BEACON_INT) &&
1627 (wl->bss_type == BSS_TYPE_IBSS)) {
1628 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1629 bss_conf->beacon_int);
1630
1631 wl->beacon_int = bss_conf->beacon_int;
1632 do_join = true;
1633 }
1634
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001635 if ((changed && BSS_CHANGED_BEACON) &&
1636 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001637 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1638
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001639 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1640
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001641 if (beacon) {
1642 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001643
1644 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001645 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1646 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001647 beacon->len, 0,
1648 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001649
1650 if (ret < 0) {
1651 dev_kfree_skb(beacon);
1652 goto out_sleep;
1653 }
1654
1655 hdr = (struct ieee80211_hdr *) beacon->data;
1656 hdr->frame_control = cpu_to_le16(
1657 IEEE80211_FTYPE_MGMT |
1658 IEEE80211_STYPE_PROBE_RESP);
1659
1660 ret = wl1271_cmd_template_set(wl,
1661 CMD_TEMPL_PROBE_RESPONSE,
1662 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001663 beacon->len, 0,
1664 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001665 dev_kfree_skb(beacon);
1666 if (ret < 0)
1667 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001668
1669 /* Need to update the SSID (for filtering etc) */
1670 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001671 }
1672 }
1673
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001674 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1675 (wl->bss_type == BSS_TYPE_IBSS)) {
1676 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1677 bss_conf->enable_beacon ? "enabled" : "disabled");
1678
1679 if (bss_conf->enable_beacon)
1680 wl->set_bss_type = BSS_TYPE_IBSS;
1681 else
1682 wl->set_bss_type = BSS_TYPE_STA_BSS;
1683 do_join = true;
1684 }
1685
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001686 if (changed & BSS_CHANGED_CQM) {
1687 bool enable = false;
1688 if (bss_conf->cqm_rssi_thold)
1689 enable = true;
1690 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1691 bss_conf->cqm_rssi_thold,
1692 bss_conf->cqm_rssi_hyst);
1693 if (ret < 0)
1694 goto out;
1695 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1696 }
1697
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001698 if ((changed & BSS_CHANGED_BSSID) &&
1699 /*
1700 * Now we know the correct bssid, so we send a new join command
1701 * and enable the BSSID filter
1702 */
1703 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001704 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001705
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001706 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001707 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001708 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001709
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001710 /* filter out all packets not from this BSSID */
1711 wl1271_configure_filters(wl, 0);
1712
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001713 /* Need to update the BSSID (for filtering etc) */
1714 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001715 }
1716
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717 if (changed & BSS_CHANGED_ASSOC) {
1718 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001719 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001721 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001723 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001724 * use basic rates from AP, and determine lowest rate
1725 * to use with control frames.
1726 */
1727 rates = bss_conf->basic_rates;
1728 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1729 rates);
1730 wl->basic_rate = wl1271_min_rate_get(wl);
1731 ret = wl1271_acx_rate_policies(wl);
1732 if (ret < 0)
1733 goto out_sleep;
1734
1735 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001736 * with wl1271, we don't need to update the
1737 * beacon_int and dtim_period, because the firmware
1738 * updates it by itself when the first beacon is
1739 * received after a join.
1740 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001741 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1742 if (ret < 0)
1743 goto out_sleep;
1744
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001745 /*
1746 * The SSID is intentionally set to NULL here - the
1747 * firmware will set the probe request with a
1748 * broadcast SSID regardless of what we set in the
1749 * template.
1750 */
1751 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1752 NULL, 0, wl->band);
1753
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001754 /* Enable the keep-alive feature */
1755 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001756 if (ret < 0)
1757 goto out_sleep;
1758
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001759 /*
1760 * This is awkward. The keep-alive configs must be done
1761 * *after* the join command, because otherwise it will
1762 * not work, but it must only be done *once* because
1763 * otherwise the firmware will start complaining.
1764 */
1765 do_keepalive = true;
1766
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001767 /* enable the connection monitoring feature */
1768 ret = wl1271_acx_conn_monit_params(wl, true);
1769 if (ret < 0)
1770 goto out_sleep;
1771
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001773 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1774 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001776 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001777 if (ret < 0)
1778 goto out_sleep;
1779 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001780 } else {
1781 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001782 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001783 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001784
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001785 /* revert back to minimum rates for the current band */
1786 wl1271_set_band_rate(wl);
1787 wl->basic_rate = wl1271_min_rate_get(wl);
1788 ret = wl1271_acx_rate_policies(wl);
1789 if (ret < 0)
1790 goto out_sleep;
1791
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001792 /* disable connection monitor features */
1793 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001794
1795 /* Disable the keep-alive feature */
1796 ret = wl1271_acx_keep_alive_mode(wl, false);
1797
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001798 if (ret < 0)
1799 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001803
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804 if (changed & BSS_CHANGED_ERP_SLOT) {
1805 if (bss_conf->use_short_slot)
1806 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1807 else
1808 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1809 if (ret < 0) {
1810 wl1271_warning("Set slot time failed %d", ret);
1811 goto out_sleep;
1812 }
1813 }
1814
1815 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1816 if (bss_conf->use_short_preamble)
1817 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1818 else
1819 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1820 }
1821
1822 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1823 if (bss_conf->use_cts_prot)
1824 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1825 else
1826 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1827 if (ret < 0) {
1828 wl1271_warning("Set ctsprotect failed %d", ret);
1829 goto out_sleep;
1830 }
1831 }
1832
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001833 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001834 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001835 if (ret < 0) {
1836 wl1271_warning("cmd join failed %d", ret);
1837 goto out_sleep;
1838 }
1839 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1840 }
1841
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001842 /*
1843 * The JOIN operation shuts down the firmware keep-alive as a side
1844 * effect, and the ACX_AID will start the keep-alive as a side effect.
1845 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1846 * JOIN operation, and the template config after the ACX_AID.
1847 */
1848 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1849 ret = wl1271_acx_aid(wl, wl->aid);
1850 if (ret < 0)
1851 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001852 }
1853
1854 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001855 ret = wl1271_cmd_build_klv_null_data(wl);
1856 if (ret < 0)
1857 goto out_sleep;
1858 ret = wl1271_acx_keep_alive_config(
1859 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1860 ACX_KEEP_ALIVE_TPL_VALID);
1861 if (ret < 0)
1862 goto out_sleep;
1863 }
1864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865out_sleep:
1866 wl1271_ps_elp_sleep(wl);
1867
1868out:
1869 mutex_unlock(&wl->mutex);
1870}
1871
Kalle Valoc6999d82010-02-18 13:25:41 +02001872static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1873 const struct ieee80211_tx_queue_params *params)
1874{
1875 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001876 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001877 int ret;
1878
1879 mutex_lock(&wl->mutex);
1880
1881 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1882
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001883 ret = wl1271_ps_elp_wakeup(wl, false);
1884 if (ret < 0)
1885 goto out;
1886
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001887 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001888 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1889 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001890 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001891 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001892 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001893
Kalle Valo4695dc92010-03-18 12:26:38 +02001894 if (params->uapsd)
1895 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1896 else
1897 ps_scheme = CONF_PS_SCHEME_LEGACY;
1898
Kalle Valoc6999d82010-02-18 13:25:41 +02001899 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1900 CONF_CHANNEL_TYPE_EDCF,
1901 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001902 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001903 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001904 goto out_sleep;
1905
1906out_sleep:
1907 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001908
1909out:
1910 mutex_unlock(&wl->mutex);
1911
1912 return ret;
1913}
1914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001915
1916/* can't be const, mac80211 writes to this */
1917static struct ieee80211_rate wl1271_rates[] = {
1918 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001919 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1920 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001921 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001922 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1923 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1925 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001926 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1927 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1929 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001930 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1931 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001932 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1933 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001934 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1935 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001936 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001937 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1938 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001939 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001940 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1941 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001942 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001943 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1944 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001946 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1947 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001949 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1950 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001952 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1953 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001955 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1956 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957};
1958
1959/* can't be const, mac80211 writes to this */
1960static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001961 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1962 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1963 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1964 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1965 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1966 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1967 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1968 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1969 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1970 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1971 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1972 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1973 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974};
1975
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001976/* mapping to indexes for wl1271_rates */
1977const static u8 wl1271_rate_to_idx_2ghz[] = {
1978 /* MCS rates are used only with 11n */
1979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1980 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1981 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1982 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1983 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1984 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1985 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1986 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1987
1988 11, /* CONF_HW_RXTX_RATE_54 */
1989 10, /* CONF_HW_RXTX_RATE_48 */
1990 9, /* CONF_HW_RXTX_RATE_36 */
1991 8, /* CONF_HW_RXTX_RATE_24 */
1992
1993 /* TI-specific rate */
1994 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1995
1996 7, /* CONF_HW_RXTX_RATE_18 */
1997 6, /* CONF_HW_RXTX_RATE_12 */
1998 3, /* CONF_HW_RXTX_RATE_11 */
1999 5, /* CONF_HW_RXTX_RATE_9 */
2000 4, /* CONF_HW_RXTX_RATE_6 */
2001 2, /* CONF_HW_RXTX_RATE_5_5 */
2002 1, /* CONF_HW_RXTX_RATE_2 */
2003 0 /* CONF_HW_RXTX_RATE_1 */
2004};
2005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002006/* can't be const, mac80211 writes to this */
2007static struct ieee80211_supported_band wl1271_band_2ghz = {
2008 .channels = wl1271_channels,
2009 .n_channels = ARRAY_SIZE(wl1271_channels),
2010 .bitrates = wl1271_rates,
2011 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2012};
2013
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002014/* 5 GHz data rates for WL1273 */
2015static struct ieee80211_rate wl1271_rates_5ghz[] = {
2016 { .bitrate = 60,
2017 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2018 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2019 { .bitrate = 90,
2020 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2021 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2022 { .bitrate = 120,
2023 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2024 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2025 { .bitrate = 180,
2026 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2027 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2028 { .bitrate = 240,
2029 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2030 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2031 { .bitrate = 360,
2032 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2033 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2034 { .bitrate = 480,
2035 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2036 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2037 { .bitrate = 540,
2038 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2039 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2040};
2041
2042/* 5 GHz band channels for WL1273 */
2043static struct ieee80211_channel wl1271_channels_5ghz[] = {
2044 { .hw_value = 183, .center_freq = 4915},
2045 { .hw_value = 184, .center_freq = 4920},
2046 { .hw_value = 185, .center_freq = 4925},
2047 { .hw_value = 187, .center_freq = 4935},
2048 { .hw_value = 188, .center_freq = 4940},
2049 { .hw_value = 189, .center_freq = 4945},
2050 { .hw_value = 192, .center_freq = 4960},
2051 { .hw_value = 196, .center_freq = 4980},
2052 { .hw_value = 7, .center_freq = 5035},
2053 { .hw_value = 8, .center_freq = 5040},
2054 { .hw_value = 9, .center_freq = 5045},
2055 { .hw_value = 11, .center_freq = 5055},
2056 { .hw_value = 12, .center_freq = 5060},
2057 { .hw_value = 16, .center_freq = 5080},
2058 { .hw_value = 34, .center_freq = 5170},
2059 { .hw_value = 36, .center_freq = 5180},
2060 { .hw_value = 38, .center_freq = 5190},
2061 { .hw_value = 40, .center_freq = 5200},
2062 { .hw_value = 42, .center_freq = 5210},
2063 { .hw_value = 44, .center_freq = 5220},
2064 { .hw_value = 46, .center_freq = 5230},
2065 { .hw_value = 48, .center_freq = 5240},
2066 { .hw_value = 52, .center_freq = 5260},
2067 { .hw_value = 56, .center_freq = 5280},
2068 { .hw_value = 60, .center_freq = 5300},
2069 { .hw_value = 64, .center_freq = 5320},
2070 { .hw_value = 100, .center_freq = 5500},
2071 { .hw_value = 104, .center_freq = 5520},
2072 { .hw_value = 108, .center_freq = 5540},
2073 { .hw_value = 112, .center_freq = 5560},
2074 { .hw_value = 116, .center_freq = 5580},
2075 { .hw_value = 120, .center_freq = 5600},
2076 { .hw_value = 124, .center_freq = 5620},
2077 { .hw_value = 128, .center_freq = 5640},
2078 { .hw_value = 132, .center_freq = 5660},
2079 { .hw_value = 136, .center_freq = 5680},
2080 { .hw_value = 140, .center_freq = 5700},
2081 { .hw_value = 149, .center_freq = 5745},
2082 { .hw_value = 153, .center_freq = 5765},
2083 { .hw_value = 157, .center_freq = 5785},
2084 { .hw_value = 161, .center_freq = 5805},
2085 { .hw_value = 165, .center_freq = 5825},
2086};
2087
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002088/* mapping to indexes for wl1271_rates_5ghz */
2089const static u8 wl1271_rate_to_idx_5ghz[] = {
2090 /* MCS rates are used only with 11n */
2091 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2092 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2094 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2095 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2096 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2099
2100 7, /* CONF_HW_RXTX_RATE_54 */
2101 6, /* CONF_HW_RXTX_RATE_48 */
2102 5, /* CONF_HW_RXTX_RATE_36 */
2103 4, /* CONF_HW_RXTX_RATE_24 */
2104
2105 /* TI-specific rate */
2106 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2107
2108 3, /* CONF_HW_RXTX_RATE_18 */
2109 2, /* CONF_HW_RXTX_RATE_12 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2111 1, /* CONF_HW_RXTX_RATE_9 */
2112 0, /* CONF_HW_RXTX_RATE_6 */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2115 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2116};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002117
2118static struct ieee80211_supported_band wl1271_band_5ghz = {
2119 .channels = wl1271_channels_5ghz,
2120 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2121 .bitrates = wl1271_rates_5ghz,
2122 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2123};
2124
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002125const static u8 *wl1271_band_rate_to_idx[] = {
2126 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2127 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2128};
2129
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130static const struct ieee80211_ops wl1271_ops = {
2131 .start = wl1271_op_start,
2132 .stop = wl1271_op_stop,
2133 .add_interface = wl1271_op_add_interface,
2134 .remove_interface = wl1271_op_remove_interface,
2135 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002136 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137 .configure_filter = wl1271_op_configure_filter,
2138 .tx = wl1271_op_tx,
2139 .set_key = wl1271_op_set_key,
2140 .hw_scan = wl1271_op_hw_scan,
2141 .bss_info_changed = wl1271_op_bss_info_changed,
2142 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002143 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002144 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145};
2146
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002147
2148u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2149{
2150 u8 idx;
2151
2152 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2153
2154 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2155 wl1271_error("Illegal RX rate from HW: %d", rate);
2156 return 0;
2157 }
2158
2159 idx = wl1271_band_rate_to_idx[wl->band][rate];
2160 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2161 wl1271_error("Unsupported RX rate from HW: %d", rate);
2162 return 0;
2163 }
2164
2165 return idx;
2166}
2167
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002168static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2169 struct device_attribute *attr,
2170 char *buf)
2171{
2172 struct wl1271 *wl = dev_get_drvdata(dev);
2173 ssize_t len;
2174
2175 /* FIXME: what's the maximum length of buf? page size?*/
2176 len = 500;
2177
2178 mutex_lock(&wl->mutex);
2179 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2180 wl->sg_enabled);
2181 mutex_unlock(&wl->mutex);
2182
2183 return len;
2184
2185}
2186
2187static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2188 struct device_attribute *attr,
2189 const char *buf, size_t count)
2190{
2191 struct wl1271 *wl = dev_get_drvdata(dev);
2192 unsigned long res;
2193 int ret;
2194
2195 ret = strict_strtoul(buf, 10, &res);
2196
2197 if (ret < 0) {
2198 wl1271_warning("incorrect value written to bt_coex_mode");
2199 return count;
2200 }
2201
2202 mutex_lock(&wl->mutex);
2203
2204 res = !!res;
2205
2206 if (res == wl->sg_enabled)
2207 goto out;
2208
2209 wl->sg_enabled = res;
2210
2211 if (wl->state == WL1271_STATE_OFF)
2212 goto out;
2213
2214 ret = wl1271_ps_elp_wakeup(wl, false);
2215 if (ret < 0)
2216 goto out;
2217
2218 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2219 wl1271_ps_elp_sleep(wl);
2220
2221 out:
2222 mutex_unlock(&wl->mutex);
2223 return count;
2224}
2225
2226static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2227 wl1271_sysfs_show_bt_coex_state,
2228 wl1271_sysfs_store_bt_coex_state);
2229
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002230int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231{
2232 int ret;
2233
2234 if (wl->mac80211_registered)
2235 return 0;
2236
2237 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2238
2239 ret = ieee80211_register_hw(wl->hw);
2240 if (ret < 0) {
2241 wl1271_error("unable to register mac80211 hw: %d", ret);
2242 return ret;
2243 }
2244
2245 wl->mac80211_registered = true;
2246
2247 wl1271_notice("loaded");
2248
2249 return 0;
2250}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002251EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002252
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002253void wl1271_unregister_hw(struct wl1271 *wl)
2254{
2255 ieee80211_unregister_hw(wl->hw);
2256 wl->mac80211_registered = false;
2257
2258}
2259EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2260
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002261int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002263 /* The tx descriptor buffer and the TKIP space. */
2264 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2265 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002266
2267 /* unit us */
2268 /* FIXME: find a proper value */
2269 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002270 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271
2272 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002273 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002274 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002275 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002276 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002277 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002278 IEEE80211_HW_CONNECTION_MONITOR |
2279 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002280
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002281 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2282 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283 wl->hw->wiphy->max_scan_ssids = 1;
2284 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2285
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002286 if (wl1271_11a_enabled())
2287 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2288
Kalle Valo12bd8942010-03-18 12:26:33 +02002289 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002290 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002291
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002292 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293
2294 return 0;
2295}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002296EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002299
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002300struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002303 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002304 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002305 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306
2307 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2308 if (!hw) {
2309 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002310 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002311 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312 }
2313
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002314 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2315 if (!plat_dev) {
2316 wl1271_error("could not allocate platform_device");
2317 ret = -ENOMEM;
2318 goto err_plat_alloc;
2319 }
2320
2321 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2322
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323 wl = hw->priv;
2324 memset(wl, 0, sizeof(*wl));
2325
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002326 INIT_LIST_HEAD(&wl->list);
2327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002329 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002330
2331 skb_queue_head_init(&wl->tx_queue);
2332
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002333 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002335 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337 wl->rx_counter = 0;
2338 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2339 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002340 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002342 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002343 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002344 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2345 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002346 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002347 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002348 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002349 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002351 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352 wl->tx_frames[i] = NULL;
2353
2354 spin_lock_init(&wl->wl_lock);
2355
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 wl->state = WL1271_STATE_OFF;
2357 mutex_init(&wl->mutex);
2358
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002359 /* Apply default driver configuration. */
2360 wl1271_conf_init(wl);
2361
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002362 wl1271_debugfs_init(wl);
2363
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002364 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002365 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002366 if (ret) {
2367 wl1271_error("couldn't register platform device");
2368 goto err_hw;
2369 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002370 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002371
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002372 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002373 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002374 if (ret < 0) {
2375 wl1271_error("failed to create sysfs file bt_coex_state");
2376 goto err_platform;
2377 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002378
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002379 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002380
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002381err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002382 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002383
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002384err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002385 wl1271_debugfs_exit(wl);
2386 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002387
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002388err_plat_alloc:
2389 ieee80211_free_hw(hw);
2390
2391err_hw_alloc:
2392
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002393 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002394}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002395EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002396
2397int wl1271_free_hw(struct wl1271 *wl)
2398{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002399 platform_device_unregister(wl->plat_dev);
2400 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002401
2402 wl1271_debugfs_exit(wl);
2403
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002404 vfree(wl->fw);
2405 wl->fw = NULL;
2406 kfree(wl->nvs);
2407 wl->nvs = NULL;
2408
2409 kfree(wl->fw_status);
2410 kfree(wl->tx_res_if);
2411
2412 ieee80211_free_hw(wl->hw);
2413
2414 return 0;
2415}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002416EXPORT_SYMBOL_GPL(wl1271_free_hw);
2417
2418MODULE_LICENSE("GPL");
2419MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2420MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");