blob: 2494c967bb34ac5351880a77ecc4076a88c726f3 [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 Oikarinenc1899552010-03-26 12:53:32 +0200267 .psm_entry_retries = 3,
268 .keep_alive_interval = 55000
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300269 },
270 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300271 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200272 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300273 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200274 },
275 .itrim = {
276 .enable = false,
277 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200278 },
279 .pm_config = {
280 .host_clk_settling_time = 5000,
281 .host_fast_wakeup_support = false
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300282 }
283};
284
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200285static void wl1271_device_release(struct device *dev)
286{
287
288}
289
290static struct platform_device wl1271_device = {
291 .name = "wl1271",
292 .id = -1,
293
294 /* device model insists to have a release function */
295 .dev = {
296 .release = wl1271_device_release,
297 },
298};
299
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300300static LIST_HEAD(wl_list);
301
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300302static void wl1271_conf_init(struct wl1271 *wl)
303{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300304
305 /*
306 * This function applies the default configuration to the driver. This
307 * function is invoked upon driver load (spi probe.)
308 *
309 * The configuration is stored in a run-time structure in order to
310 * facilitate for run-time adjustment of any of the parameters. Making
311 * changes to the configuration structure will apply the new values on
312 * the next interface up (wl1271_op_start.)
313 */
314
315 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300316 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300317}
318
319
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300320static int wl1271_plt_init(struct wl1271 *wl)
321{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200322 struct conf_tx_ac_category *conf_ac;
323 struct conf_tx_tid *conf_tid;
324 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300325
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200326 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200327 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200328 return ret;
329
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200330 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200331 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200332 return ret;
333
Luciano Coelho12419cc2010-02-18 13:25:44 +0200334 ret = wl1271_init_templates_config(wl);
335 if (ret < 0)
336 return ret;
337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300338 ret = wl1271_acx_init_mem_config(wl);
339 if (ret < 0)
340 return ret;
341
Luciano Coelho12419cc2010-02-18 13:25:44 +0200342 /* PHY layer config */
343 ret = wl1271_init_phy_config(wl);
344 if (ret < 0)
345 goto out_free_memmap;
346
347 ret = wl1271_acx_dco_itrim_params(wl);
348 if (ret < 0)
349 goto out_free_memmap;
350
351 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200352 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200353 if (ret < 0)
354 goto out_free_memmap;
355
356 /* Bluetooth WLAN coexistence */
357 ret = wl1271_init_pta(wl);
358 if (ret < 0)
359 goto out_free_memmap;
360
361 /* Energy detection */
362 ret = wl1271_init_energy_detection(wl);
363 if (ret < 0)
364 goto out_free_memmap;
365
366 /* Default fragmentation threshold */
367 ret = wl1271_acx_frag_threshold(wl);
368 if (ret < 0)
369 goto out_free_memmap;
370
371 /* Default TID configuration */
372 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
373 conf_tid = &wl->conf.tx.tid_conf[i];
374 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
375 conf_tid->channel_type,
376 conf_tid->tsid,
377 conf_tid->ps_scheme,
378 conf_tid->ack_policy,
379 conf_tid->apsd_conf[0],
380 conf_tid->apsd_conf[1]);
381 if (ret < 0)
382 goto out_free_memmap;
383 }
384
385 /* Default AC configuration */
386 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
387 conf_ac = &wl->conf.tx.ac_conf[i];
388 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
389 conf_ac->cw_max, conf_ac->aifsn,
390 conf_ac->tx_op_limit);
391 if (ret < 0)
392 goto out_free_memmap;
393 }
394
395 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200396 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300397 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200398 goto out_free_memmap;
399
400 /* Configure for CAM power saving (ie. always active) */
401 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
402 if (ret < 0)
403 goto out_free_memmap;
404
405 /* configure PM */
406 ret = wl1271_acx_pm_config(wl);
407 if (ret < 0)
408 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409
410 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200411
412 out_free_memmap:
413 kfree(wl->target_mem_map);
414 wl->target_mem_map = NULL;
415
416 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300417}
418
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300419static void wl1271_fw_status(struct wl1271 *wl,
420 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300421{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200422 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423 u32 total = 0;
424 int i;
425
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200426 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427
428 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
429 "drv_rx_counter = %d, tx_results_counter = %d)",
430 status->intr,
431 status->fw_rx_counter,
432 status->drv_rx_counter,
433 status->tx_results_counter);
434
435 /* update number of available TX blocks */
436 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300437 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
438 wl->tx_blocks_freed[i];
439
440 wl->tx_blocks_freed[i] =
441 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 wl->tx_blocks_available += cnt;
443 total += cnt;
444 }
445
446 /* if more blocks are available now, schedule some tx work */
447 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300448 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300449
450 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200451 getnstimeofday(&ts);
452 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
453 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454}
455
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200456#define WL1271_IRQ_MAX_LOOPS 10
457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300458static void wl1271_irq_work(struct work_struct *work)
459{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300460 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300461 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200462 int loopcount = WL1271_IRQ_MAX_LOOPS;
463 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300464 struct wl1271 *wl =
465 container_of(work, struct wl1271, irq_work);
466
467 mutex_lock(&wl->mutex);
468
469 wl1271_debug(DEBUG_IRQ, "IRQ work");
470
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200471 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300472 goto out;
473
474 ret = wl1271_ps_elp_wakeup(wl, true);
475 if (ret < 0)
476 goto out;
477
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200478 spin_lock_irqsave(&wl->wl_lock, flags);
479 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
480 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
481 spin_unlock_irqrestore(&wl->wl_lock, flags);
482 loopcount--;
483
484 wl1271_fw_status(wl, wl->fw_status);
485 intr = le32_to_cpu(wl->fw_status->intr);
486 if (!intr) {
487 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
488 continue;
489 }
490
491 intr &= WL1271_INTR_MASK;
492
493 if (intr & WL1271_ACX_INTR_DATA) {
494 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
495
496 /* check for tx results */
497 if (wl->fw_status->tx_results_counter !=
498 (wl->tx_results_count & 0xff))
499 wl1271_tx_complete(wl);
500
501 wl1271_rx(wl, wl->fw_status);
502 }
503
504 if (intr & WL1271_ACX_INTR_EVENT_A) {
505 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
506 wl1271_event_handle(wl, 0);
507 }
508
509 if (intr & WL1271_ACX_INTR_EVENT_B) {
510 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
511 wl1271_event_handle(wl, 1);
512 }
513
514 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
515 wl1271_debug(DEBUG_IRQ,
516 "WL1271_ACX_INTR_INIT_COMPLETE");
517
518 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
519 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
520
521 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300522 }
523
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200524 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
525 ieee80211_queue_work(wl->hw, &wl->irq_work);
526 else
527 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
528 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530 wl1271_ps_elp_sleep(wl);
531
532out:
533 mutex_unlock(&wl->mutex);
534}
535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300536static int wl1271_fetch_firmware(struct wl1271 *wl)
537{
538 const struct firmware *fw;
539 int ret;
540
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200541 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300542
543 if (ret < 0) {
544 wl1271_error("could not get firmware: %d", ret);
545 return ret;
546 }
547
548 if (fw->size % 4) {
549 wl1271_error("firmware size is not multiple of 32 bits: %zu",
550 fw->size);
551 ret = -EILSEQ;
552 goto out;
553 }
554
555 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300556 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300557
558 if (!wl->fw) {
559 wl1271_error("could not allocate memory for the firmware");
560 ret = -ENOMEM;
561 goto out;
562 }
563
564 memcpy(wl->fw, fw->data, wl->fw_len);
565
566 ret = 0;
567
568out:
569 release_firmware(fw);
570
571 return ret;
572}
573
574static int wl1271_fetch_nvs(struct wl1271 *wl)
575{
576 const struct firmware *fw;
577 int ret;
578
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200579 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580
581 if (ret < 0) {
582 wl1271_error("could not get nvs file: %d", ret);
583 return ret;
584 }
585
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200586 if (fw->size != sizeof(struct wl1271_nvs_file)) {
587 wl1271_error("nvs size is not as expected: %zu != %zu",
588 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300589 ret = -EILSEQ;
590 goto out;
591 }
592
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200593 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300594
595 if (!wl->nvs) {
596 wl1271_error("could not allocate memory for the nvs file");
597 ret = -ENOMEM;
598 goto out;
599 }
600
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200601 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300603out:
604 release_firmware(fw);
605
606 return ret;
607}
608
609static void wl1271_fw_wakeup(struct wl1271 *wl)
610{
611 u32 elp_reg;
612
613 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300614 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300615}
616
617static int wl1271_setup(struct wl1271 *wl)
618{
619 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
620 if (!wl->fw_status)
621 return -ENOMEM;
622
623 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
624 if (!wl->tx_res_if) {
625 kfree(wl->fw_status);
626 return -ENOMEM;
627 }
628
629 INIT_WORK(&wl->irq_work, wl1271_irq_work);
630 INIT_WORK(&wl->tx_work, wl1271_tx_work);
631 return 0;
632}
633
634static int wl1271_chip_wakeup(struct wl1271 *wl)
635{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300636 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637 int ret = 0;
638
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200639 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640 wl1271_power_on(wl);
641 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200642 wl1271_io_reset(wl);
643 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300644
645 /* We don't need a real memory partition here, because we only want
646 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300647 memset(&partition, 0, sizeof(partition));
648 partition.reg.start = REGISTERS_BASE;
649 partition.reg.size = REGISTERS_DOWN_SIZE;
650 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651
652 /* ELP module wake up */
653 wl1271_fw_wakeup(wl);
654
655 /* whal_FwCtrl_BootSm() */
656
657 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200658 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659
660 /* 1. check if chip id is valid */
661
662 switch (wl->chip.id) {
663 case CHIP_ID_1271_PG10:
664 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
665 wl->chip.id);
666
667 ret = wl1271_setup(wl);
668 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 break;
671 case CHIP_ID_1271_PG20:
672 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
673 wl->chip.id);
674
675 ret = wl1271_setup(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 break;
679 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200680 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300681 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200682 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 }
684
685 if (wl->fw == NULL) {
686 ret = wl1271_fetch_firmware(wl);
687 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200688 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 }
690
691 /* No NVS from netlink, try to get it from the filesystem */
692 if (wl->nvs == NULL) {
693 ret = wl1271_fetch_nvs(wl);
694 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200695 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696 }
697
698out:
699 return ret;
700}
701
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300702int wl1271_plt_start(struct wl1271 *wl)
703{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200704 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705 int ret;
706
707 mutex_lock(&wl->mutex);
708
709 wl1271_notice("power up");
710
711 if (wl->state != WL1271_STATE_OFF) {
712 wl1271_error("cannot go into PLT state because not "
713 "in off state: %d", wl->state);
714 ret = -EBUSY;
715 goto out;
716 }
717
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718 while (retries) {
719 retries--;
720 ret = wl1271_chip_wakeup(wl);
721 if (ret < 0)
722 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300723
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200724 ret = wl1271_boot(wl);
725 if (ret < 0)
726 goto power_off;
727
728 ret = wl1271_plt_init(wl);
729 if (ret < 0)
730 goto irq_disable;
731
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200732 wl->state = WL1271_STATE_PLT;
733 wl1271_notice("firmware booted in PLT mode (%s)",
734 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300735 goto out;
736
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200737irq_disable:
738 wl1271_disable_interrupts(wl);
739 mutex_unlock(&wl->mutex);
740 /* Unlocking the mutex in the middle of handling is
741 inherently unsafe. In this case we deem it safe to do,
742 because we need to let any possibly pending IRQ out of
743 the system (and while we are WL1271_STATE_OFF the IRQ
744 work function will not do anything.) Also, any other
745 possible concurrent operations will fail due to the
746 current state, hence the wl1271 struct should be safe. */
747 cancel_work_sync(&wl->irq_work);
748 mutex_lock(&wl->mutex);
749power_off:
750 wl1271_power_off(wl);
751 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300752
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200753 wl1271_error("firmware boot in PLT mode failed despite %d retries",
754 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300755out:
756 mutex_unlock(&wl->mutex);
757
758 return ret;
759}
760
761int wl1271_plt_stop(struct wl1271 *wl)
762{
763 int ret = 0;
764
765 mutex_lock(&wl->mutex);
766
767 wl1271_notice("power down");
768
769 if (wl->state != WL1271_STATE_PLT) {
770 wl1271_error("cannot power down because not in PLT "
771 "state: %d", wl->state);
772 ret = -EBUSY;
773 goto out;
774 }
775
776 wl1271_disable_interrupts(wl);
777 wl1271_power_off(wl);
778
779 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300780 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781
782out:
783 mutex_unlock(&wl->mutex);
784
785 return ret;
786}
787
788
789static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
790{
791 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200792 struct ieee80211_conf *conf = &hw->conf;
793 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
794 struct ieee80211_sta *sta = txinfo->control.sta;
795 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200797 /* peek into the rates configured in the STA entry */
798 spin_lock_irqsave(&wl->wl_lock, flags);
799 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
800 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
801 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
802 }
803 spin_unlock_irqrestore(&wl->wl_lock, flags);
804
805 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806 skb_queue_tail(&wl->tx_queue, skb);
807
808 /*
809 * The chip specific setup must run before the first TX packet -
810 * before that, the tx_work will not be initialized!
811 */
812
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300813 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300814
815 /*
816 * The workqueue is slow to process the tx_queue and we need stop
817 * the queue here, otherwise the queue will get too long.
818 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200819 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
820 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300821
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200822 spin_lock_irqsave(&wl->wl_lock, flags);
823 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200824 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200825 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300826 }
827
828 return NETDEV_TX_OK;
829}
830
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300831static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
832 void *arg)
833{
834 struct net_device *dev;
835 struct wireless_dev *wdev;
836 struct wiphy *wiphy;
837 struct ieee80211_hw *hw;
838 struct wl1271 *wl;
839 struct wl1271 *wl_temp;
840 struct in_device *idev;
841 struct in_ifaddr *ifa = arg;
842 int ret = 0;
843
844 /* FIXME: this ugly function should probably be implemented in the
845 * mac80211, and here should only be a simple callback handling actual
846 * setting of the filters. Now we need to dig up references to
847 * various structures to gain access to what we need.
848 * Also, because of this, there is no "initial" setting of the filter
849 * in "op_start", because we don't want to dig up struct net_device
850 * there - the filter will be set upon first change of the interface
851 * IP address. */
852
853 dev = ifa->ifa_dev->dev;
854
855 wdev = dev->ieee80211_ptr;
856 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200857 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300858
859 wiphy = wdev->wiphy;
860 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200861 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300862
863 hw = wiphy_priv(wiphy);
864 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200865 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300866
867 /* Check that the interface is one supported by this driver. */
868 wl_temp = hw->priv;
869 list_for_each_entry(wl, &wl_list, list) {
870 if (wl == wl_temp)
871 break;
872 }
873 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200874 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300875
876 /* Get the interface IP address for the device. "ifa" will become
877 NULL if:
878 - there is no IPV4 protocol address configured
879 - there are multiple (virtual) IPV4 addresses configured
880 When "ifa" is NULL, filtering will be disabled.
881 */
882 ifa = NULL;
883 idev = dev->ip_ptr;
884 if (idev)
885 ifa = idev->ifa_list;
886
887 if (ifa && ifa->ifa_next)
888 ifa = NULL;
889
890 mutex_lock(&wl->mutex);
891
892 if (wl->state == WL1271_STATE_OFF)
893 goto out;
894
895 ret = wl1271_ps_elp_wakeup(wl, false);
896 if (ret < 0)
897 goto out;
898 if (ifa)
899 ret = wl1271_acx_arp_ip_filter(wl, true,
900 (u8 *)&ifa->ifa_address,
901 ACX_IPV4_VERSION);
902 else
903 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
904 ACX_IPV4_VERSION);
905 wl1271_ps_elp_sleep(wl);
906
907out:
908 mutex_unlock(&wl->mutex);
909
Luciano Coelho17d72652009-11-23 23:22:15 +0200910 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300911}
912
913static struct notifier_block wl1271_dev_notifier = {
914 .notifier_call = wl1271_dev_notify,
915};
916
917
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918static int wl1271_op_start(struct ieee80211_hw *hw)
919{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200920 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
921
922 /*
923 * We have to delay the booting of the hardware because
924 * we need to know the local MAC address before downloading and
925 * initializing the firmware. The MAC address cannot be changed
926 * after boot, and without the proper MAC address, the firmware
927 * will not function properly.
928 *
929 * The MAC address is first known when the corresponding interface
930 * is added. That is where we will initialize the hardware.
931 */
932
933 return 0;
934}
935
936static void wl1271_op_stop(struct ieee80211_hw *hw)
937{
938 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
939}
940
941static int wl1271_op_add_interface(struct ieee80211_hw *hw,
942 struct ieee80211_vif *vif)
943{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300944 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200945 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 int ret = 0;
947
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200948 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
949 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950
951 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200952 if (wl->vif) {
953 ret = -EBUSY;
954 goto out;
955 }
956
957 wl->vif = vif;
958
959 switch (vif->type) {
960 case NL80211_IFTYPE_STATION:
961 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200962 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200963 break;
964 case NL80211_IFTYPE_ADHOC:
965 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200966 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200967 break;
968 default:
969 ret = -EOPNOTSUPP;
970 goto out;
971 }
972
973 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300974
975 if (wl->state != WL1271_STATE_OFF) {
976 wl1271_error("cannot start because not in off state: %d",
977 wl->state);
978 ret = -EBUSY;
979 goto out;
980 }
981
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200982 while (retries) {
983 retries--;
984 ret = wl1271_chip_wakeup(wl);
985 if (ret < 0)
986 goto power_off;
987
988 ret = wl1271_boot(wl);
989 if (ret < 0)
990 goto power_off;
991
992 ret = wl1271_hw_init(wl);
993 if (ret < 0)
994 goto irq_disable;
995
996 wl->state = WL1271_STATE_ON;
997 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 goto out;
999
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001000irq_disable:
1001 wl1271_disable_interrupts(wl);
1002 mutex_unlock(&wl->mutex);
1003 /* Unlocking the mutex in the middle of handling is
1004 inherently unsafe. In this case we deem it safe to do,
1005 because we need to let any possibly pending IRQ out of
1006 the system (and while we are WL1271_STATE_OFF the IRQ
1007 work function will not do anything.) Also, any other
1008 possible concurrent operations will fail due to the
1009 current state, hence the wl1271 struct should be safe. */
1010 cancel_work_sync(&wl->irq_work);
1011 mutex_lock(&wl->mutex);
1012power_off:
1013 wl1271_power_off(wl);
1014 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001015
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001016 wl1271_error("firmware boot failed despite %d retries",
1017 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001018out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 mutex_unlock(&wl->mutex);
1020
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001021 if (!ret) {
1022 list_add(&wl->list, &wl_list);
1023 register_inetaddr_notifier(&wl1271_dev_notifier);
1024 }
1025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 return ret;
1027}
1028
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001029static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1030 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031{
1032 struct wl1271 *wl = hw->priv;
1033 int i;
1034
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001035 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1036
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001037 mutex_lock(&wl->mutex);
1038 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001039
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001040 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001042 list_del(&wl->list);
1043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 WARN_ON(wl->state != WL1271_STATE_ON);
1045
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001046 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 mutex_unlock(&wl->mutex);
1048 ieee80211_scan_completed(wl->hw, true);
1049 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 }
1051
1052 wl->state = WL1271_STATE_OFF;
1053
1054 wl1271_disable_interrupts(wl);
1055
1056 mutex_unlock(&wl->mutex);
1057
1058 cancel_work_sync(&wl->irq_work);
1059 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060
1061 mutex_lock(&wl->mutex);
1062
1063 /* let's notify MAC80211 about the remaining pending TX frames */
1064 wl1271_tx_flush(wl);
1065 wl1271_power_off(wl);
1066
1067 memset(wl->bssid, 0, ETH_ALEN);
1068 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1069 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001071 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001072 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001073
1074 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001075 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001076 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1077 wl->tx_blocks_available = 0;
1078 wl->tx_results_count = 0;
1079 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001080 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001081 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 wl->time_offset = 0;
1083 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001084 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1085 wl->sta_rate_set = 0;
1086 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001087 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001088 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 for (i = 0; i < NUM_TX_QUEUES; i++)
1091 wl->tx_blocks_freed[i] = 0;
1092
1093 wl1271_debugfs_reset(wl);
1094 mutex_unlock(&wl->mutex);
1095}
1096
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001097static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1098{
1099 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1100 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1101
1102 /* combine requested filters with current filter config */
1103 filters = wl->filters | filters;
1104
1105 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1106
1107 if (filters & FIF_PROMISC_IN_BSS) {
1108 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1109 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1110 wl->rx_config |= CFG_BSSID_FILTER_EN;
1111 }
1112 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1113 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1114 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1115 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1116 }
1117 if (filters & FIF_OTHER_BSS) {
1118 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1119 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1120 }
1121 if (filters & FIF_CONTROL) {
1122 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1123 wl->rx_filter |= CFG_RX_CTL_EN;
1124 }
1125 if (filters & FIF_FCSFAIL) {
1126 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1127 wl->rx_filter |= CFG_RX_FCS_ERROR;
1128 }
1129}
1130
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001131static int wl1271_join_channel(struct wl1271 *wl, int channel)
1132{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001133 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001134 /* we need to use a dummy BSSID for now */
1135 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1136 0xad, 0xbe, 0xef };
1137
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001138 wl->channel = channel;
1139 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1140
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001141 /* pass through frames from all BSS */
1142 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1143
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001144 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001145 if (ret < 0)
1146 goto out;
1147
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001148 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001149
1150out:
1151 return ret;
1152}
1153
1154static int wl1271_unjoin_channel(struct wl1271 *wl)
1155{
1156 int ret;
1157
1158 /* to stop listening to a channel, we disconnect */
1159 ret = wl1271_cmd_disconnect(wl);
1160 if (ret < 0)
1161 goto out;
1162
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001163 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001164 wl->channel = 0;
1165 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001166
1167 /* stop filterting packets based on bssid */
1168 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001169
1170out:
1171 return ret;
1172}
1173
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001174static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1175{
1176 struct wl1271 *wl = hw->priv;
1177 struct ieee80211_conf *conf = &hw->conf;
1178 int channel, ret = 0;
1179
1180 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1181
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001182 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 channel,
1184 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001185 conf->power_level,
1186 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001187
1188 mutex_lock(&wl->mutex);
1189
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001190 wl->band = conf->channel->band;
1191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 ret = wl1271_ps_elp_wakeup(wl, false);
1193 if (ret < 0)
1194 goto out;
1195
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001196 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001197 if (conf->flags & IEEE80211_CONF_IDLE &&
1198 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001199 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001200 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001201 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001202
1203 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001204 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1205 wl->sta_rate_set = 0;
1206 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001207 wl1271_acx_keep_alive_config(
1208 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1209 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001210 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 }
1212
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001213 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001214 if (channel != wl->channel &&
1215 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1216 wl->channel = channel;
1217 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001218 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001219 if (ret < 0)
1220 wl1271_warning("cmd join to update channel failed %d",
1221 ret);
1222 } else
1223 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001224
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001225 if (conf->flags & IEEE80211_CONF_PS &&
1226 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1227 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228
1229 /*
1230 * We enter PSM only if we're already associated.
1231 * If we're not, we'll enter it when joining an SSID,
1232 * through the bss_info_changed() hook.
1233 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001234 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001235 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001236 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1237 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001238 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001240 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001241 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001243 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001245 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001246 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1247 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248 }
1249
1250 if (conf->power_level != wl->power_level) {
1251 ret = wl1271_acx_tx_power(wl, conf->power_level);
1252 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001253 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 wl->power_level = conf->power_level;
1256 }
1257
1258out_sleep:
1259 wl1271_ps_elp_sleep(wl);
1260
1261out:
1262 mutex_unlock(&wl->mutex);
1263
1264 return ret;
1265}
1266
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001267struct wl1271_filter_params {
1268 bool enabled;
1269 int mc_list_length;
1270 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1271};
1272
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001273static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1274 struct dev_addr_list *mc_list)
1275{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001276 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001277 int i;
1278
Juuso Oikarinen74441132009-10-13 12:47:53 +03001279 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001280 if (!fp) {
1281 wl1271_error("Out of memory setting filters.");
1282 return 0;
1283 }
1284
1285 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001286 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001287 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1288 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001289 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001290 }
1291
1292 fp->mc_list_length = 0;
1293 for (i = 0; i < mc_count; i++) {
1294 if (mc_list->da_addrlen == ETH_ALEN) {
1295 memcpy(fp->mc_list[fp->mc_list_length],
1296 mc_list->da_addr, ETH_ALEN);
1297 fp->mc_list_length++;
1298 } else
1299 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001300 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001301 }
1302
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001303 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001304}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001306#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1307 FIF_ALLMULTI | \
1308 FIF_FCSFAIL | \
1309 FIF_BCN_PRBRESP_PROMISC | \
1310 FIF_CONTROL | \
1311 FIF_OTHER_BSS)
1312
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1314 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001315 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001317 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001319 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
1321 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1322
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001323 mutex_lock(&wl->mutex);
1324
1325 if (wl->state == WL1271_STATE_OFF)
1326 goto out;
1327
1328 ret = wl1271_ps_elp_wakeup(wl, false);
1329 if (ret < 0)
1330 goto out;
1331
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332 *total &= WL1271_SUPPORTED_FILTERS;
1333 changed &= WL1271_SUPPORTED_FILTERS;
1334
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001335 if (*total & FIF_ALLMULTI)
1336 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1337 else if (fp)
1338 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1339 fp->mc_list,
1340 fp->mc_list_length);
1341 if (ret < 0)
1342 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 /* determine, whether supported filter values have changed */
1345 if (changed == 0)
1346 goto out_sleep;
1347
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001348 /* configure filters */
1349 wl->filters = *total;
1350 wl1271_configure_filters(wl, 0);
1351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352 /* apply configured filters */
1353 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1354 if (ret < 0)
1355 goto out_sleep;
1356
1357out_sleep:
1358 wl1271_ps_elp_sleep(wl);
1359
1360out:
1361 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001362 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363}
1364
1365static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1366 struct ieee80211_vif *vif,
1367 struct ieee80211_sta *sta,
1368 struct ieee80211_key_conf *key_conf)
1369{
1370 struct wl1271 *wl = hw->priv;
1371 const u8 *addr;
1372 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001373 u32 tx_seq_32 = 0;
1374 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375 u8 key_type;
1376
1377 static const u8 bcast_addr[ETH_ALEN] =
1378 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1379
1380 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1381
1382 addr = sta ? sta->addr : bcast_addr;
1383
1384 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1385 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1386 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1387 key_conf->alg, key_conf->keyidx,
1388 key_conf->keylen, key_conf->flags);
1389 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1390
1391 if (is_zero_ether_addr(addr)) {
1392 /* We dont support TX only encryption */
1393 ret = -EOPNOTSUPP;
1394 goto out;
1395 }
1396
1397 mutex_lock(&wl->mutex);
1398
1399 ret = wl1271_ps_elp_wakeup(wl, false);
1400 if (ret < 0)
1401 goto out_unlock;
1402
1403 switch (key_conf->alg) {
1404 case ALG_WEP:
1405 key_type = KEY_WEP;
1406
1407 key_conf->hw_key_idx = key_conf->keyidx;
1408 break;
1409 case ALG_TKIP:
1410 key_type = KEY_TKIP;
1411
1412 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001413 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1414 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415 break;
1416 case ALG_CCMP:
1417 key_type = KEY_AES;
1418
1419 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001420 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1421 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422 break;
1423 default:
1424 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1425
1426 ret = -EOPNOTSUPP;
1427 goto out_sleep;
1428 }
1429
1430 switch (cmd) {
1431 case SET_KEY:
1432 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1433 key_conf->keyidx, key_type,
1434 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001435 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 if (ret < 0) {
1437 wl1271_error("Could not add or replace key");
1438 goto out_sleep;
1439 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001440
1441 /* the default WEP key needs to be configured at least once */
1442 if (key_type == KEY_WEP) {
1443 ret = wl1271_cmd_set_default_wep_key(wl,
1444 wl->default_key);
1445 if (ret < 0)
1446 goto out_sleep;
1447 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448 break;
1449
1450 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001451 /* The wl1271 does not allow to remove unicast keys - they
1452 will be cleared automatically on next CMD_JOIN. Ignore the
1453 request silently, as we dont want the mac80211 to emit
1454 an error message. */
1455 if (!is_broadcast_ether_addr(addr))
1456 break;
1457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1459 key_conf->keyidx, key_type,
1460 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001461 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462 if (ret < 0) {
1463 wl1271_error("Could not remove key");
1464 goto out_sleep;
1465 }
1466 break;
1467
1468 default:
1469 wl1271_error("Unsupported key cmd 0x%x", cmd);
1470 ret = -EOPNOTSUPP;
1471 goto out_sleep;
1472
1473 break;
1474 }
1475
1476out_sleep:
1477 wl1271_ps_elp_sleep(wl);
1478
1479out_unlock:
1480 mutex_unlock(&wl->mutex);
1481
1482out:
1483 return ret;
1484}
1485
1486static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1487 struct cfg80211_scan_request *req)
1488{
1489 struct wl1271 *wl = hw->priv;
1490 int ret;
1491 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001492 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493
1494 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1495
1496 if (req->n_ssids) {
1497 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001498 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499 }
1500
1501 mutex_lock(&wl->mutex);
1502
1503 ret = wl1271_ps_elp_wakeup(wl, false);
1504 if (ret < 0)
1505 goto out;
1506
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001507 if (wl1271_11a_enabled())
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_DUAL, 3);
1511 else
Kalle Valo818e3062010-03-18 12:26:35 +02001512 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1513 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001514 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001515
1516 wl1271_ps_elp_sleep(wl);
1517
1518out:
1519 mutex_unlock(&wl->mutex);
1520
1521 return ret;
1522}
1523
1524static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1525{
1526 struct wl1271 *wl = hw->priv;
1527 int ret;
1528
1529 mutex_lock(&wl->mutex);
1530
1531 ret = wl1271_ps_elp_wakeup(wl, false);
1532 if (ret < 0)
1533 goto out;
1534
1535 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1536 if (ret < 0)
1537 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1538
1539 wl1271_ps_elp_sleep(wl);
1540
1541out:
1542 mutex_unlock(&wl->mutex);
1543
1544 return ret;
1545}
1546
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001547static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1548{
1549 u8 *ptr = beacon->data +
1550 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1551
1552 /* find the location of the ssid in the beacon */
1553 while (ptr < beacon->data + beacon->len) {
1554 if (ptr[0] == WLAN_EID_SSID) {
1555 wl->ssid_len = ptr[1];
1556 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1557 return;
1558 }
1559 ptr += ptr[1];
1560 }
1561 wl1271_error("ad-hoc beacon template has no SSID!\n");
1562}
1563
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001564static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1565 struct ieee80211_vif *vif,
1566 struct ieee80211_bss_conf *bss_conf,
1567 u32 changed)
1568{
1569 enum wl1271_cmd_ps_mode mode;
1570 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001571 bool do_join = false;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001572 bool do_keepalive = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573 int ret;
1574
1575 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1576
1577 mutex_lock(&wl->mutex);
1578
1579 ret = wl1271_ps_elp_wakeup(wl, false);
1580 if (ret < 0)
1581 goto out;
1582
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001583 if ((changed && BSS_CHANGED_BEACON_INT) &&
1584 (wl->bss_type == BSS_TYPE_IBSS)) {
1585 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1586 bss_conf->beacon_int);
1587
1588 wl->beacon_int = bss_conf->beacon_int;
1589 do_join = true;
1590 }
1591
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001592 if ((changed && BSS_CHANGED_BEACON) &&
1593 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001594 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1595
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001596 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1597
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001598 if (beacon) {
1599 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001600
1601 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001602 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1603 beacon->data,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +02001604 beacon->len, 0);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001605
1606 if (ret < 0) {
1607 dev_kfree_skb(beacon);
1608 goto out_sleep;
1609 }
1610
1611 hdr = (struct ieee80211_hdr *) beacon->data;
1612 hdr->frame_control = cpu_to_le16(
1613 IEEE80211_FTYPE_MGMT |
1614 IEEE80211_STYPE_PROBE_RESP);
1615
1616 ret = wl1271_cmd_template_set(wl,
1617 CMD_TEMPL_PROBE_RESPONSE,
1618 beacon->data,
Juuso Oikarinenbfb24c92010-03-26 12:53:31 +02001619 beacon->len, 0);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001620 dev_kfree_skb(beacon);
1621 if (ret < 0)
1622 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001623
1624 /* Need to update the SSID (for filtering etc) */
1625 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001626 }
1627 }
1628
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001629 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1630 (wl->bss_type == BSS_TYPE_IBSS)) {
1631 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1632 bss_conf->enable_beacon ? "enabled" : "disabled");
1633
1634 if (bss_conf->enable_beacon)
1635 wl->set_bss_type = BSS_TYPE_IBSS;
1636 else
1637 wl->set_bss_type = BSS_TYPE_STA_BSS;
1638 do_join = true;
1639 }
1640
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001641 if ((changed & BSS_CHANGED_BSSID) &&
1642 /*
1643 * Now we know the correct bssid, so we send a new join command
1644 * and enable the BSSID filter
1645 */
1646 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001647 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001648
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001649 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001650 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001651 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001652
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001653 /* filter out all packets not from this BSSID */
1654 wl1271_configure_filters(wl, 0);
1655
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001656 /* Need to update the BSSID (for filtering etc) */
1657 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001658 }
1659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001660 if (changed & BSS_CHANGED_ASSOC) {
1661 if (bss_conf->assoc) {
1662 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001663 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001665 /*
1666 * with wl1271, we don't need to update the
1667 * beacon_int and dtim_period, because the firmware
1668 * updates it by itself when the first beacon is
1669 * received after a join.
1670 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001671 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1672 if (ret < 0)
1673 goto out_sleep;
1674
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001675 /*
1676 * The SSID is intentionally set to NULL here - the
1677 * firmware will set the probe request with a
1678 * broadcast SSID regardless of what we set in the
1679 * template.
1680 */
1681 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1682 NULL, 0, wl->band);
1683
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001684 /* Enable the keep-alive feature */
1685 ret = wl1271_acx_keep_alive_mode(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 if (ret < 0)
1687 goto out_sleep;
1688
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001689 /*
1690 * This is awkward. The keep-alive configs must be done
1691 * *after* the join command, because otherwise it will
1692 * not work, but it must only be done *once* because
1693 * otherwise the firmware will start complaining.
1694 */
1695 do_keepalive = true;
1696
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001697 /* enable the connection monitoring feature */
1698 ret = wl1271_acx_conn_monit_params(wl, true);
1699 if (ret < 0)
1700 goto out_sleep;
1701
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001703 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1704 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001705 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001706 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001707 if (ret < 0)
1708 goto out_sleep;
1709 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001710 } else {
1711 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001712 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001713 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001714
1715 /* disable connection monitor features */
1716 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001717
1718 /* Disable the keep-alive feature */
1719 ret = wl1271_acx_keep_alive_mode(wl, false);
1720
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001721 if (ret < 0)
1722 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001725 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001726
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727 if (changed & BSS_CHANGED_ERP_SLOT) {
1728 if (bss_conf->use_short_slot)
1729 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1730 else
1731 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1732 if (ret < 0) {
1733 wl1271_warning("Set slot time failed %d", ret);
1734 goto out_sleep;
1735 }
1736 }
1737
1738 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1739 if (bss_conf->use_short_preamble)
1740 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1741 else
1742 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1743 }
1744
1745 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1746 if (bss_conf->use_cts_prot)
1747 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1748 else
1749 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1750 if (ret < 0) {
1751 wl1271_warning("Set ctsprotect failed %d", ret);
1752 goto out_sleep;
1753 }
1754 }
1755
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001756 if (do_join) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001757 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001758 if (ret < 0) {
1759 wl1271_warning("cmd join failed %d", ret);
1760 goto out_sleep;
1761 }
1762 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1763 }
1764
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001765 /*
1766 * The JOIN operation shuts down the firmware keep-alive as a side
1767 * effect, and the ACX_AID will start the keep-alive as a side effect.
1768 * Hence, for non-IBSS, the ACX_AID must always happen *after* the
1769 * JOIN operation, and the template config after the ACX_AID.
1770 */
1771 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
1772 ret = wl1271_acx_aid(wl, wl->aid);
1773 if (ret < 0)
1774 goto out_sleep;
Juuso Oikarinen40b359c2010-04-01 11:38:19 +03001775 }
1776
1777 if (do_keepalive) {
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001778 ret = wl1271_cmd_build_klv_null_data(wl);
1779 if (ret < 0)
1780 goto out_sleep;
1781 ret = wl1271_acx_keep_alive_config(
1782 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1783 ACX_KEEP_ALIVE_TPL_VALID);
1784 if (ret < 0)
1785 goto out_sleep;
1786 }
1787
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788out_sleep:
1789 wl1271_ps_elp_sleep(wl);
1790
1791out:
1792 mutex_unlock(&wl->mutex);
1793}
1794
Kalle Valoc6999d82010-02-18 13:25:41 +02001795static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1796 const struct ieee80211_tx_queue_params *params)
1797{
1798 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001799 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001800 int ret;
1801
1802 mutex_lock(&wl->mutex);
1803
1804 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1805
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001806 ret = wl1271_ps_elp_wakeup(wl, false);
1807 if (ret < 0)
1808 goto out;
1809
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001810 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001811 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1812 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001813 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001814 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001815 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001816
Kalle Valo4695dc92010-03-18 12:26:38 +02001817 if (params->uapsd)
1818 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1819 else
1820 ps_scheme = CONF_PS_SCHEME_LEGACY;
1821
Kalle Valoc6999d82010-02-18 13:25:41 +02001822 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1823 CONF_CHANNEL_TYPE_EDCF,
1824 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001825 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001826 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001827 goto out_sleep;
1828
1829out_sleep:
1830 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001831
1832out:
1833 mutex_unlock(&wl->mutex);
1834
1835 return ret;
1836}
1837
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001838
1839/* can't be const, mac80211 writes to this */
1840static struct ieee80211_rate wl1271_rates[] = {
1841 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001842 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1843 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001845 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1846 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1848 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001849 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1850 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1852 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001853 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1854 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1856 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001857 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1858 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001859 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001860 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1861 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001862 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001863 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1864 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001866 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1867 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001869 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1870 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001872 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1873 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001874 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001875 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1876 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001878 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1879 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880};
1881
1882/* can't be const, mac80211 writes to this */
1883static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001884 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1885 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1886 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1887 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1888 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1889 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1890 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1891 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1892 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1893 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1894 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1895 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1896 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897};
1898
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001899/* mapping to indexes for wl1271_rates */
1900const static u8 wl1271_rate_to_idx_2ghz[] = {
1901 /* MCS rates are used only with 11n */
1902 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1903 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1904 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1905 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1906 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1907 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1908 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1909 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1910
1911 11, /* CONF_HW_RXTX_RATE_54 */
1912 10, /* CONF_HW_RXTX_RATE_48 */
1913 9, /* CONF_HW_RXTX_RATE_36 */
1914 8, /* CONF_HW_RXTX_RATE_24 */
1915
1916 /* TI-specific rate */
1917 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
1918
1919 7, /* CONF_HW_RXTX_RATE_18 */
1920 6, /* CONF_HW_RXTX_RATE_12 */
1921 3, /* CONF_HW_RXTX_RATE_11 */
1922 5, /* CONF_HW_RXTX_RATE_9 */
1923 4, /* CONF_HW_RXTX_RATE_6 */
1924 2, /* CONF_HW_RXTX_RATE_5_5 */
1925 1, /* CONF_HW_RXTX_RATE_2 */
1926 0 /* CONF_HW_RXTX_RATE_1 */
1927};
1928
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929/* can't be const, mac80211 writes to this */
1930static struct ieee80211_supported_band wl1271_band_2ghz = {
1931 .channels = wl1271_channels,
1932 .n_channels = ARRAY_SIZE(wl1271_channels),
1933 .bitrates = wl1271_rates,
1934 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1935};
1936
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001937/* 5 GHz data rates for WL1273 */
1938static struct ieee80211_rate wl1271_rates_5ghz[] = {
1939 { .bitrate = 60,
1940 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1941 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1942 { .bitrate = 90,
1943 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1944 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1945 { .bitrate = 120,
1946 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1947 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1948 { .bitrate = 180,
1949 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1950 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1951 { .bitrate = 240,
1952 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1953 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1954 { .bitrate = 360,
1955 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1956 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1957 { .bitrate = 480,
1958 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1959 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1960 { .bitrate = 540,
1961 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1962 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1963};
1964
1965/* 5 GHz band channels for WL1273 */
1966static struct ieee80211_channel wl1271_channels_5ghz[] = {
1967 { .hw_value = 183, .center_freq = 4915},
1968 { .hw_value = 184, .center_freq = 4920},
1969 { .hw_value = 185, .center_freq = 4925},
1970 { .hw_value = 187, .center_freq = 4935},
1971 { .hw_value = 188, .center_freq = 4940},
1972 { .hw_value = 189, .center_freq = 4945},
1973 { .hw_value = 192, .center_freq = 4960},
1974 { .hw_value = 196, .center_freq = 4980},
1975 { .hw_value = 7, .center_freq = 5035},
1976 { .hw_value = 8, .center_freq = 5040},
1977 { .hw_value = 9, .center_freq = 5045},
1978 { .hw_value = 11, .center_freq = 5055},
1979 { .hw_value = 12, .center_freq = 5060},
1980 { .hw_value = 16, .center_freq = 5080},
1981 { .hw_value = 34, .center_freq = 5170},
1982 { .hw_value = 36, .center_freq = 5180},
1983 { .hw_value = 38, .center_freq = 5190},
1984 { .hw_value = 40, .center_freq = 5200},
1985 { .hw_value = 42, .center_freq = 5210},
1986 { .hw_value = 44, .center_freq = 5220},
1987 { .hw_value = 46, .center_freq = 5230},
1988 { .hw_value = 48, .center_freq = 5240},
1989 { .hw_value = 52, .center_freq = 5260},
1990 { .hw_value = 56, .center_freq = 5280},
1991 { .hw_value = 60, .center_freq = 5300},
1992 { .hw_value = 64, .center_freq = 5320},
1993 { .hw_value = 100, .center_freq = 5500},
1994 { .hw_value = 104, .center_freq = 5520},
1995 { .hw_value = 108, .center_freq = 5540},
1996 { .hw_value = 112, .center_freq = 5560},
1997 { .hw_value = 116, .center_freq = 5580},
1998 { .hw_value = 120, .center_freq = 5600},
1999 { .hw_value = 124, .center_freq = 5620},
2000 { .hw_value = 128, .center_freq = 5640},
2001 { .hw_value = 132, .center_freq = 5660},
2002 { .hw_value = 136, .center_freq = 5680},
2003 { .hw_value = 140, .center_freq = 5700},
2004 { .hw_value = 149, .center_freq = 5745},
2005 { .hw_value = 153, .center_freq = 5765},
2006 { .hw_value = 157, .center_freq = 5785},
2007 { .hw_value = 161, .center_freq = 5805},
2008 { .hw_value = 165, .center_freq = 5825},
2009};
2010
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002011/* mapping to indexes for wl1271_rates_5ghz */
2012const static u8 wl1271_rate_to_idx_5ghz[] = {
2013 /* MCS rates are used only with 11n */
2014 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2015 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2016 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2017 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2018 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2019 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2020 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2021 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2022
2023 7, /* CONF_HW_RXTX_RATE_54 */
2024 6, /* CONF_HW_RXTX_RATE_48 */
2025 5, /* CONF_HW_RXTX_RATE_36 */
2026 4, /* CONF_HW_RXTX_RATE_24 */
2027
2028 /* TI-specific rate */
2029 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2030
2031 3, /* CONF_HW_RXTX_RATE_18 */
2032 2, /* CONF_HW_RXTX_RATE_12 */
2033 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2034 1, /* CONF_HW_RXTX_RATE_9 */
2035 0, /* CONF_HW_RXTX_RATE_6 */
2036 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2037 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2038 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2039};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002040
2041static struct ieee80211_supported_band wl1271_band_5ghz = {
2042 .channels = wl1271_channels_5ghz,
2043 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2044 .bitrates = wl1271_rates_5ghz,
2045 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2046};
2047
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002048const static u8 *wl1271_band_rate_to_idx[] = {
2049 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2050 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2051};
2052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053static const struct ieee80211_ops wl1271_ops = {
2054 .start = wl1271_op_start,
2055 .stop = wl1271_op_stop,
2056 .add_interface = wl1271_op_add_interface,
2057 .remove_interface = wl1271_op_remove_interface,
2058 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002059 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 .configure_filter = wl1271_op_configure_filter,
2061 .tx = wl1271_op_tx,
2062 .set_key = wl1271_op_set_key,
2063 .hw_scan = wl1271_op_hw_scan,
2064 .bss_info_changed = wl1271_op_bss_info_changed,
2065 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002066 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002067 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068};
2069
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002070
2071u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2072{
2073 u8 idx;
2074
2075 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2076
2077 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2078 wl1271_error("Illegal RX rate from HW: %d", rate);
2079 return 0;
2080 }
2081
2082 idx = wl1271_band_rate_to_idx[wl->band][rate];
2083 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2084 wl1271_error("Unsupported RX rate from HW: %d", rate);
2085 return 0;
2086 }
2087
2088 return idx;
2089}
2090
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002091static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2092 struct device_attribute *attr,
2093 char *buf)
2094{
2095 struct wl1271 *wl = dev_get_drvdata(dev);
2096 ssize_t len;
2097
2098 /* FIXME: what's the maximum length of buf? page size?*/
2099 len = 500;
2100
2101 mutex_lock(&wl->mutex);
2102 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2103 wl->sg_enabled);
2104 mutex_unlock(&wl->mutex);
2105
2106 return len;
2107
2108}
2109
2110static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2111 struct device_attribute *attr,
2112 const char *buf, size_t count)
2113{
2114 struct wl1271 *wl = dev_get_drvdata(dev);
2115 unsigned long res;
2116 int ret;
2117
2118 ret = strict_strtoul(buf, 10, &res);
2119
2120 if (ret < 0) {
2121 wl1271_warning("incorrect value written to bt_coex_mode");
2122 return count;
2123 }
2124
2125 mutex_lock(&wl->mutex);
2126
2127 res = !!res;
2128
2129 if (res == wl->sg_enabled)
2130 goto out;
2131
2132 wl->sg_enabled = res;
2133
2134 if (wl->state == WL1271_STATE_OFF)
2135 goto out;
2136
2137 ret = wl1271_ps_elp_wakeup(wl, false);
2138 if (ret < 0)
2139 goto out;
2140
2141 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2142 wl1271_ps_elp_sleep(wl);
2143
2144 out:
2145 mutex_unlock(&wl->mutex);
2146 return count;
2147}
2148
2149static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2150 wl1271_sysfs_show_bt_coex_state,
2151 wl1271_sysfs_store_bt_coex_state);
2152
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002153int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002154{
2155 int ret;
2156
2157 if (wl->mac80211_registered)
2158 return 0;
2159
2160 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2161
2162 ret = ieee80211_register_hw(wl->hw);
2163 if (ret < 0) {
2164 wl1271_error("unable to register mac80211 hw: %d", ret);
2165 return ret;
2166 }
2167
2168 wl->mac80211_registered = true;
2169
2170 wl1271_notice("loaded");
2171
2172 return 0;
2173}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002174EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002175
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002176void wl1271_unregister_hw(struct wl1271 *wl)
2177{
2178 ieee80211_unregister_hw(wl->hw);
2179 wl->mac80211_registered = false;
2180
2181}
2182EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2183
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002184int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002186 /* The tx descriptor buffer and the TKIP space. */
2187 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2188 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189
2190 /* unit us */
2191 /* FIXME: find a proper value */
2192 wl->hw->channel_change_time = 10000;
2193
2194 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002195 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002196 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002197 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002198 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002199 IEEE80211_HW_HAS_RATE_CONTROL |
2200 IEEE80211_HW_CONNECTION_MONITOR;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002202 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2203 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204 wl->hw->wiphy->max_scan_ssids = 1;
2205 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2206
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002207 if (wl1271_11a_enabled())
2208 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2209
Kalle Valo12bd8942010-03-18 12:26:33 +02002210 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002211 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002212
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002213 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214
2215 return 0;
2216}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002217EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002220
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002221struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002222{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002224 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002225 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002226 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002227
2228 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2229 if (!hw) {
2230 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002231 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002232 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002233 }
2234
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002235 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2236 if (!plat_dev) {
2237 wl1271_error("could not allocate platform_device");
2238 ret = -ENOMEM;
2239 goto err_plat_alloc;
2240 }
2241
2242 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2243
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002244 wl = hw->priv;
2245 memset(wl, 0, sizeof(*wl));
2246
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002247 INIT_LIST_HEAD(&wl->list);
2248
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002249 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002250 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002251
2252 skb_queue_head_init(&wl->tx_queue);
2253
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002254 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002255 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002256 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 wl->rx_counter = 0;
2259 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2260 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002261 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002263 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002264 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2265 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002266 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002267 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002268 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002269 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002271 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002272 wl->tx_frames[i] = NULL;
2273
2274 spin_lock_init(&wl->wl_lock);
2275
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276 wl->state = WL1271_STATE_OFF;
2277 mutex_init(&wl->mutex);
2278
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002279 /* Apply default driver configuration. */
2280 wl1271_conf_init(wl);
2281
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002282 wl1271_debugfs_init(wl);
2283
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002284 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002285 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002286 if (ret) {
2287 wl1271_error("couldn't register platform device");
2288 goto err_hw;
2289 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002290 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002291
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002292 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002293 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002294 if (ret < 0) {
2295 wl1271_error("failed to create sysfs file bt_coex_state");
2296 goto err_platform;
2297 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002298
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002299 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002300
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002301err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002302 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002303
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002304err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002305 wl1271_debugfs_exit(wl);
2306 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002307
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002308err_plat_alloc:
2309 ieee80211_free_hw(hw);
2310
2311err_hw_alloc:
2312
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002313 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002314}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002315EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002316
2317int wl1271_free_hw(struct wl1271 *wl)
2318{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002319 platform_device_unregister(wl->plat_dev);
2320 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002321
2322 wl1271_debugfs_exit(wl);
2323
2324 kfree(wl->target_mem_map);
2325 vfree(wl->fw);
2326 wl->fw = NULL;
2327 kfree(wl->nvs);
2328 wl->nvs = NULL;
2329
2330 kfree(wl->fw_status);
2331 kfree(wl->tx_res_if);
2332
2333 ieee80211_free_hw(wl->hw);
2334
2335 return 0;
2336}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002337EXPORT_SYMBOL_GPL(wl1271_free_hw);
2338
2339MODULE_LICENSE("GPL");
2340MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2341MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");