blob: 283d5dade1ae194fb255c7d8d14a3002d12e004e [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,
1526 struct cfg80211_scan_request *req)
1527{
1528 struct wl1271 *wl = hw->priv;
1529 int ret;
1530 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001531 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532
1533 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1534
1535 if (req->n_ssids) {
1536 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001537 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538 }
1539
1540 mutex_lock(&wl->mutex);
1541
1542 ret = wl1271_ps_elp_wakeup(wl, false);
1543 if (ret < 0)
1544 goto out;
1545
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001546 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001547 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1548 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001549 WL1271_SCAN_BAND_DUAL, 3);
1550 else
Kalle Valo818e3062010-03-18 12:26:35 +02001551 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1552 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001553 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554
1555 wl1271_ps_elp_sleep(wl);
1556
1557out:
1558 mutex_unlock(&wl->mutex);
1559
1560 return ret;
1561}
1562
1563static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1564{
1565 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001566 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001567
1568 mutex_lock(&wl->mutex);
1569
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001570 if (unlikely(wl->state == WL1271_STATE_OFF))
1571 goto out;
1572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573 ret = wl1271_ps_elp_wakeup(wl, false);
1574 if (ret < 0)
1575 goto out;
1576
1577 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1578 if (ret < 0)
1579 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1580
1581 wl1271_ps_elp_sleep(wl);
1582
1583out:
1584 mutex_unlock(&wl->mutex);
1585
1586 return ret;
1587}
1588
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001589static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1590{
1591 u8 *ptr = beacon->data +
1592 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1593
1594 /* find the location of the ssid in the beacon */
1595 while (ptr < beacon->data + beacon->len) {
1596 if (ptr[0] == WLAN_EID_SSID) {
1597 wl->ssid_len = ptr[1];
1598 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1599 return;
1600 }
1601 ptr += ptr[1];
1602 }
1603 wl1271_error("ad-hoc beacon template has no SSID!\n");
1604}
1605
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001606static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1607 struct ieee80211_vif *vif,
1608 struct ieee80211_bss_conf *bss_conf,
1609 u32 changed)
1610{
1611 enum wl1271_cmd_ps_mode mode;
1612 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001613 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001614 bool do_keepalive = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615 int ret;
1616
1617 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1618
1619 mutex_lock(&wl->mutex);
1620
1621 ret = wl1271_ps_elp_wakeup(wl, false);
1622 if (ret < 0)
1623 goto out;
1624
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001625 if ((changed && BSS_CHANGED_BEACON_INT) &&
1626 (wl->bss_type == BSS_TYPE_IBSS)) {
1627 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1628 bss_conf->beacon_int);
1629
1630 wl->beacon_int = bss_conf->beacon_int;
1631 do_join = true;
1632 }
1633
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001634 if ((changed && BSS_CHANGED_BEACON) &&
1635 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001636 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1637
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001638 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1639
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001640 if (beacon) {
1641 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001642
1643 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001644 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1645 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001646 beacon->len, 0,
1647 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001648
1649 if (ret < 0) {
1650 dev_kfree_skb(beacon);
1651 goto out_sleep;
1652 }
1653
1654 hdr = (struct ieee80211_hdr *) beacon->data;
1655 hdr->frame_control = cpu_to_le16(
1656 IEEE80211_FTYPE_MGMT |
1657 IEEE80211_STYPE_PROBE_RESP);
1658
1659 ret = wl1271_cmd_template_set(wl,
1660 CMD_TEMPL_PROBE_RESPONSE,
1661 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001662 beacon->len, 0,
1663 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001664 dev_kfree_skb(beacon);
1665 if (ret < 0)
1666 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001667
1668 /* Need to update the SSID (for filtering etc) */
1669 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001670 }
1671 }
1672
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001673 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1674 (wl->bss_type == BSS_TYPE_IBSS)) {
1675 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1676 bss_conf->enable_beacon ? "enabled" : "disabled");
1677
1678 if (bss_conf->enable_beacon)
1679 wl->set_bss_type = BSS_TYPE_IBSS;
1680 else
1681 wl->set_bss_type = BSS_TYPE_STA_BSS;
1682 do_join = true;
1683 }
1684
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001685 if (changed & BSS_CHANGED_CQM) {
1686 bool enable = false;
1687 if (bss_conf->cqm_rssi_thold)
1688 enable = true;
1689 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1690 bss_conf->cqm_rssi_thold,
1691 bss_conf->cqm_rssi_hyst);
1692 if (ret < 0)
1693 goto out;
1694 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1695 }
1696
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001697 if ((changed & BSS_CHANGED_BSSID) &&
1698 /*
1699 * Now we know the correct bssid, so we send a new join command
1700 * and enable the BSSID filter
1701 */
1702 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001703 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001704
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001705 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001706 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001707 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001708
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001709 /* filter out all packets not from this BSSID */
1710 wl1271_configure_filters(wl, 0);
1711
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001712 /* Need to update the BSSID (for filtering etc) */
1713 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001714 }
1715
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001716 if (changed & BSS_CHANGED_ASSOC) {
1717 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001718 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001719 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001720 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001721
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001722 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001723 * use basic rates from AP, and determine lowest rate
1724 * to use with control frames.
1725 */
1726 rates = bss_conf->basic_rates;
1727 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1728 rates);
1729 wl->basic_rate = wl1271_min_rate_get(wl);
1730 ret = wl1271_acx_rate_policies(wl);
1731 if (ret < 0)
1732 goto out_sleep;
1733
1734 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001735 * with wl1271, we don't need to update the
1736 * beacon_int and dtim_period, because the firmware
1737 * updates it by itself when the first beacon is
1738 * received after a join.
1739 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001740 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1741 if (ret < 0)
1742 goto out_sleep;
1743
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001744 /*
1745 * The SSID is intentionally set to NULL here - the
1746 * firmware will set the probe request with a
1747 * broadcast SSID regardless of what we set in the
1748 * template.
1749 */
1750 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1751 NULL, 0, wl->band);
1752
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001753 /* Enable the keep-alive feature */
1754 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755 if (ret < 0)
1756 goto out_sleep;
1757
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001758 /*
1759 * This is awkward. The keep-alive configs must be done
1760 * *after* the join command, because otherwise it will
1761 * not work, but it must only be done *once* because
1762 * otherwise the firmware will start complaining.
1763 */
1764 do_keepalive = true;
1765
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001766 /* enable the connection monitoring feature */
1767 ret = wl1271_acx_conn_monit_params(wl, true);
1768 if (ret < 0)
1769 goto out_sleep;
1770
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001772 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1773 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001774 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001775 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001776 if (ret < 0)
1777 goto out_sleep;
1778 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001779 } else {
1780 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001781 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001782 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001783
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001784 /* revert back to minimum rates for the current band */
1785 wl1271_set_band_rate(wl);
1786 wl->basic_rate = wl1271_min_rate_get(wl);
1787 ret = wl1271_acx_rate_policies(wl);
1788 if (ret < 0)
1789 goto out_sleep;
1790
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001791 /* disable connection monitor features */
1792 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001793
1794 /* Disable the keep-alive feature */
1795 ret = wl1271_acx_keep_alive_mode(wl, false);
1796
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001797 if (ret < 0)
1798 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 if (changed & BSS_CHANGED_ERP_SLOT) {
1804 if (bss_conf->use_short_slot)
1805 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1806 else
1807 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1808 if (ret < 0) {
1809 wl1271_warning("Set slot time failed %d", ret);
1810 goto out_sleep;
1811 }
1812 }
1813
1814 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1815 if (bss_conf->use_short_preamble)
1816 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1817 else
1818 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1819 }
1820
1821 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1822 if (bss_conf->use_cts_prot)
1823 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1824 else
1825 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1826 if (ret < 0) {
1827 wl1271_warning("Set ctsprotect failed %d", ret);
1828 goto out_sleep;
1829 }
1830 }
1831
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001832 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001833 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001834 if (ret < 0) {
1835 wl1271_warning("cmd join failed %d", ret);
1836 goto out_sleep;
1837 }
1838 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1839 }
1840
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001841 /*
1842 * The JOIN operation shuts down the firmware keep-alive as a side
1843 * effect, and the ACX_AID will start the keep-alive as a side effect.
1844 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1845 * JOIN operation, and the template config after the ACX_AID.
1846 */
1847 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1848 ret = wl1271_acx_aid(wl, wl->aid);
1849 if (ret < 0)
1850 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001851 }
1852
1853 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001854 ret = wl1271_cmd_build_klv_null_data(wl);
1855 if (ret < 0)
1856 goto out_sleep;
1857 ret = wl1271_acx_keep_alive_config(
1858 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1859 ACX_KEEP_ALIVE_TPL_VALID);
1860 if (ret < 0)
1861 goto out_sleep;
1862 }
1863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001864out_sleep:
1865 wl1271_ps_elp_sleep(wl);
1866
1867out:
1868 mutex_unlock(&wl->mutex);
1869}
1870
Kalle Valoc6999d82010-02-18 13:25:41 +02001871static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1872 const struct ieee80211_tx_queue_params *params)
1873{
1874 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001875 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001876 int ret;
1877
1878 mutex_lock(&wl->mutex);
1879
1880 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1881
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001882 ret = wl1271_ps_elp_wakeup(wl, false);
1883 if (ret < 0)
1884 goto out;
1885
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001886 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001887 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1888 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001889 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001890 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001891 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001892
Kalle Valo4695dc92010-03-18 12:26:38 +02001893 if (params->uapsd)
1894 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1895 else
1896 ps_scheme = CONF_PS_SCHEME_LEGACY;
1897
Kalle Valoc6999d82010-02-18 13:25:41 +02001898 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1899 CONF_CHANNEL_TYPE_EDCF,
1900 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001901 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001902 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001903 goto out_sleep;
1904
1905out_sleep:
1906 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001907
1908out:
1909 mutex_unlock(&wl->mutex);
1910
1911 return ret;
1912}
1913
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914
1915/* can't be const, mac80211 writes to this */
1916static struct ieee80211_rate wl1271_rates[] = {
1917 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001918 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1919 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001921 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1922 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001923 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1924 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001925 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1926 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1928 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001929 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1930 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1932 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001933 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1934 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001936 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1937 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001939 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1940 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001945 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1946 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001948 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1949 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001951 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1952 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001954 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1955 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956};
1957
1958/* can't be const, mac80211 writes to this */
1959static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001960 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1961 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1962 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1963 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1964 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1965 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1966 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1967 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1968 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1969 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1970 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1971 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1972 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973};
1974
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001975/* mapping to indexes for wl1271_rates */
1976const static u8 wl1271_rate_to_idx_2ghz[] = {
1977 /* MCS rates are used only with 11n */
1978 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1980 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1981 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1982 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1983 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1984 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1985 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1986
1987 11, /* CONF_HW_RXTX_RATE_54 */
1988 10, /* CONF_HW_RXTX_RATE_48 */
1989 9, /* CONF_HW_RXTX_RATE_36 */
1990 8, /* CONF_HW_RXTX_RATE_24 */
1991
1992 /* TI-specific rate */
1993 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1994
1995 7, /* CONF_HW_RXTX_RATE_18 */
1996 6, /* CONF_HW_RXTX_RATE_12 */
1997 3, /* CONF_HW_RXTX_RATE_11 */
1998 5, /* CONF_HW_RXTX_RATE_9 */
1999 4, /* CONF_HW_RXTX_RATE_6 */
2000 2, /* CONF_HW_RXTX_RATE_5_5 */
2001 1, /* CONF_HW_RXTX_RATE_2 */
2002 0 /* CONF_HW_RXTX_RATE_1 */
2003};
2004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005/* can't be const, mac80211 writes to this */
2006static struct ieee80211_supported_band wl1271_band_2ghz = {
2007 .channels = wl1271_channels,
2008 .n_channels = ARRAY_SIZE(wl1271_channels),
2009 .bitrates = wl1271_rates,
2010 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2011};
2012
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002013/* 5 GHz data rates for WL1273 */
2014static struct ieee80211_rate wl1271_rates_5ghz[] = {
2015 { .bitrate = 60,
2016 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2017 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2018 { .bitrate = 90,
2019 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2020 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2021 { .bitrate = 120,
2022 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2023 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2024 { .bitrate = 180,
2025 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2026 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2027 { .bitrate = 240,
2028 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2029 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2030 { .bitrate = 360,
2031 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2032 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2033 { .bitrate = 480,
2034 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2035 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2036 { .bitrate = 540,
2037 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2038 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2039};
2040
2041/* 5 GHz band channels for WL1273 */
2042static struct ieee80211_channel wl1271_channels_5ghz[] = {
2043 { .hw_value = 183, .center_freq = 4915},
2044 { .hw_value = 184, .center_freq = 4920},
2045 { .hw_value = 185, .center_freq = 4925},
2046 { .hw_value = 187, .center_freq = 4935},
2047 { .hw_value = 188, .center_freq = 4940},
2048 { .hw_value = 189, .center_freq = 4945},
2049 { .hw_value = 192, .center_freq = 4960},
2050 { .hw_value = 196, .center_freq = 4980},
2051 { .hw_value = 7, .center_freq = 5035},
2052 { .hw_value = 8, .center_freq = 5040},
2053 { .hw_value = 9, .center_freq = 5045},
2054 { .hw_value = 11, .center_freq = 5055},
2055 { .hw_value = 12, .center_freq = 5060},
2056 { .hw_value = 16, .center_freq = 5080},
2057 { .hw_value = 34, .center_freq = 5170},
2058 { .hw_value = 36, .center_freq = 5180},
2059 { .hw_value = 38, .center_freq = 5190},
2060 { .hw_value = 40, .center_freq = 5200},
2061 { .hw_value = 42, .center_freq = 5210},
2062 { .hw_value = 44, .center_freq = 5220},
2063 { .hw_value = 46, .center_freq = 5230},
2064 { .hw_value = 48, .center_freq = 5240},
2065 { .hw_value = 52, .center_freq = 5260},
2066 { .hw_value = 56, .center_freq = 5280},
2067 { .hw_value = 60, .center_freq = 5300},
2068 { .hw_value = 64, .center_freq = 5320},
2069 { .hw_value = 100, .center_freq = 5500},
2070 { .hw_value = 104, .center_freq = 5520},
2071 { .hw_value = 108, .center_freq = 5540},
2072 { .hw_value = 112, .center_freq = 5560},
2073 { .hw_value = 116, .center_freq = 5580},
2074 { .hw_value = 120, .center_freq = 5600},
2075 { .hw_value = 124, .center_freq = 5620},
2076 { .hw_value = 128, .center_freq = 5640},
2077 { .hw_value = 132, .center_freq = 5660},
2078 { .hw_value = 136, .center_freq = 5680},
2079 { .hw_value = 140, .center_freq = 5700},
2080 { .hw_value = 149, .center_freq = 5745},
2081 { .hw_value = 153, .center_freq = 5765},
2082 { .hw_value = 157, .center_freq = 5785},
2083 { .hw_value = 161, .center_freq = 5805},
2084 { .hw_value = 165, .center_freq = 5825},
2085};
2086
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002087/* mapping to indexes for wl1271_rates_5ghz */
2088const static u8 wl1271_rate_to_idx_5ghz[] = {
2089 /* MCS rates are used only with 11n */
2090 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2091 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2092 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2093 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2094 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2095 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2096 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2098
2099 7, /* CONF_HW_RXTX_RATE_54 */
2100 6, /* CONF_HW_RXTX_RATE_48 */
2101 5, /* CONF_HW_RXTX_RATE_36 */
2102 4, /* CONF_HW_RXTX_RATE_24 */
2103
2104 /* TI-specific rate */
2105 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2106
2107 3, /* CONF_HW_RXTX_RATE_18 */
2108 2, /* CONF_HW_RXTX_RATE_12 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2110 1, /* CONF_HW_RXTX_RATE_9 */
2111 0, /* CONF_HW_RXTX_RATE_6 */
2112 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2115};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002116
2117static struct ieee80211_supported_band wl1271_band_5ghz = {
2118 .channels = wl1271_channels_5ghz,
2119 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2120 .bitrates = wl1271_rates_5ghz,
2121 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2122};
2123
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002124const static u8 *wl1271_band_rate_to_idx[] = {
2125 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2126 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2127};
2128
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002129static const struct ieee80211_ops wl1271_ops = {
2130 .start = wl1271_op_start,
2131 .stop = wl1271_op_stop,
2132 .add_interface = wl1271_op_add_interface,
2133 .remove_interface = wl1271_op_remove_interface,
2134 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002135 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002136 .configure_filter = wl1271_op_configure_filter,
2137 .tx = wl1271_op_tx,
2138 .set_key = wl1271_op_set_key,
2139 .hw_scan = wl1271_op_hw_scan,
2140 .bss_info_changed = wl1271_op_bss_info_changed,
2141 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002142 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002143 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144};
2145
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002146
2147u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2148{
2149 u8 idx;
2150
2151 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2152
2153 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2154 wl1271_error("Illegal RX rate from HW: %d", rate);
2155 return 0;
2156 }
2157
2158 idx = wl1271_band_rate_to_idx[wl->band][rate];
2159 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2160 wl1271_error("Unsupported RX rate from HW: %d", rate);
2161 return 0;
2162 }
2163
2164 return idx;
2165}
2166
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002167static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2168 struct device_attribute *attr,
2169 char *buf)
2170{
2171 struct wl1271 *wl = dev_get_drvdata(dev);
2172 ssize_t len;
2173
2174 /* FIXME: what's the maximum length of buf? page size?*/
2175 len = 500;
2176
2177 mutex_lock(&wl->mutex);
2178 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2179 wl->sg_enabled);
2180 mutex_unlock(&wl->mutex);
2181
2182 return len;
2183
2184}
2185
2186static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2187 struct device_attribute *attr,
2188 const char *buf, size_t count)
2189{
2190 struct wl1271 *wl = dev_get_drvdata(dev);
2191 unsigned long res;
2192 int ret;
2193
2194 ret = strict_strtoul(buf, 10, &res);
2195
2196 if (ret < 0) {
2197 wl1271_warning("incorrect value written to bt_coex_mode");
2198 return count;
2199 }
2200
2201 mutex_lock(&wl->mutex);
2202
2203 res = !!res;
2204
2205 if (res == wl->sg_enabled)
2206 goto out;
2207
2208 wl->sg_enabled = res;
2209
2210 if (wl->state == WL1271_STATE_OFF)
2211 goto out;
2212
2213 ret = wl1271_ps_elp_wakeup(wl, false);
2214 if (ret < 0)
2215 goto out;
2216
2217 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2218 wl1271_ps_elp_sleep(wl);
2219
2220 out:
2221 mutex_unlock(&wl->mutex);
2222 return count;
2223}
2224
2225static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2226 wl1271_sysfs_show_bt_coex_state,
2227 wl1271_sysfs_store_bt_coex_state);
2228
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002229int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002230{
2231 int ret;
2232
2233 if (wl->mac80211_registered)
2234 return 0;
2235
2236 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2237
2238 ret = ieee80211_register_hw(wl->hw);
2239 if (ret < 0) {
2240 wl1271_error("unable to register mac80211 hw: %d", ret);
2241 return ret;
2242 }
2243
2244 wl->mac80211_registered = true;
2245
2246 wl1271_notice("loaded");
2247
2248 return 0;
2249}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002250EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002252void wl1271_unregister_hw(struct wl1271 *wl)
2253{
2254 ieee80211_unregister_hw(wl->hw);
2255 wl->mac80211_registered = false;
2256
2257}
2258EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2259
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002260int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002262 /* The tx descriptor buffer and the TKIP space. */
2263 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2264 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002265
2266 /* unit us */
2267 /* FIXME: find a proper value */
2268 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002269 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270
2271 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002272 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002273 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002274 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002275 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002276 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002277 IEEE80211_HW_CONNECTION_MONITOR |
2278 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002280 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2281 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002282 wl->hw->wiphy->max_scan_ssids = 1;
2283 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2284
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002285 if (wl1271_11a_enabled())
2286 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2287
Kalle Valo12bd8942010-03-18 12:26:33 +02002288 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002289 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002290
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002291 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
2293 return 0;
2294}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002295EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002298
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002299struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002300{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002302 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002304 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305
2306 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2307 if (!hw) {
2308 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002309 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002310 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 }
2312
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002313 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2314 if (!plat_dev) {
2315 wl1271_error("could not allocate platform_device");
2316 ret = -ENOMEM;
2317 goto err_plat_alloc;
2318 }
2319
2320 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322 wl = hw->priv;
2323 memset(wl, 0, sizeof(*wl));
2324
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002325 INIT_LIST_HEAD(&wl->list);
2326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002328 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329
2330 skb_queue_head_init(&wl->tx_queue);
2331
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002332 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002333 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002334 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336 wl->rx_counter = 0;
2337 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2338 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002339 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002341 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002342 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002343 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2344 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002345 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002346 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002347 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002348 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002350 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351 wl->tx_frames[i] = NULL;
2352
2353 spin_lock_init(&wl->wl_lock);
2354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355 wl->state = WL1271_STATE_OFF;
2356 mutex_init(&wl->mutex);
2357
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002358 /* Apply default driver configuration. */
2359 wl1271_conf_init(wl);
2360
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002361 wl1271_debugfs_init(wl);
2362
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002363 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002364 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002365 if (ret) {
2366 wl1271_error("couldn't register platform device");
2367 goto err_hw;
2368 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002369 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002370
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002371 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002372 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002373 if (ret < 0) {
2374 wl1271_error("failed to create sysfs file bt_coex_state");
2375 goto err_platform;
2376 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002377
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002378 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002379
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002380err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002381 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002382
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002383err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002384 wl1271_debugfs_exit(wl);
2385 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002386
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002387err_plat_alloc:
2388 ieee80211_free_hw(hw);
2389
2390err_hw_alloc:
2391
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002392 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002393}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002394EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002395
2396int wl1271_free_hw(struct wl1271 *wl)
2397{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002398 platform_device_unregister(wl->plat_dev);
2399 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002400
2401 wl1271_debugfs_exit(wl);
2402
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002403 vfree(wl->fw);
2404 wl->fw = NULL;
2405 kfree(wl->nvs);
2406 wl->nvs = NULL;
2407
2408 kfree(wl->fw_status);
2409 kfree(wl->tx_res_if);
2410
2411 ieee80211_free_hw(wl->hw);
2412
2413 return 0;
2414}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002415EXPORT_SYMBOL_GPL(wl1271_free_hw);
2416
2417MODULE_LICENSE("GPL");
2418MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2419MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");