blob: afab52bec1344a5362665849a0451b11a12c7db8 [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 Oikarinenec078d92009-12-11 15:41:05 +0200119 .enabled_rates = CONF_HW_BIT_RATE_1MBPS |
120 CONF_HW_BIT_RATE_2MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
127 [0] = {
128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
134 [1] = {
135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
141 [2] = {
142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
148 [3] = {
149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
156 .tid_conf_count = 7,
157 .tid_conf = {
158 [0] = {
159 .queue_id = 0,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
166 [1] = {
167 .queue_id = 1,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
174 [2] = {
175 .queue_id = 2,
176 .channel_type = CONF_CHANNEL_TYPE_DCF,
177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
182 [3] = {
183 .queue_id = 3,
184 .channel_type = CONF_CHANNEL_TYPE_DCF,
185 .tsid = CONF_TX_AC_BE,
186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
190 [4] = {
191 .queue_id = 4,
192 .channel_type = CONF_CHANNEL_TYPE_DCF,
193 .tsid = CONF_TX_AC_BE,
194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
198 [5] = {
199 .queue_id = 5,
200 .channel_type = CONF_CHANNEL_TYPE_DCF,
201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
206 [6] = {
207 .queue_id = 6,
208 .channel_type = CONF_CHANNEL_TYPE_DCF,
209 .tsid = CONF_TX_AC_BE,
210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 }
214 },
215 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200216 .tx_compl_timeout = 700,
217 .tx_compl_threshold = 4
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 },
219 .conn = {
220 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
221 .listen_interval = 0,
222 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
223 .bcn_filt_ie_count = 1,
224 .bcn_filt_ie = {
225 [0] = {
226 .ie = WLAN_EID_CHANNEL_SWITCH,
227 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
228 }
229 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200230 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 .bss_lose_timeout = 100,
232 .beacon_rx_timeout = 10000,
233 .broadcast_timeout = 20000,
234 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200235 .ps_poll_threshold = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300236 .sig_trigger_count = 2,
237 .sig_trigger = {
238 [0] = {
239 .threshold = -75,
240 .pacing = 500,
241 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
242 .type = CONF_TRIG_EVENT_TYPE_EDGE,
243 .direction = CONF_TRIG_EVENT_DIR_LOW,
244 .hysteresis = 2,
245 .index = 0,
246 .enable = 1
247 },
248 [1] = {
249 .threshold = -75,
250 .pacing = 500,
251 .metric = CONF_TRIG_METRIC_RSSI_BEACON,
252 .type = CONF_TRIG_EVENT_TYPE_EDGE,
253 .direction = CONF_TRIG_EVENT_DIR_HIGH,
254 .hysteresis = 2,
255 .index = 1,
256 .enable = 1
257 }
258 },
259 .sig_weights = {
260 .rssi_bcn_avg_weight = 10,
261 .rssi_pkt_avg_weight = 10,
262 .snr_bcn_avg_weight = 10,
263 .snr_pkt_avg_weight = 10
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300264 },
265 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200266 .bet_max_consecutive = 10,
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200267 .psm_entry_retries = 3
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300268 },
269 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200271 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200273 },
274 .itrim = {
275 .enable = false,
276 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200277 },
278 .pm_config = {
279 .host_clk_settling_time = 5000,
280 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300281 }
282};
283
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200284static void wl1271_device_release(struct device *dev)
285{
286
287}
288
289static struct platform_device wl1271_device = {
290 .name = "wl1271",
291 .id = -1,
292
293 /* device model insists to have a release function */
294 .dev = {
295 .release = wl1271_device_release,
296 },
297};
298
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300299static LIST_HEAD(wl_list);
300
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300301static void wl1271_conf_init(struct wl1271 *wl)
302{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300303
304 /*
305 * This function applies the default configuration to the driver. This
306 * function is invoked upon driver load (spi probe.)
307 *
308 * The configuration is stored in a run-time structure in order to
309 * facilitate for run-time adjustment of any of the parameters. Making
310 * changes to the configuration structure will apply the new values on
311 * the next interface up (wl1271_op_start.)
312 */
313
314 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300315 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300316}
317
318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300319static int wl1271_plt_init(struct wl1271 *wl)
320{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200321 struct conf_tx_ac_category *conf_ac;
322 struct conf_tx_tid *conf_tid;
323 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300324
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200325 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200326 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200327 return ret;
328
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200329 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200330 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200331 return ret;
332
Luciano Coelho12419cc2010-02-18 13:25:44 +0200333 ret = wl1271_init_templates_config(wl);
334 if (ret < 0)
335 return ret;
336
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300337 ret = wl1271_acx_init_mem_config(wl);
338 if (ret < 0)
339 return ret;
340
Luciano Coelho12419cc2010-02-18 13:25:44 +0200341 /* PHY layer config */
342 ret = wl1271_init_phy_config(wl);
343 if (ret < 0)
344 goto out_free_memmap;
345
346 ret = wl1271_acx_dco_itrim_params(wl);
347 if (ret < 0)
348 goto out_free_memmap;
349
350 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200351 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200352 if (ret < 0)
353 goto out_free_memmap;
354
355 /* Bluetooth WLAN coexistence */
356 ret = wl1271_init_pta(wl);
357 if (ret < 0)
358 goto out_free_memmap;
359
360 /* Energy detection */
361 ret = wl1271_init_energy_detection(wl);
362 if (ret < 0)
363 goto out_free_memmap;
364
365 /* Default fragmentation threshold */
366 ret = wl1271_acx_frag_threshold(wl);
367 if (ret < 0)
368 goto out_free_memmap;
369
370 /* Default TID configuration */
371 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
372 conf_tid = &wl->conf.tx.tid_conf[i];
373 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
374 conf_tid->channel_type,
375 conf_tid->tsid,
376 conf_tid->ps_scheme,
377 conf_tid->ack_policy,
378 conf_tid->apsd_conf[0],
379 conf_tid->apsd_conf[1]);
380 if (ret < 0)
381 goto out_free_memmap;
382 }
383
384 /* Default AC configuration */
385 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
386 conf_ac = &wl->conf.tx.ac_conf[i];
387 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
388 conf_ac->cw_max, conf_ac->aifsn,
389 conf_ac->tx_op_limit);
390 if (ret < 0)
391 goto out_free_memmap;
392 }
393
394 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200395 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300396 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200397 goto out_free_memmap;
398
399 /* Configure for CAM power saving (ie. always active) */
400 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
401 if (ret < 0)
402 goto out_free_memmap;
403
404 /* configure PM */
405 ret = wl1271_acx_pm_config(wl);
406 if (ret < 0)
407 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300408
409 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200410
411 out_free_memmap:
412 kfree(wl->target_mem_map);
413 wl->target_mem_map = NULL;
414
415 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300416}
417
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300418static void wl1271_fw_status(struct wl1271 *wl,
419 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200421 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300422 u32 total = 0;
423 int i;
424
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200425 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300426
427 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
428 "drv_rx_counter = %d, tx_results_counter = %d)",
429 status->intr,
430 status->fw_rx_counter,
431 status->drv_rx_counter,
432 status->tx_results_counter);
433
434 /* update number of available TX blocks */
435 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300436 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
437 wl->tx_blocks_freed[i];
438
439 wl->tx_blocks_freed[i] =
440 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 wl->tx_blocks_available += cnt;
442 total += cnt;
443 }
444
445 /* if more blocks are available now, schedule some tx work */
446 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300447 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300448
449 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200450 getnstimeofday(&ts);
451 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
452 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453}
454
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200455#define WL1271_IRQ_MAX_LOOPS 10
456
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300457static void wl1271_irq_work(struct work_struct *work)
458{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300459 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300460 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200461 int loopcount = WL1271_IRQ_MAX_LOOPS;
462 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300463 struct wl1271 *wl =
464 container_of(work, struct wl1271, irq_work);
465
466 mutex_lock(&wl->mutex);
467
468 wl1271_debug(DEBUG_IRQ, "IRQ work");
469
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200470 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300471 goto out;
472
473 ret = wl1271_ps_elp_wakeup(wl, true);
474 if (ret < 0)
475 goto out;
476
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200477 spin_lock_irqsave(&wl->wl_lock, flags);
478 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
479 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
480 spin_unlock_irqrestore(&wl->wl_lock, flags);
481 loopcount--;
482
483 wl1271_fw_status(wl, wl->fw_status);
484 intr = le32_to_cpu(wl->fw_status->intr);
485 if (!intr) {
486 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
487 continue;
488 }
489
490 intr &= WL1271_INTR_MASK;
491
492 if (intr & WL1271_ACX_INTR_DATA) {
493 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
494
495 /* check for tx results */
496 if (wl->fw_status->tx_results_counter !=
497 (wl->tx_results_count & 0xff))
498 wl1271_tx_complete(wl);
499
500 wl1271_rx(wl, wl->fw_status);
501 }
502
503 if (intr & WL1271_ACX_INTR_EVENT_A) {
504 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
505 wl1271_event_handle(wl, 0);
506 }
507
508 if (intr & WL1271_ACX_INTR_EVENT_B) {
509 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
510 wl1271_event_handle(wl, 1);
511 }
512
513 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
514 wl1271_debug(DEBUG_IRQ,
515 "WL1271_ACX_INTR_INIT_COMPLETE");
516
517 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
518 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
519
520 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521 }
522
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200523 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
524 ieee80211_queue_work(wl->hw, &wl->irq_work);
525 else
526 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
527 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529 wl1271_ps_elp_sleep(wl);
530
531out:
532 mutex_unlock(&wl->mutex);
533}
534
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300535static int wl1271_fetch_firmware(struct wl1271 *wl)
536{
537 const struct firmware *fw;
538 int ret;
539
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200540 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300541
542 if (ret < 0) {
543 wl1271_error("could not get firmware: %d", ret);
544 return ret;
545 }
546
547 if (fw->size % 4) {
548 wl1271_error("firmware size is not multiple of 32 bits: %zu",
549 fw->size);
550 ret = -EILSEQ;
551 goto out;
552 }
553
554 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300555 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300556
557 if (!wl->fw) {
558 wl1271_error("could not allocate memory for the firmware");
559 ret = -ENOMEM;
560 goto out;
561 }
562
563 memcpy(wl->fw, fw->data, wl->fw_len);
564
565 ret = 0;
566
567out:
568 release_firmware(fw);
569
570 return ret;
571}
572
573static int wl1271_fetch_nvs(struct wl1271 *wl)
574{
575 const struct firmware *fw;
576 int ret;
577
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200578 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579
580 if (ret < 0) {
581 wl1271_error("could not get nvs file: %d", ret);
582 return ret;
583 }
584
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200585 if (fw->size != sizeof(struct wl1271_nvs_file)) {
586 wl1271_error("nvs size is not as expected: %zu != %zu",
587 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300588 ret = -EILSEQ;
589 goto out;
590 }
591
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200592 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593
594 if (!wl->nvs) {
595 wl1271_error("could not allocate memory for the nvs file");
596 ret = -ENOMEM;
597 goto out;
598 }
599
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200600 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602out:
603 release_firmware(fw);
604
605 return ret;
606}
607
608static void wl1271_fw_wakeup(struct wl1271 *wl)
609{
610 u32 elp_reg;
611
612 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300613 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300614}
615
616static int wl1271_setup(struct wl1271 *wl)
617{
618 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
619 if (!wl->fw_status)
620 return -ENOMEM;
621
622 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
623 if (!wl->tx_res_if) {
624 kfree(wl->fw_status);
625 return -ENOMEM;
626 }
627
628 INIT_WORK(&wl->irq_work, wl1271_irq_work);
629 INIT_WORK(&wl->tx_work, wl1271_tx_work);
630 return 0;
631}
632
633static int wl1271_chip_wakeup(struct wl1271 *wl)
634{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300635 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300636 int ret = 0;
637
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200638 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300639 wl1271_power_on(wl);
640 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200641 wl1271_io_reset(wl);
642 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300643
644 /* We don't need a real memory partition here, because we only want
645 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300646 memset(&partition, 0, sizeof(partition));
647 partition.reg.start = REGISTERS_BASE;
648 partition.reg.size = REGISTERS_DOWN_SIZE;
649 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650
651 /* ELP module wake up */
652 wl1271_fw_wakeup(wl);
653
654 /* whal_FwCtrl_BootSm() */
655
656 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200657 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658
659 /* 1. check if chip id is valid */
660
661 switch (wl->chip.id) {
662 case CHIP_ID_1271_PG10:
663 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
664 wl->chip.id);
665
666 ret = wl1271_setup(wl);
667 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200668 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 break;
670 case CHIP_ID_1271_PG20:
671 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
672 wl->chip.id);
673
674 ret = wl1271_setup(wl);
675 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200676 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 break;
678 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200679 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300680 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200681 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 }
683
684 if (wl->fw == NULL) {
685 ret = wl1271_fetch_firmware(wl);
686 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200687 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 }
689
690 /* No NVS from netlink, try to get it from the filesystem */
691 if (wl->nvs == NULL) {
692 ret = wl1271_fetch_nvs(wl);
693 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200694 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695 }
696
697out:
698 return ret;
699}
700
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701int wl1271_plt_start(struct wl1271 *wl)
702{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200703 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704 int ret;
705
706 mutex_lock(&wl->mutex);
707
708 wl1271_notice("power up");
709
710 if (wl->state != WL1271_STATE_OFF) {
711 wl1271_error("cannot go into PLT state because not "
712 "in off state: %d", wl->state);
713 ret = -EBUSY;
714 goto out;
715 }
716
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200717 while (retries) {
718 retries--;
719 ret = wl1271_chip_wakeup(wl);
720 if (ret < 0)
721 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723 ret = wl1271_boot(wl);
724 if (ret < 0)
725 goto power_off;
726
727 ret = wl1271_plt_init(wl);
728 if (ret < 0)
729 goto irq_disable;
730
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200731 wl->state = WL1271_STATE_PLT;
732 wl1271_notice("firmware booted in PLT mode (%s)",
733 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734 goto out;
735
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200736irq_disable:
737 wl1271_disable_interrupts(wl);
738 mutex_unlock(&wl->mutex);
739 /* Unlocking the mutex in the middle of handling is
740 inherently unsafe. In this case we deem it safe to do,
741 because we need to let any possibly pending IRQ out of
742 the system (and while we are WL1271_STATE_OFF the IRQ
743 work function will not do anything.) Also, any other
744 possible concurrent operations will fail due to the
745 current state, hence the wl1271 struct should be safe. */
746 cancel_work_sync(&wl->irq_work);
747 mutex_lock(&wl->mutex);
748power_off:
749 wl1271_power_off(wl);
750 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300751
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200752 wl1271_error("firmware boot in PLT mode failed despite %d retries",
753 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754out:
755 mutex_unlock(&wl->mutex);
756
757 return ret;
758}
759
760int wl1271_plt_stop(struct wl1271 *wl)
761{
762 int ret = 0;
763
764 mutex_lock(&wl->mutex);
765
766 wl1271_notice("power down");
767
768 if (wl->state != WL1271_STATE_PLT) {
769 wl1271_error("cannot power down because not in PLT "
770 "state: %d", wl->state);
771 ret = -EBUSY;
772 goto out;
773 }
774
775 wl1271_disable_interrupts(wl);
776 wl1271_power_off(wl);
777
778 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300779 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
781out:
782 mutex_unlock(&wl->mutex);
783
784 return ret;
785}
786
787
788static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
789{
790 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200791 struct ieee80211_conf *conf = &hw->conf;
792 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
793 struct ieee80211_sta *sta = txinfo->control.sta;
794 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200796 /* peek into the rates configured in the STA entry */
797 spin_lock_irqsave(&wl->wl_lock, flags);
798 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
799 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
800 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
801 }
802 spin_unlock_irqrestore(&wl->wl_lock, flags);
803
804 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300805 skb_queue_tail(&wl->tx_queue, skb);
806
807 /*
808 * The chip specific setup must run before the first TX packet -
809 * before that, the tx_work will not be initialized!
810 */
811
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300812 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300813
814 /*
815 * The workqueue is slow to process the tx_queue and we need stop
816 * the queue here, otherwise the queue will get too long.
817 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200818 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
819 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300820
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200821 spin_lock_irqsave(&wl->wl_lock, flags);
822 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200823 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200824 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300825 }
826
827 return NETDEV_TX_OK;
828}
829
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300830static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
831 void *arg)
832{
833 struct net_device *dev;
834 struct wireless_dev *wdev;
835 struct wiphy *wiphy;
836 struct ieee80211_hw *hw;
837 struct wl1271 *wl;
838 struct wl1271 *wl_temp;
839 struct in_device *idev;
840 struct in_ifaddr *ifa = arg;
841 int ret = 0;
842
843 /* FIXME: this ugly function should probably be implemented in the
844 * mac80211, and here should only be a simple callback handling actual
845 * setting of the filters. Now we need to dig up references to
846 * various structures to gain access to what we need.
847 * Also, because of this, there is no "initial" setting of the filter
848 * in "op_start", because we don't want to dig up struct net_device
849 * there - the filter will be set upon first change of the interface
850 * IP address. */
851
852 dev = ifa->ifa_dev->dev;
853
854 wdev = dev->ieee80211_ptr;
855 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200856 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300857
858 wiphy = wdev->wiphy;
859 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200860 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300861
862 hw = wiphy_priv(wiphy);
863 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200864 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300865
866 /* Check that the interface is one supported by this driver. */
867 wl_temp = hw->priv;
868 list_for_each_entry(wl, &wl_list, list) {
869 if (wl == wl_temp)
870 break;
871 }
872 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200873 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300874
875 /* Get the interface IP address for the device. "ifa" will become
876 NULL if:
877 - there is no IPV4 protocol address configured
878 - there are multiple (virtual) IPV4 addresses configured
879 When "ifa" is NULL, filtering will be disabled.
880 */
881 ifa = NULL;
882 idev = dev->ip_ptr;
883 if (idev)
884 ifa = idev->ifa_list;
885
886 if (ifa && ifa->ifa_next)
887 ifa = NULL;
888
889 mutex_lock(&wl->mutex);
890
891 if (wl->state == WL1271_STATE_OFF)
892 goto out;
893
894 ret = wl1271_ps_elp_wakeup(wl, false);
895 if (ret < 0)
896 goto out;
897 if (ifa)
898 ret = wl1271_acx_arp_ip_filter(wl, true,
899 (u8 *)&ifa->ifa_address,
900 ACX_IPV4_VERSION);
901 else
902 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
903 ACX_IPV4_VERSION);
904 wl1271_ps_elp_sleep(wl);
905
906out:
907 mutex_unlock(&wl->mutex);
908
Luciano Coelho17d72652009-11-23 23:22:15 +0200909 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300910}
911
912static struct notifier_block wl1271_dev_notifier = {
913 .notifier_call = wl1271_dev_notify,
914};
915
916
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917static int wl1271_op_start(struct ieee80211_hw *hw)
918{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200919 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
920
921 /*
922 * We have to delay the booting of the hardware because
923 * we need to know the local MAC address before downloading and
924 * initializing the firmware. The MAC address cannot be changed
925 * after boot, and without the proper MAC address, the firmware
926 * will not function properly.
927 *
928 * The MAC address is first known when the corresponding interface
929 * is added. That is where we will initialize the hardware.
930 */
931
932 return 0;
933}
934
935static void wl1271_op_stop(struct ieee80211_hw *hw)
936{
937 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
938}
939
940static int wl1271_op_add_interface(struct ieee80211_hw *hw,
941 struct ieee80211_vif *vif)
942{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300943 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200944 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945 int ret = 0;
946
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200947 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
948 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949
950 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200951 if (wl->vif) {
952 ret = -EBUSY;
953 goto out;
954 }
955
956 wl->vif = vif;
957
958 switch (vif->type) {
959 case NL80211_IFTYPE_STATION:
960 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200961 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200962 break;
963 case NL80211_IFTYPE_ADHOC:
964 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200965 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200966 break;
967 default:
968 ret = -EOPNOTSUPP;
969 goto out;
970 }
971
972 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973
974 if (wl->state != WL1271_STATE_OFF) {
975 wl1271_error("cannot start because not in off state: %d",
976 wl->state);
977 ret = -EBUSY;
978 goto out;
979 }
980
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981 while (retries) {
982 retries--;
983 ret = wl1271_chip_wakeup(wl);
984 if (ret < 0)
985 goto power_off;
986
987 ret = wl1271_boot(wl);
988 if (ret < 0)
989 goto power_off;
990
991 ret = wl1271_hw_init(wl);
992 if (ret < 0)
993 goto irq_disable;
994
995 wl->state = WL1271_STATE_ON;
996 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997 goto out;
998
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200999irq_disable:
1000 wl1271_disable_interrupts(wl);
1001 mutex_unlock(&wl->mutex);
1002 /* Unlocking the mutex in the middle of handling is
1003 inherently unsafe. In this case we deem it safe to do,
1004 because we need to let any possibly pending IRQ out of
1005 the system (and while we are WL1271_STATE_OFF the IRQ
1006 work function will not do anything.) Also, any other
1007 possible concurrent operations will fail due to the
1008 current state, hence the wl1271 struct should be safe. */
1009 cancel_work_sync(&wl->irq_work);
1010 mutex_lock(&wl->mutex);
1011power_off:
1012 wl1271_power_off(wl);
1013 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001015 wl1271_error("firmware boot failed despite %d retries",
1016 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001017out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018 mutex_unlock(&wl->mutex);
1019
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001020 if (!ret) {
1021 list_add(&wl->list, &wl_list);
1022 register_inetaddr_notifier(&wl1271_dev_notifier);
1023 }
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 return ret;
1026}
1027
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001028static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1029 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030{
1031 struct wl1271 *wl = hw->priv;
1032 int i;
1033
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001034 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1035
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001036 mutex_lock(&wl->mutex);
1037 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001039 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001041 list_del(&wl->list);
1042
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 WARN_ON(wl->state != WL1271_STATE_ON);
1044
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001045 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 mutex_unlock(&wl->mutex);
1047 ieee80211_scan_completed(wl->hw, true);
1048 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001049 }
1050
1051 wl->state = WL1271_STATE_OFF;
1052
1053 wl1271_disable_interrupts(wl);
1054
1055 mutex_unlock(&wl->mutex);
1056
1057 cancel_work_sync(&wl->irq_work);
1058 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059
1060 mutex_lock(&wl->mutex);
1061
1062 /* let's notify MAC80211 about the remaining pending TX frames */
1063 wl1271_tx_flush(wl);
1064 wl1271_power_off(wl);
1065
1066 memset(wl->bssid, 0, ETH_ALEN);
1067 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1068 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001070 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001071 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072
1073 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001074 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1076 wl->tx_blocks_available = 0;
1077 wl->tx_results_count = 0;
1078 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001079 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001080 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 wl->time_offset = 0;
1082 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001083 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1084 wl->sta_rate_set = 0;
1085 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001086 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001087 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001088
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089 for (i = 0; i < NUM_TX_QUEUES; i++)
1090 wl->tx_blocks_freed[i] = 0;
1091
1092 wl1271_debugfs_reset(wl);
1093 mutex_unlock(&wl->mutex);
1094}
1095
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001096static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1097{
1098 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1099 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1100
1101 /* combine requested filters with current filter config */
1102 filters = wl->filters | filters;
1103
1104 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1105
1106 if (filters & FIF_PROMISC_IN_BSS) {
1107 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1108 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1109 wl->rx_config |= CFG_BSSID_FILTER_EN;
1110 }
1111 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1112 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1113 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1114 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1115 }
1116 if (filters & FIF_OTHER_BSS) {
1117 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1118 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1119 }
1120 if (filters & FIF_CONTROL) {
1121 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1122 wl->rx_filter |= CFG_RX_CTL_EN;
1123 }
1124 if (filters & FIF_FCSFAIL) {
1125 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1126 wl->rx_filter |= CFG_RX_FCS_ERROR;
1127 }
1128}
1129
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001130static int wl1271_join_channel(struct wl1271 *wl, int channel)
1131{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001132 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133 /* we need to use a dummy BSSID for now */
1134 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1135 0xad, 0xbe, 0xef };
1136
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001137 wl->channel = channel;
1138 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1139
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001140 /* pass through frames from all BSS */
1141 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1142
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001143 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001144 if (ret < 0)
1145 goto out;
1146
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001147 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001148
1149out:
1150 return ret;
1151}
1152
1153static int wl1271_unjoin_channel(struct wl1271 *wl)
1154{
1155 int ret;
1156
1157 /* to stop listening to a channel, we disconnect */
1158 ret = wl1271_cmd_disconnect(wl);
1159 if (ret < 0)
1160 goto out;
1161
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001162 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001163 wl->channel = 0;
1164 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001165
1166 /* stop filterting packets based on bssid */
1167 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001168
1169out:
1170 return ret;
1171}
1172
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001173static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1174{
1175 struct wl1271 *wl = hw->priv;
1176 struct ieee80211_conf *conf = &hw->conf;
1177 int channel, ret = 0;
1178
1179 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1180
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001181 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182 channel,
1183 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001184 conf->power_level,
1185 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186
1187 mutex_lock(&wl->mutex);
1188
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001189 wl->band = conf->channel->band;
1190
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001191 ret = wl1271_ps_elp_wakeup(wl, false);
1192 if (ret < 0)
1193 goto out;
1194
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001195 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001196 if (conf->flags & IEEE80211_CONF_IDLE &&
1197 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001198 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001199 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001200 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001201
1202 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001203 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1204 wl->sta_rate_set = 0;
1205 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001206 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 }
1208
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001209 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001210 if (channel != wl->channel &&
1211 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1212 wl->channel = channel;
1213 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001214 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001215 if (ret < 0)
1216 wl1271_warning("cmd join to update channel failed %d",
1217 ret);
1218 } else
1219 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001220
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001221 if (conf->flags & IEEE80211_CONF_PS &&
1222 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1223 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224
1225 /*
1226 * We enter PSM only if we're already associated.
1227 * If we're not, we'll enter it when joining an SSID,
1228 * through the bss_info_changed() hook.
1229 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001230 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001231 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001232 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1233 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001234 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001235 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001236 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001237 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001239 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001241 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001242 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1243 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 }
1245
1246 if (conf->power_level != wl->power_level) {
1247 ret = wl1271_acx_tx_power(wl, conf->power_level);
1248 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001249 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250
1251 wl->power_level = conf->power_level;
1252 }
1253
1254out_sleep:
1255 wl1271_ps_elp_sleep(wl);
1256
1257out:
1258 mutex_unlock(&wl->mutex);
1259
1260 return ret;
1261}
1262
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001263struct wl1271_filter_params {
1264 bool enabled;
1265 int mc_list_length;
1266 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1267};
1268
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001269static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1270 struct dev_addr_list *mc_list)
1271{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001272 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001273 int i;
1274
Juuso Oikarinen74441132009-10-13 12:47:53 +03001275 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001276 if (!fp) {
1277 wl1271_error("Out of memory setting filters.");
1278 return 0;
1279 }
1280
1281 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001282 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001283 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1284 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001285 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001286 }
1287
1288 fp->mc_list_length = 0;
1289 for (i = 0; i < mc_count; i++) {
1290 if (mc_list->da_addrlen == ETH_ALEN) {
1291 memcpy(fp->mc_list[fp->mc_list_length],
1292 mc_list->da_addr, ETH_ALEN);
1293 fp->mc_list_length++;
1294 } else
1295 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001296 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001297 }
1298
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001299 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001300}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001302#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1303 FIF_ALLMULTI | \
1304 FIF_FCSFAIL | \
1305 FIF_BCN_PRBRESP_PROMISC | \
1306 FIF_CONTROL | \
1307 FIF_OTHER_BSS)
1308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1310 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001311 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001313 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001315 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
1317 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1318
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001319 mutex_lock(&wl->mutex);
1320
1321 if (wl->state == WL1271_STATE_OFF)
1322 goto out;
1323
1324 ret = wl1271_ps_elp_wakeup(wl, false);
1325 if (ret < 0)
1326 goto out;
1327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 *total &= WL1271_SUPPORTED_FILTERS;
1329 changed &= WL1271_SUPPORTED_FILTERS;
1330
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001331 if (*total & FIF_ALLMULTI)
1332 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1333 else if (fp)
1334 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1335 fp->mc_list,
1336 fp->mc_list_length);
1337 if (ret < 0)
1338 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001340 /* determine, whether supported filter values have changed */
1341 if (changed == 0)
1342 goto out_sleep;
1343
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001344 /* configure filters */
1345 wl->filters = *total;
1346 wl1271_configure_filters(wl, 0);
1347
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348 /* apply configured filters */
1349 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1350 if (ret < 0)
1351 goto out_sleep;
1352
1353out_sleep:
1354 wl1271_ps_elp_sleep(wl);
1355
1356out:
1357 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001358 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359}
1360
1361static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1362 struct ieee80211_vif *vif,
1363 struct ieee80211_sta *sta,
1364 struct ieee80211_key_conf *key_conf)
1365{
1366 struct wl1271 *wl = hw->priv;
1367 const u8 *addr;
1368 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001369 u32 tx_seq_32 = 0;
1370 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371 u8 key_type;
1372
1373 static const u8 bcast_addr[ETH_ALEN] =
1374 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1375
1376 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1377
1378 addr = sta ? sta->addr : bcast_addr;
1379
1380 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1381 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1382 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1383 key_conf->alg, key_conf->keyidx,
1384 key_conf->keylen, key_conf->flags);
1385 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1386
1387 if (is_zero_ether_addr(addr)) {
1388 /* We dont support TX only encryption */
1389 ret = -EOPNOTSUPP;
1390 goto out;
1391 }
1392
1393 mutex_lock(&wl->mutex);
1394
1395 ret = wl1271_ps_elp_wakeup(wl, false);
1396 if (ret < 0)
1397 goto out_unlock;
1398
1399 switch (key_conf->alg) {
1400 case ALG_WEP:
1401 key_type = KEY_WEP;
1402
1403 key_conf->hw_key_idx = key_conf->keyidx;
1404 break;
1405 case ALG_TKIP:
1406 key_type = KEY_TKIP;
1407
1408 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001409 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1410 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411 break;
1412 case ALG_CCMP:
1413 key_type = KEY_AES;
1414
1415 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001416 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1417 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418 break;
1419 default:
1420 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1421
1422 ret = -EOPNOTSUPP;
1423 goto out_sleep;
1424 }
1425
1426 switch (cmd) {
1427 case SET_KEY:
1428 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1429 key_conf->keyidx, key_type,
1430 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001431 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 if (ret < 0) {
1433 wl1271_error("Could not add or replace key");
1434 goto out_sleep;
1435 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001436
1437 /* the default WEP key needs to be configured at least once */
1438 if (key_type == KEY_WEP) {
1439 ret = wl1271_cmd_set_default_wep_key(wl,
1440 wl->default_key);
1441 if (ret < 0)
1442 goto out_sleep;
1443 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444 break;
1445
1446 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001447 /* The wl1271 does not allow to remove unicast keys - they
1448 will be cleared automatically on next CMD_JOIN. Ignore the
1449 request silently, as we dont want the mac80211 to emit
1450 an error message. */
1451 if (!is_broadcast_ether_addr(addr))
1452 break;
1453
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1455 key_conf->keyidx, key_type,
1456 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001457 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 if (ret < 0) {
1459 wl1271_error("Could not remove key");
1460 goto out_sleep;
1461 }
1462 break;
1463
1464 default:
1465 wl1271_error("Unsupported key cmd 0x%x", cmd);
1466 ret = -EOPNOTSUPP;
1467 goto out_sleep;
1468
1469 break;
1470 }
1471
1472out_sleep:
1473 wl1271_ps_elp_sleep(wl);
1474
1475out_unlock:
1476 mutex_unlock(&wl->mutex);
1477
1478out:
1479 return ret;
1480}
1481
1482static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1483 struct cfg80211_scan_request *req)
1484{
1485 struct wl1271 *wl = hw->priv;
1486 int ret;
1487 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001488 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489
1490 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1491
1492 if (req->n_ssids) {
1493 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001494 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 }
1496
1497 mutex_lock(&wl->mutex);
1498
1499 ret = wl1271_ps_elp_wakeup(wl, false);
1500 if (ret < 0)
1501 goto out;
1502
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001503 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001504 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1505 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001506 WL1271_SCAN_BAND_DUAL, 3);
1507 else
Kalle Valo818e3062010-03-18 12:26:35 +02001508 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1509 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001510 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001511
1512 wl1271_ps_elp_sleep(wl);
1513
1514out:
1515 mutex_unlock(&wl->mutex);
1516
1517 return ret;
1518}
1519
1520static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1521{
1522 struct wl1271 *wl = hw->priv;
1523 int ret;
1524
1525 mutex_lock(&wl->mutex);
1526
1527 ret = wl1271_ps_elp_wakeup(wl, false);
1528 if (ret < 0)
1529 goto out;
1530
1531 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1532 if (ret < 0)
1533 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1534
1535 wl1271_ps_elp_sleep(wl);
1536
1537out:
1538 mutex_unlock(&wl->mutex);
1539
1540 return ret;
1541}
1542
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001543static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1544{
1545 u8 *ptr = beacon->data +
1546 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1547
1548 /* find the location of the ssid in the beacon */
1549 while (ptr < beacon->data + beacon->len) {
1550 if (ptr[0] == WLAN_EID_SSID) {
1551 wl->ssid_len = ptr[1];
1552 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1553 return;
1554 }
1555 ptr += ptr[1];
1556 }
1557 wl1271_error("ad-hoc beacon template has no SSID!\n");
1558}
1559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1561 struct ieee80211_vif *vif,
1562 struct ieee80211_bss_conf *bss_conf,
1563 u32 changed)
1564{
1565 enum wl1271_cmd_ps_mode mode;
1566 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001567 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001568 int ret;
1569
1570 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1571
1572 mutex_lock(&wl->mutex);
1573
1574 ret = wl1271_ps_elp_wakeup(wl, false);
1575 if (ret < 0)
1576 goto out;
1577
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001578 if ((changed && BSS_CHANGED_BEACON_INT) &&
1579 (wl->bss_type == BSS_TYPE_IBSS)) {
1580 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1581 bss_conf->beacon_int);
1582
1583 wl->beacon_int = bss_conf->beacon_int;
1584 do_join = true;
1585 }
1586
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001587 if ((changed && BSS_CHANGED_BEACON) &&
1588 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001589 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1590
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001591 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1592
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001593 if (beacon) {
1594 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001595
1596 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001597 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1598 beacon->data,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +02001599 beacon->len, 0);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001600
1601 if (ret < 0) {
1602 dev_kfree_skb(beacon);
1603 goto out_sleep;
1604 }
1605
1606 hdr = (struct ieee80211_hdr *) beacon->data;
1607 hdr->frame_control = cpu_to_le16(
1608 IEEE80211_FTYPE_MGMT |
1609 IEEE80211_STYPE_PROBE_RESP);
1610
1611 ret = wl1271_cmd_template_set(wl,
1612 CMD_TEMPL_PROBE_RESPONSE,
1613 beacon->data,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +02001614 beacon->len, 0);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001615 dev_kfree_skb(beacon);
1616 if (ret < 0)
1617 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001618
1619 /* Need to update the SSID (for filtering etc) */
1620 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001621 }
1622 }
1623
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001624 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1625 (wl->bss_type == BSS_TYPE_IBSS)) {
1626 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1627 bss_conf->enable_beacon ? "enabled" : "disabled");
1628
1629 if (bss_conf->enable_beacon)
1630 wl->set_bss_type = BSS_TYPE_IBSS;
1631 else
1632 wl->set_bss_type = BSS_TYPE_STA_BSS;
1633 do_join = true;
1634 }
1635
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001636 if ((changed & BSS_CHANGED_BSSID) &&
1637 /*
1638 * Now we know the correct bssid, so we send a new join command
1639 * and enable the BSSID filter
1640 */
1641 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001642 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001643
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001644 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001645 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001646 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001647
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001648 /* filter out all packets not from this BSSID */
1649 wl1271_configure_filters(wl, 0);
1650
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001651 /* Need to update the BSSID (for filtering etc) */
1652 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001653 }
1654
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655 if (changed & BSS_CHANGED_ASSOC) {
1656 if (bss_conf->assoc) {
1657 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001658 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001660 /*
1661 * with wl1271, we don't need to update the
1662 * beacon_int and dtim_period, because the firmware
1663 * updates it by itself when the first beacon is
1664 * received after a join.
1665 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001666 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1667 if (ret < 0)
1668 goto out_sleep;
1669
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001670 /*
1671 * The SSID is intentionally set to NULL here - the
1672 * firmware will set the probe request with a
1673 * broadcast SSID regardless of what we set in the
1674 * template.
1675 */
1676 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1677 NULL, 0, wl->band);
1678
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679 ret = wl1271_acx_aid(wl, wl->aid);
1680 if (ret < 0)
1681 goto out_sleep;
1682
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001683 /* enable the connection monitoring feature */
1684 ret = wl1271_acx_conn_monit_params(wl, true);
1685 if (ret < 0)
1686 goto out_sleep;
1687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001689 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1690 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001691 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001692 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 if (ret < 0)
1694 goto out_sleep;
1695 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001696 } else {
1697 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001698 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001699 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001700
1701 /* disable connection monitor features */
1702 ret = wl1271_acx_conn_monit_params(wl, false);
1703 if (ret < 0)
1704 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001705 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001706
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001708
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 if (changed & BSS_CHANGED_ERP_SLOT) {
1710 if (bss_conf->use_short_slot)
1711 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1712 else
1713 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1714 if (ret < 0) {
1715 wl1271_warning("Set slot time failed %d", ret);
1716 goto out_sleep;
1717 }
1718 }
1719
1720 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1721 if (bss_conf->use_short_preamble)
1722 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1723 else
1724 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1725 }
1726
1727 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1728 if (bss_conf->use_cts_prot)
1729 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1730 else
1731 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1732 if (ret < 0) {
1733 wl1271_warning("Set ctsprotect failed %d", ret);
1734 goto out_sleep;
1735 }
1736 }
1737
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001738 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001739 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001740 if (ret < 0) {
1741 wl1271_warning("cmd join failed %d", ret);
1742 goto out_sleep;
1743 }
1744 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1745 }
1746
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001747out_sleep:
1748 wl1271_ps_elp_sleep(wl);
1749
1750out:
1751 mutex_unlock(&wl->mutex);
1752}
1753
Kalle Valoc6999d82010-02-18 13:25:41 +02001754static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1755 const struct ieee80211_tx_queue_params *params)
1756{
1757 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001758 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001759 int ret;
1760
1761 mutex_lock(&wl->mutex);
1762
1763 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1764
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001765 ret = wl1271_ps_elp_wakeup(wl, false);
1766 if (ret < 0)
1767 goto out;
1768
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001769 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001770 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1771 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001772 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001773 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001774 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001775
Kalle Valo4695dc92010-03-18 12:26:38 +02001776 if (params->uapsd)
1777 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1778 else
1779 ps_scheme = CONF_PS_SCHEME_LEGACY;
1780
Kalle Valoc6999d82010-02-18 13:25:41 +02001781 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1782 CONF_CHANNEL_TYPE_EDCF,
1783 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001784 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001785 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001786 goto out_sleep;
1787
1788out_sleep:
1789 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001790
1791out:
1792 mutex_unlock(&wl->mutex);
1793
1794 return ret;
1795}
1796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797
1798/* can't be const, mac80211 writes to this */
1799static struct ieee80211_rate wl1271_rates[] = {
1800 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001801 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1802 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001804 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1805 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1807 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001808 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1809 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1811 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001812 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1813 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001814 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1815 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001816 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1817 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001819 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1820 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001822 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1823 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001825 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1826 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001828 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1829 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001831 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1832 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001834 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1835 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001837 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1838 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001839};
1840
1841/* can't be const, mac80211 writes to this */
1842static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001843 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1844 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1845 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1846 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1847 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1848 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1849 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1850 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1851 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1852 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1853 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1854 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1855 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856};
1857
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001858/* mapping to indexes for wl1271_rates */
1859const static u8 wl1271_rate_to_idx_2ghz[] = {
1860 /* MCS rates are used only with 11n */
1861 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1862 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1863 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1864 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1865 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1866 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1867 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1868 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1869
1870 11, /* CONF_HW_RXTX_RATE_54 */
1871 10, /* CONF_HW_RXTX_RATE_48 */
1872 9, /* CONF_HW_RXTX_RATE_36 */
1873 8, /* CONF_HW_RXTX_RATE_24 */
1874
1875 /* TI-specific rate */
1876 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1877
1878 7, /* CONF_HW_RXTX_RATE_18 */
1879 6, /* CONF_HW_RXTX_RATE_12 */
1880 3, /* CONF_HW_RXTX_RATE_11 */
1881 5, /* CONF_HW_RXTX_RATE_9 */
1882 4, /* CONF_HW_RXTX_RATE_6 */
1883 2, /* CONF_HW_RXTX_RATE_5_5 */
1884 1, /* CONF_HW_RXTX_RATE_2 */
1885 0 /* CONF_HW_RXTX_RATE_1 */
1886};
1887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888/* can't be const, mac80211 writes to this */
1889static struct ieee80211_supported_band wl1271_band_2ghz = {
1890 .channels = wl1271_channels,
1891 .n_channels = ARRAY_SIZE(wl1271_channels),
1892 .bitrates = wl1271_rates,
1893 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1894};
1895
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001896/* 5 GHz data rates for WL1273 */
1897static struct ieee80211_rate wl1271_rates_5ghz[] = {
1898 { .bitrate = 60,
1899 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1900 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1901 { .bitrate = 90,
1902 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1903 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1904 { .bitrate = 120,
1905 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1906 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1907 { .bitrate = 180,
1908 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1909 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1910 { .bitrate = 240,
1911 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1912 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1913 { .bitrate = 360,
1914 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1915 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1916 { .bitrate = 480,
1917 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1918 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1919 { .bitrate = 540,
1920 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1921 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1922};
1923
1924/* 5 GHz band channels for WL1273 */
1925static struct ieee80211_channel wl1271_channels_5ghz[] = {
1926 { .hw_value = 183, .center_freq = 4915},
1927 { .hw_value = 184, .center_freq = 4920},
1928 { .hw_value = 185, .center_freq = 4925},
1929 { .hw_value = 187, .center_freq = 4935},
1930 { .hw_value = 188, .center_freq = 4940},
1931 { .hw_value = 189, .center_freq = 4945},
1932 { .hw_value = 192, .center_freq = 4960},
1933 { .hw_value = 196, .center_freq = 4980},
1934 { .hw_value = 7, .center_freq = 5035},
1935 { .hw_value = 8, .center_freq = 5040},
1936 { .hw_value = 9, .center_freq = 5045},
1937 { .hw_value = 11, .center_freq = 5055},
1938 { .hw_value = 12, .center_freq = 5060},
1939 { .hw_value = 16, .center_freq = 5080},
1940 { .hw_value = 34, .center_freq = 5170},
1941 { .hw_value = 36, .center_freq = 5180},
1942 { .hw_value = 38, .center_freq = 5190},
1943 { .hw_value = 40, .center_freq = 5200},
1944 { .hw_value = 42, .center_freq = 5210},
1945 { .hw_value = 44, .center_freq = 5220},
1946 { .hw_value = 46, .center_freq = 5230},
1947 { .hw_value = 48, .center_freq = 5240},
1948 { .hw_value = 52, .center_freq = 5260},
1949 { .hw_value = 56, .center_freq = 5280},
1950 { .hw_value = 60, .center_freq = 5300},
1951 { .hw_value = 64, .center_freq = 5320},
1952 { .hw_value = 100, .center_freq = 5500},
1953 { .hw_value = 104, .center_freq = 5520},
1954 { .hw_value = 108, .center_freq = 5540},
1955 { .hw_value = 112, .center_freq = 5560},
1956 { .hw_value = 116, .center_freq = 5580},
1957 { .hw_value = 120, .center_freq = 5600},
1958 { .hw_value = 124, .center_freq = 5620},
1959 { .hw_value = 128, .center_freq = 5640},
1960 { .hw_value = 132, .center_freq = 5660},
1961 { .hw_value = 136, .center_freq = 5680},
1962 { .hw_value = 140, .center_freq = 5700},
1963 { .hw_value = 149, .center_freq = 5745},
1964 { .hw_value = 153, .center_freq = 5765},
1965 { .hw_value = 157, .center_freq = 5785},
1966 { .hw_value = 161, .center_freq = 5805},
1967 { .hw_value = 165, .center_freq = 5825},
1968};
1969
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001970/* mapping to indexes for wl1271_rates_5ghz */
1971const static u8 wl1271_rate_to_idx_5ghz[] = {
1972 /* MCS rates are used only with 11n */
1973 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1974 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1975 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1976 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1977 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1978 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1980 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1981
1982 7, /* CONF_HW_RXTX_RATE_54 */
1983 6, /* CONF_HW_RXTX_RATE_48 */
1984 5, /* CONF_HW_RXTX_RATE_36 */
1985 4, /* CONF_HW_RXTX_RATE_24 */
1986
1987 /* TI-specific rate */
1988 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1989
1990 3, /* CONF_HW_RXTX_RATE_18 */
1991 2, /* CONF_HW_RXTX_RATE_12 */
1992 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
1993 1, /* CONF_HW_RXTX_RATE_9 */
1994 0, /* CONF_HW_RXTX_RATE_6 */
1995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
1998};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001999
2000static struct ieee80211_supported_band wl1271_band_5ghz = {
2001 .channels = wl1271_channels_5ghz,
2002 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2003 .bitrates = wl1271_rates_5ghz,
2004 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2005};
2006
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002007const static u8 *wl1271_band_rate_to_idx[] = {
2008 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2009 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2010};
2011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012static const struct ieee80211_ops wl1271_ops = {
2013 .start = wl1271_op_start,
2014 .stop = wl1271_op_stop,
2015 .add_interface = wl1271_op_add_interface,
2016 .remove_interface = wl1271_op_remove_interface,
2017 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002018 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 .configure_filter = wl1271_op_configure_filter,
2020 .tx = wl1271_op_tx,
2021 .set_key = wl1271_op_set_key,
2022 .hw_scan = wl1271_op_hw_scan,
2023 .bss_info_changed = wl1271_op_bss_info_changed,
2024 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002025 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002026 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027};
2028
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002029
2030u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2031{
2032 u8 idx;
2033
2034 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2035
2036 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2037 wl1271_error("Illegal RX rate from HW: %d", rate);
2038 return 0;
2039 }
2040
2041 idx = wl1271_band_rate_to_idx[wl->band][rate];
2042 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2043 wl1271_error("Unsupported RX rate from HW: %d", rate);
2044 return 0;
2045 }
2046
2047 return idx;
2048}
2049
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002050static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2051 struct device_attribute *attr,
2052 char *buf)
2053{
2054 struct wl1271 *wl = dev_get_drvdata(dev);
2055 ssize_t len;
2056
2057 /* FIXME: what's the maximum length of buf? page size?*/
2058 len = 500;
2059
2060 mutex_lock(&wl->mutex);
2061 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2062 wl->sg_enabled);
2063 mutex_unlock(&wl->mutex);
2064
2065 return len;
2066
2067}
2068
2069static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2070 struct device_attribute *attr,
2071 const char *buf, size_t count)
2072{
2073 struct wl1271 *wl = dev_get_drvdata(dev);
2074 unsigned long res;
2075 int ret;
2076
2077 ret = strict_strtoul(buf, 10, &res);
2078
2079 if (ret < 0) {
2080 wl1271_warning("incorrect value written to bt_coex_mode");
2081 return count;
2082 }
2083
2084 mutex_lock(&wl->mutex);
2085
2086 res = !!res;
2087
2088 if (res == wl->sg_enabled)
2089 goto out;
2090
2091 wl->sg_enabled = res;
2092
2093 if (wl->state == WL1271_STATE_OFF)
2094 goto out;
2095
2096 ret = wl1271_ps_elp_wakeup(wl, false);
2097 if (ret < 0)
2098 goto out;
2099
2100 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2101 wl1271_ps_elp_sleep(wl);
2102
2103 out:
2104 mutex_unlock(&wl->mutex);
2105 return count;
2106}
2107
2108static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2109 wl1271_sysfs_show_bt_coex_state,
2110 wl1271_sysfs_store_bt_coex_state);
2111
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002112int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113{
2114 int ret;
2115
2116 if (wl->mac80211_registered)
2117 return 0;
2118
2119 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2120
2121 ret = ieee80211_register_hw(wl->hw);
2122 if (ret < 0) {
2123 wl1271_error("unable to register mac80211 hw: %d", ret);
2124 return ret;
2125 }
2126
2127 wl->mac80211_registered = true;
2128
2129 wl1271_notice("loaded");
2130
2131 return 0;
2132}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002133EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002135void wl1271_unregister_hw(struct wl1271 *wl)
2136{
2137 ieee80211_unregister_hw(wl->hw);
2138 wl->mac80211_registered = false;
2139
2140}
2141EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2142
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002143int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002145 /* The tx descriptor buffer and the TKIP space. */
2146 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2147 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148
2149 /* unit us */
2150 /* FIXME: find a proper value */
2151 wl->hw->channel_change_time = 10000;
2152
2153 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002154 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002155 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002156 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002157 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002158 IEEE80211_HW_HAS_RATE_CONTROL |
2159 IEEE80211_HW_CONNECTION_MONITOR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002161 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2162 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 wl->hw->wiphy->max_scan_ssids = 1;
2164 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2165
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002166 if (wl1271_11a_enabled())
2167 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2168
Kalle Valo12bd8942010-03-18 12:26:33 +02002169 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002170 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002171
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002172 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002173
2174 return 0;
2175}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002176EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002179
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002180struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002183 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002185 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186
2187 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2188 if (!hw) {
2189 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002190 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002191 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 }
2193
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002194 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2195 if (!plat_dev) {
2196 wl1271_error("could not allocate platform_device");
2197 ret = -ENOMEM;
2198 goto err_plat_alloc;
2199 }
2200
2201 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2202
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002203 wl = hw->priv;
2204 memset(wl, 0, sizeof(*wl));
2205
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002206 INIT_LIST_HEAD(&wl->list);
2207
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002209 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210
2211 skb_queue_head_init(&wl->tx_queue);
2212
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002213 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002215 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 wl->rx_counter = 0;
2218 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2219 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002220 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002222 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002223 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2224 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002225 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002226 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002227 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002228 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002229
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002230 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 wl->tx_frames[i] = NULL;
2232
2233 spin_lock_init(&wl->wl_lock);
2234
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002235 wl->state = WL1271_STATE_OFF;
2236 mutex_init(&wl->mutex);
2237
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002238 /* Apply default driver configuration. */
2239 wl1271_conf_init(wl);
2240
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002241 wl1271_debugfs_init(wl);
2242
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002243 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002244 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002245 if (ret) {
2246 wl1271_error("couldn't register platform device");
2247 goto err_hw;
2248 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002249 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002250
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002251 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002252 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002253 if (ret < 0) {
2254 wl1271_error("failed to create sysfs file bt_coex_state");
2255 goto err_platform;
2256 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002257
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002258 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002259
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002260err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002261 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002262
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002263err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002264 wl1271_debugfs_exit(wl);
2265 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002266
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002267err_plat_alloc:
2268 ieee80211_free_hw(hw);
2269
2270err_hw_alloc:
2271
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002272 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002273}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002274EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002275
2276int wl1271_free_hw(struct wl1271 *wl)
2277{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002278 platform_device_unregister(wl->plat_dev);
2279 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002280
2281 wl1271_debugfs_exit(wl);
2282
2283 kfree(wl->target_mem_map);
2284 vfree(wl->fw);
2285 wl->fw = NULL;
2286 kfree(wl->nvs);
2287 wl->nvs = NULL;
2288
2289 kfree(wl->fw_status);
2290 kfree(wl->tx_res_if);
2291
2292 ieee80211_free_hw(wl->hw);
2293
2294 return 0;
2295}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002296EXPORT_SYMBOL_GPL(wl1271_free_hw);
2297
2298MODULE_LICENSE("GPL");
2299MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2300MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");