blob: d8cb51410b2fe1b16c48df2b267977da22b9618d [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 */
351 ret = wl1271_acx_conn_monit_params(wl);
352 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;
961 break;
962 case NL80211_IFTYPE_ADHOC:
963 wl->bss_type = BSS_TYPE_IBSS;
964 break;
965 default:
966 ret = -EOPNOTSUPP;
967 goto out;
968 }
969
970 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300971
972 if (wl->state != WL1271_STATE_OFF) {
973 wl1271_error("cannot start because not in off state: %d",
974 wl->state);
975 ret = -EBUSY;
976 goto out;
977 }
978
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200979 while (retries) {
980 retries--;
981 ret = wl1271_chip_wakeup(wl);
982 if (ret < 0)
983 goto power_off;
984
985 ret = wl1271_boot(wl);
986 if (ret < 0)
987 goto power_off;
988
989 ret = wl1271_hw_init(wl);
990 if (ret < 0)
991 goto irq_disable;
992
993 wl->state = WL1271_STATE_ON;
994 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 goto out;
996
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997irq_disable:
998 wl1271_disable_interrupts(wl);
999 mutex_unlock(&wl->mutex);
1000 /* Unlocking the mutex in the middle of handling is
1001 inherently unsafe. In this case we deem it safe to do,
1002 because we need to let any possibly pending IRQ out of
1003 the system (and while we are WL1271_STATE_OFF the IRQ
1004 work function will not do anything.) Also, any other
1005 possible concurrent operations will fail due to the
1006 current state, hence the wl1271 struct should be safe. */
1007 cancel_work_sync(&wl->irq_work);
1008 mutex_lock(&wl->mutex);
1009power_off:
1010 wl1271_power_off(wl);
1011 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001013 wl1271_error("firmware boot failed despite %d retries",
1014 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001015out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 mutex_unlock(&wl->mutex);
1017
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001018 if (!ret) {
1019 list_add(&wl->list, &wl_list);
1020 register_inetaddr_notifier(&wl1271_dev_notifier);
1021 }
1022
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 return ret;
1024}
1025
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001026static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1027 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028{
1029 struct wl1271 *wl = hw->priv;
1030 int i;
1031
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001032 mutex_lock(&wl->mutex);
1033 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001035 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001037 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1038 list_del(&wl->list);
1039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 WARN_ON(wl->state != WL1271_STATE_ON);
1041
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001042 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 mutex_unlock(&wl->mutex);
1044 ieee80211_scan_completed(wl->hw, true);
1045 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 }
1047
1048 wl->state = WL1271_STATE_OFF;
1049
1050 wl1271_disable_interrupts(wl);
1051
1052 mutex_unlock(&wl->mutex);
1053
1054 cancel_work_sync(&wl->irq_work);
1055 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 mutex_lock(&wl->mutex);
1058
1059 /* let's notify MAC80211 about the remaining pending TX frames */
1060 wl1271_tx_flush(wl);
1061 wl1271_power_off(wl);
1062
1063 memset(wl->bssid, 0, ETH_ALEN);
1064 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1065 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001067 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001070 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1072 wl->tx_blocks_available = 0;
1073 wl->tx_results_count = 0;
1074 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001075 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001076 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 wl->time_offset = 0;
1078 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001079 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1080 wl->sta_rate_set = 0;
1081 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001082 wl->vif = NULL;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 for (i = 0; i < NUM_TX_QUEUES; i++)
1085 wl->tx_blocks_freed[i] = 0;
1086
1087 wl1271_debugfs_reset(wl);
1088 mutex_unlock(&wl->mutex);
1089}
1090
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091#if 0
1092static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1093 struct ieee80211_vif *vif,
1094 struct ieee80211_if_conf *conf)
1095{
1096 struct wl1271 *wl = hw->priv;
1097 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098 int ret;
1099
David S. Miller32646902009-09-17 10:18:30 -07001100 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1101 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001102 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1103 conf->ssid_len);
1104
1105 mutex_lock(&wl->mutex);
1106
1107 ret = wl1271_ps_elp_wakeup(wl, false);
1108 if (ret < 0)
1109 goto out;
1110
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001111 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1112 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1113
1114 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1115
Juuso Oikarinen15305492010-02-22 08:38:32 +02001116 ret = wl1271_cmd_join(wl, wl->bss_type);
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001117 if (ret < 0)
1118 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001120 ret = wl1271_cmd_build_null_data(wl);
1121 if (ret < 0)
1122 goto out_sleep;
1123 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001124
1125 wl->ssid_len = conf->ssid_len;
1126 if (wl->ssid_len)
1127 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1128
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001129 if (conf->changed & IEEE80211_IFCC_BEACON) {
1130 beacon = ieee80211_beacon_get(hw, vif);
1131 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1132 beacon->data, beacon->len);
1133
1134 if (ret < 0) {
1135 dev_kfree_skb(beacon);
1136 goto out_sleep;
1137 }
1138
1139 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1140 beacon->data, beacon->len);
1141
1142 dev_kfree_skb(beacon);
1143
1144 if (ret < 0)
1145 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146 }
1147
1148out_sleep:
1149 wl1271_ps_elp_sleep(wl);
1150
1151out:
1152 mutex_unlock(&wl->mutex);
1153
1154 return ret;
1155}
1156#endif
1157
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001158static int wl1271_join_channel(struct wl1271 *wl, int channel)
1159{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001160 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001161 /* we need to use a dummy BSSID for now */
1162 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1163 0xad, 0xbe, 0xef };
1164
1165 /* disable mac filter, so we hear everything */
1166 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1167
1168 wl->channel = channel;
1169 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1170
Juuso Oikarinen15305492010-02-22 08:38:32 +02001171 /* the dummy join is performed always with STATION BSS type to allow
1172 also ad-hoc mode to listen to the surroundings without sending any
1173 beacons yet. */
1174 ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001175 if (ret < 0)
1176 goto out;
1177
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001178 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001179
1180out:
1181 return ret;
1182}
1183
1184static int wl1271_unjoin_channel(struct wl1271 *wl)
1185{
1186 int ret;
1187
1188 /* to stop listening to a channel, we disconnect */
1189 ret = wl1271_cmd_disconnect(wl);
1190 if (ret < 0)
1191 goto out;
1192
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001193 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001194 wl->channel = 0;
1195 memset(wl->bssid, 0, ETH_ALEN);
1196 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1197
1198out:
1199 return ret;
1200}
1201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1203{
1204 struct wl1271 *wl = hw->priv;
1205 struct ieee80211_conf *conf = &hw->conf;
1206 int channel, ret = 0;
1207
1208 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1209
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001210 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001211 channel,
1212 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001213 conf->power_level,
1214 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215
1216 mutex_lock(&wl->mutex);
1217
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001218 wl->band = conf->channel->band;
1219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 ret = wl1271_ps_elp_wakeup(wl, false);
1221 if (ret < 0)
1222 goto out;
1223
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001224 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001225 if (conf->flags & IEEE80211_CONF_IDLE &&
1226 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001227 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001228 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001229 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001230
1231 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001232 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1233 wl->sta_rate_set = 0;
1234 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236 }
1237
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001238 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001239 if (channel != wl->channel &&
1240 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1241 wl->channel = channel;
1242 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen15305492010-02-22 08:38:32 +02001243 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001244 if (ret < 0)
1245 wl1271_warning("cmd join to update channel failed %d",
1246 ret);
1247 } else
1248 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001249
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001250 if (conf->flags & IEEE80211_CONF_PS &&
1251 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1252 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253
1254 /*
1255 * We enter PSM only if we're already associated.
1256 * If we're not, we'll enter it when joining an SSID,
1257 * through the bss_info_changed() hook.
1258 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001259 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001260 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001261 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1262 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001263 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001264 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001265 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001266 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001268 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001270 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001271 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1272 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 }
1274
1275 if (conf->power_level != wl->power_level) {
1276 ret = wl1271_acx_tx_power(wl, conf->power_level);
1277 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001278 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279
1280 wl->power_level = conf->power_level;
1281 }
1282
1283out_sleep:
1284 wl1271_ps_elp_sleep(wl);
1285
1286out:
1287 mutex_unlock(&wl->mutex);
1288
1289 return ret;
1290}
1291
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001292struct wl1271_filter_params {
1293 bool enabled;
1294 int mc_list_length;
1295 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1296};
1297
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001298static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1299 struct dev_addr_list *mc_list)
1300{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001301 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001302 int i;
1303
Juuso Oikarinen74441132009-10-13 12:47:53 +03001304 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001305 if (!fp) {
1306 wl1271_error("Out of memory setting filters.");
1307 return 0;
1308 }
1309
1310 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001311 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001312 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1313 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001314 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001315 }
1316
1317 fp->mc_list_length = 0;
1318 for (i = 0; i < mc_count; i++) {
1319 if (mc_list->da_addrlen == ETH_ALEN) {
1320 memcpy(fp->mc_list[fp->mc_list_length],
1321 mc_list->da_addr, ETH_ALEN);
1322 fp->mc_list_length++;
1323 } else
1324 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001325 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 }
1327
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001328 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001331#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1332 FIF_ALLMULTI | \
1333 FIF_FCSFAIL | \
1334 FIF_BCN_PRBRESP_PROMISC | \
1335 FIF_CONTROL | \
1336 FIF_OTHER_BSS)
1337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1339 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001340 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001342 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001344 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001345
1346 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1347
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348 mutex_lock(&wl->mutex);
1349
1350 if (wl->state == WL1271_STATE_OFF)
1351 goto out;
1352
1353 ret = wl1271_ps_elp_wakeup(wl, false);
1354 if (ret < 0)
1355 goto out;
1356
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 *total &= WL1271_SUPPORTED_FILTERS;
1358 changed &= WL1271_SUPPORTED_FILTERS;
1359
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001360 if (*total & FIF_ALLMULTI)
1361 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1362 else if (fp)
1363 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1364 fp->mc_list,
1365 fp->mc_list_length);
1366 if (ret < 0)
1367 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001369 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001370
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001371 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001372
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001373 /* determine, whether supported filter values have changed */
1374 if (changed == 0)
1375 goto out_sleep;
1376
1377 /* apply configured filters */
1378 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1379 if (ret < 0)
1380 goto out_sleep;
1381
1382out_sleep:
1383 wl1271_ps_elp_sleep(wl);
1384
1385out:
1386 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001387}
1388
1389static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1390 struct ieee80211_vif *vif,
1391 struct ieee80211_sta *sta,
1392 struct ieee80211_key_conf *key_conf)
1393{
1394 struct wl1271 *wl = hw->priv;
1395 const u8 *addr;
1396 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001397 u32 tx_seq_32 = 0;
1398 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 u8 key_type;
1400
1401 static const u8 bcast_addr[ETH_ALEN] =
1402 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1403
1404 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1405
1406 addr = sta ? sta->addr : bcast_addr;
1407
1408 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1409 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1410 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1411 key_conf->alg, key_conf->keyidx,
1412 key_conf->keylen, key_conf->flags);
1413 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1414
1415 if (is_zero_ether_addr(addr)) {
1416 /* We dont support TX only encryption */
1417 ret = -EOPNOTSUPP;
1418 goto out;
1419 }
1420
1421 mutex_lock(&wl->mutex);
1422
1423 ret = wl1271_ps_elp_wakeup(wl, false);
1424 if (ret < 0)
1425 goto out_unlock;
1426
1427 switch (key_conf->alg) {
1428 case ALG_WEP:
1429 key_type = KEY_WEP;
1430
1431 key_conf->hw_key_idx = key_conf->keyidx;
1432 break;
1433 case ALG_TKIP:
1434 key_type = KEY_TKIP;
1435
1436 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001437 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1438 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439 break;
1440 case ALG_CCMP:
1441 key_type = KEY_AES;
1442
1443 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001444 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1445 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446 break;
1447 default:
1448 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1449
1450 ret = -EOPNOTSUPP;
1451 goto out_sleep;
1452 }
1453
1454 switch (cmd) {
1455 case SET_KEY:
1456 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1457 key_conf->keyidx, key_type,
1458 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001459 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 if (ret < 0) {
1461 wl1271_error("Could not add or replace key");
1462 goto out_sleep;
1463 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001464
1465 /* the default WEP key needs to be configured at least once */
1466 if (key_type == KEY_WEP) {
1467 ret = wl1271_cmd_set_default_wep_key(wl,
1468 wl->default_key);
1469 if (ret < 0)
1470 goto out_sleep;
1471 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 break;
1473
1474 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001475 /* The wl1271 does not allow to remove unicast keys - they
1476 will be cleared automatically on next CMD_JOIN. Ignore the
1477 request silently, as we dont want the mac80211 to emit
1478 an error message. */
1479 if (!is_broadcast_ether_addr(addr))
1480 break;
1481
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1483 key_conf->keyidx, key_type,
1484 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001485 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 if (ret < 0) {
1487 wl1271_error("Could not remove key");
1488 goto out_sleep;
1489 }
1490 break;
1491
1492 default:
1493 wl1271_error("Unsupported key cmd 0x%x", cmd);
1494 ret = -EOPNOTSUPP;
1495 goto out_sleep;
1496
1497 break;
1498 }
1499
1500out_sleep:
1501 wl1271_ps_elp_sleep(wl);
1502
1503out_unlock:
1504 mutex_unlock(&wl->mutex);
1505
1506out:
1507 return ret;
1508}
1509
1510static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1511 struct cfg80211_scan_request *req)
1512{
1513 struct wl1271 *wl = hw->priv;
1514 int ret;
1515 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001516 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
1518 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1519
1520 if (req->n_ssids) {
1521 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001522 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 }
1524
1525 mutex_lock(&wl->mutex);
1526
1527 ret = wl1271_ps_elp_wakeup(wl, false);
1528 if (ret < 0)
1529 goto out;
1530
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001531 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001532 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1533 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001534 WL1271_SCAN_BAND_DUAL, 3);
1535 else
Kalle Valo818e3062010-03-18 12:26:35 +02001536 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1537 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001538 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539
1540 wl1271_ps_elp_sleep(wl);
1541
1542out:
1543 mutex_unlock(&wl->mutex);
1544
1545 return ret;
1546}
1547
1548static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1549{
1550 struct wl1271 *wl = hw->priv;
1551 int ret;
1552
1553 mutex_lock(&wl->mutex);
1554
1555 ret = wl1271_ps_elp_wakeup(wl, false);
1556 if (ret < 0)
1557 goto out;
1558
1559 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1560 if (ret < 0)
1561 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1562
1563 wl1271_ps_elp_sleep(wl);
1564
1565out:
1566 mutex_unlock(&wl->mutex);
1567
1568 return ret;
1569}
1570
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001571static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1572{
1573 u8 *ptr = beacon->data +
1574 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1575
1576 /* find the location of the ssid in the beacon */
1577 while (ptr < beacon->data + beacon->len) {
1578 if (ptr[0] == WLAN_EID_SSID) {
1579 wl->ssid_len = ptr[1];
1580 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1581 return;
1582 }
1583 ptr += ptr[1];
1584 }
1585 wl1271_error("ad-hoc beacon template has no SSID!\n");
1586}
1587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1589 struct ieee80211_vif *vif,
1590 struct ieee80211_bss_conf *bss_conf,
1591 u32 changed)
1592{
1593 enum wl1271_cmd_ps_mode mode;
1594 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001595 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001596 int ret;
1597
1598 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1599
1600 mutex_lock(&wl->mutex);
1601
1602 ret = wl1271_ps_elp_wakeup(wl, false);
1603 if (ret < 0)
1604 goto out;
1605
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001606 if (wl->bss_type == BSS_TYPE_IBSS) {
1607 /* FIXME: This implements rudimentary ad-hoc support -
1608 proper templates are on the wish list and notification
1609 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001610 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001611 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1612
1613 if (beacon) {
1614 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001615
1616 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001617 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1618 beacon->data,
1619 beacon->len);
1620
1621 if (ret < 0) {
1622 dev_kfree_skb(beacon);
1623 goto out_sleep;
1624 }
1625
1626 hdr = (struct ieee80211_hdr *) beacon->data;
1627 hdr->frame_control = cpu_to_le16(
1628 IEEE80211_FTYPE_MGMT |
1629 IEEE80211_STYPE_PROBE_RESP);
1630
1631 ret = wl1271_cmd_template_set(wl,
1632 CMD_TEMPL_PROBE_RESPONSE,
1633 beacon->data,
1634 beacon->len);
1635 dev_kfree_skb(beacon);
1636 if (ret < 0)
1637 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001638
1639 /* Need to update the SSID (for filtering etc) */
1640 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001641 }
1642 }
1643
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001644 if ((changed & BSS_CHANGED_BSSID) &&
1645 /*
1646 * Now we know the correct bssid, so we send a new join command
1647 * and enable the BSSID filter
1648 */
1649 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1650 wl->rx_config |= CFG_BSSID_FILTER_EN;
1651 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1652 ret = wl1271_cmd_build_null_data(wl);
1653 if (ret < 0) {
1654 wl1271_warning("cmd buld null data failed %d",
1655 ret);
1656 goto out_sleep;
1657 }
1658
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001659 /* Need to update the BSSID (for filtering etc) */
1660 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001661 }
1662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663 if (changed & BSS_CHANGED_ASSOC) {
1664 if (bss_conf->assoc) {
1665 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001666 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001668 /*
1669 * with wl1271, we don't need to update the
1670 * beacon_int and dtim_period, because the firmware
1671 * updates it by itself when the first beacon is
1672 * received after a join.
1673 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001674 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1675 if (ret < 0)
1676 goto out_sleep;
1677
1678 ret = wl1271_acx_aid(wl, wl->aid);
1679 if (ret < 0)
1680 goto out_sleep;
1681
1682 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001683 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1684 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001686 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 if (ret < 0)
1688 goto out_sleep;
1689 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001690 } else {
1691 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001692 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001693 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001694 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001695
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001697
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 if (changed & BSS_CHANGED_ERP_SLOT) {
1699 if (bss_conf->use_short_slot)
1700 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1701 else
1702 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1703 if (ret < 0) {
1704 wl1271_warning("Set slot time failed %d", ret);
1705 goto out_sleep;
1706 }
1707 }
1708
1709 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1710 if (bss_conf->use_short_preamble)
1711 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1712 else
1713 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1714 }
1715
1716 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1717 if (bss_conf->use_cts_prot)
1718 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1719 else
1720 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1721 if (ret < 0) {
1722 wl1271_warning("Set ctsprotect failed %d", ret);
1723 goto out_sleep;
1724 }
1725 }
1726
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001727 if (do_join) {
Juuso Oikarinen15305492010-02-22 08:38:32 +02001728 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001729 if (ret < 0) {
1730 wl1271_warning("cmd join failed %d", ret);
1731 goto out_sleep;
1732 }
1733 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1734 }
1735
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001736out_sleep:
1737 wl1271_ps_elp_sleep(wl);
1738
1739out:
1740 mutex_unlock(&wl->mutex);
1741}
1742
Kalle Valoc6999d82010-02-18 13:25:41 +02001743static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1744 const struct ieee80211_tx_queue_params *params)
1745{
1746 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001747 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001748 int ret;
1749
1750 mutex_lock(&wl->mutex);
1751
1752 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1753
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001754 ret = wl1271_ps_elp_wakeup(wl, false);
1755 if (ret < 0)
1756 goto out;
1757
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001758 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001759 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1760 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001761 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001762 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001763 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001764
Kalle Valo4695dc92010-03-18 12:26:38 +02001765 if (params->uapsd)
1766 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1767 else
1768 ps_scheme = CONF_PS_SCHEME_LEGACY;
1769
Kalle Valoc6999d82010-02-18 13:25:41 +02001770 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1771 CONF_CHANNEL_TYPE_EDCF,
1772 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001773 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001774 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001775 goto out_sleep;
1776
1777out_sleep:
1778 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001779
1780out:
1781 mutex_unlock(&wl->mutex);
1782
1783 return ret;
1784}
1785
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001786
1787/* can't be const, mac80211 writes to this */
1788static struct ieee80211_rate wl1271_rates[] = {
1789 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001790 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1791 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001792 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001793 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1794 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1796 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001797 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1798 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1800 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001801 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1802 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1804 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001805 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1806 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001808 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1809 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001811 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1812 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001814 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1815 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001817 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1818 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001820 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1821 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001823 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1824 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001826 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1827 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001828};
1829
1830/* can't be const, mac80211 writes to this */
1831static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001832 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1833 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1834 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1835 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1836 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1837 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1838 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1839 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1840 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1841 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1842 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1843 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1844 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001845};
1846
1847/* can't be const, mac80211 writes to this */
1848static struct ieee80211_supported_band wl1271_band_2ghz = {
1849 .channels = wl1271_channels,
1850 .n_channels = ARRAY_SIZE(wl1271_channels),
1851 .bitrates = wl1271_rates,
1852 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1853};
1854
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001855/* 5 GHz data rates for WL1273 */
1856static struct ieee80211_rate wl1271_rates_5ghz[] = {
1857 { .bitrate = 60,
1858 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1859 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1860 { .bitrate = 90,
1861 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1862 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1863 { .bitrate = 120,
1864 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1865 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1866 { .bitrate = 180,
1867 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1868 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1869 { .bitrate = 240,
1870 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1871 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1872 { .bitrate = 360,
1873 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1874 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1875 { .bitrate = 480,
1876 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1877 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1878 { .bitrate = 540,
1879 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1880 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1881};
1882
1883/* 5 GHz band channels for WL1273 */
1884static struct ieee80211_channel wl1271_channels_5ghz[] = {
1885 { .hw_value = 183, .center_freq = 4915},
1886 { .hw_value = 184, .center_freq = 4920},
1887 { .hw_value = 185, .center_freq = 4925},
1888 { .hw_value = 187, .center_freq = 4935},
1889 { .hw_value = 188, .center_freq = 4940},
1890 { .hw_value = 189, .center_freq = 4945},
1891 { .hw_value = 192, .center_freq = 4960},
1892 { .hw_value = 196, .center_freq = 4980},
1893 { .hw_value = 7, .center_freq = 5035},
1894 { .hw_value = 8, .center_freq = 5040},
1895 { .hw_value = 9, .center_freq = 5045},
1896 { .hw_value = 11, .center_freq = 5055},
1897 { .hw_value = 12, .center_freq = 5060},
1898 { .hw_value = 16, .center_freq = 5080},
1899 { .hw_value = 34, .center_freq = 5170},
1900 { .hw_value = 36, .center_freq = 5180},
1901 { .hw_value = 38, .center_freq = 5190},
1902 { .hw_value = 40, .center_freq = 5200},
1903 { .hw_value = 42, .center_freq = 5210},
1904 { .hw_value = 44, .center_freq = 5220},
1905 { .hw_value = 46, .center_freq = 5230},
1906 { .hw_value = 48, .center_freq = 5240},
1907 { .hw_value = 52, .center_freq = 5260},
1908 { .hw_value = 56, .center_freq = 5280},
1909 { .hw_value = 60, .center_freq = 5300},
1910 { .hw_value = 64, .center_freq = 5320},
1911 { .hw_value = 100, .center_freq = 5500},
1912 { .hw_value = 104, .center_freq = 5520},
1913 { .hw_value = 108, .center_freq = 5540},
1914 { .hw_value = 112, .center_freq = 5560},
1915 { .hw_value = 116, .center_freq = 5580},
1916 { .hw_value = 120, .center_freq = 5600},
1917 { .hw_value = 124, .center_freq = 5620},
1918 { .hw_value = 128, .center_freq = 5640},
1919 { .hw_value = 132, .center_freq = 5660},
1920 { .hw_value = 136, .center_freq = 5680},
1921 { .hw_value = 140, .center_freq = 5700},
1922 { .hw_value = 149, .center_freq = 5745},
1923 { .hw_value = 153, .center_freq = 5765},
1924 { .hw_value = 157, .center_freq = 5785},
1925 { .hw_value = 161, .center_freq = 5805},
1926 { .hw_value = 165, .center_freq = 5825},
1927};
1928
1929
1930static struct ieee80211_supported_band wl1271_band_5ghz = {
1931 .channels = wl1271_channels_5ghz,
1932 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1933 .bitrates = wl1271_rates_5ghz,
1934 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1935};
1936
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937static const struct ieee80211_ops wl1271_ops = {
1938 .start = wl1271_op_start,
1939 .stop = wl1271_op_stop,
1940 .add_interface = wl1271_op_add_interface,
1941 .remove_interface = wl1271_op_remove_interface,
1942 .config = wl1271_op_config,
1943/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001944 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001945 .configure_filter = wl1271_op_configure_filter,
1946 .tx = wl1271_op_tx,
1947 .set_key = wl1271_op_set_key,
1948 .hw_scan = wl1271_op_hw_scan,
1949 .bss_info_changed = wl1271_op_bss_info_changed,
1950 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001951 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001952 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953};
1954
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02001955static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
1956 struct device_attribute *attr,
1957 char *buf)
1958{
1959 struct wl1271 *wl = dev_get_drvdata(dev);
1960 ssize_t len;
1961
1962 /* FIXME: what's the maximum length of buf? page size?*/
1963 len = 500;
1964
1965 mutex_lock(&wl->mutex);
1966 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
1967 wl->sg_enabled);
1968 mutex_unlock(&wl->mutex);
1969
1970 return len;
1971
1972}
1973
1974static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
1975 struct device_attribute *attr,
1976 const char *buf, size_t count)
1977{
1978 struct wl1271 *wl = dev_get_drvdata(dev);
1979 unsigned long res;
1980 int ret;
1981
1982 ret = strict_strtoul(buf, 10, &res);
1983
1984 if (ret < 0) {
1985 wl1271_warning("incorrect value written to bt_coex_mode");
1986 return count;
1987 }
1988
1989 mutex_lock(&wl->mutex);
1990
1991 res = !!res;
1992
1993 if (res == wl->sg_enabled)
1994 goto out;
1995
1996 wl->sg_enabled = res;
1997
1998 if (wl->state == WL1271_STATE_OFF)
1999 goto out;
2000
2001 ret = wl1271_ps_elp_wakeup(wl, false);
2002 if (ret < 0)
2003 goto out;
2004
2005 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2006 wl1271_ps_elp_sleep(wl);
2007
2008 out:
2009 mutex_unlock(&wl->mutex);
2010 return count;
2011}
2012
2013static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2014 wl1271_sysfs_show_bt_coex_state,
2015 wl1271_sysfs_store_bt_coex_state);
2016
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002017int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002018{
2019 int ret;
2020
2021 if (wl->mac80211_registered)
2022 return 0;
2023
2024 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2025
2026 ret = ieee80211_register_hw(wl->hw);
2027 if (ret < 0) {
2028 wl1271_error("unable to register mac80211 hw: %d", ret);
2029 return ret;
2030 }
2031
2032 wl->mac80211_registered = true;
2033
2034 wl1271_notice("loaded");
2035
2036 return 0;
2037}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002038EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002040int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002042 /* The tx descriptor buffer and the TKIP space. */
2043 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2044 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002045
2046 /* unit us */
2047 /* FIXME: find a proper value */
2048 wl->hw->channel_change_time = 10000;
2049
2050 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002051 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002052 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002053 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002054 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002055 IEEE80211_HW_HAS_RATE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002057 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2058 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059 wl->hw->wiphy->max_scan_ssids = 1;
2060 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2061
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002062 if (wl1271_11a_enabled())
2063 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2064
Kalle Valo12bd8942010-03-18 12:26:33 +02002065 wl->hw->queues = 4;
2066
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002067 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068
2069 return 0;
2070}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002071EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002073#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002074
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002075struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077 struct ieee80211_hw *hw;
2078 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002079 int i, ret;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002080 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002081
2082 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2083 if (!hw) {
2084 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002085 ret = -ENOMEM;
2086 goto err;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 }
2088
2089 wl = hw->priv;
2090 memset(wl, 0, sizeof(*wl));
2091
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002092 INIT_LIST_HEAD(&wl->list);
2093
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002094 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095
2096 skb_queue_head_init(&wl->tx_queue);
2097
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002098 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002101 wl->rx_counter = 0;
2102 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2103 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002104 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002105 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002106 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002107 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2108 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002109 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002110 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002111 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002112 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002114 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002115 wl->tx_frames[i] = NULL;
2116
2117 spin_lock_init(&wl->wl_lock);
2118
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119 wl->state = WL1271_STATE_OFF;
2120 mutex_init(&wl->mutex);
2121
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002122 /*
2123 * FIXME: we should use a zero MAC address here, but for now we
2124 * generate a random Nokia address.
2125 */
2126 memcpy(wl->mac_addr, nokia_oui, 3);
2127 get_random_bytes(wl->mac_addr + 3, 3);
2128
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002129 /* Apply default driver configuration. */
2130 wl1271_conf_init(wl);
2131
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002132 wl1271_debugfs_init(wl);
2133
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002134 /* Register platform device */
2135 ret = platform_device_register(&wl1271_device);
2136 if (ret) {
2137 wl1271_error("couldn't register platform device");
2138 goto err_hw;
2139 }
2140 dev_set_drvdata(&wl1271_device.dev, wl);
2141
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002142 /* Create sysfs file to control bt coex state */
2143 ret = device_create_file(&wl1271_device.dev, &dev_attr_bt_coex_state);
2144 if (ret < 0) {
2145 wl1271_error("failed to create sysfs file bt_coex_state");
2146 goto err_platform;
2147 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002148
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002149 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002150
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002151err_platform:
2152 platform_device_unregister(&wl1271_device);
2153
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002154err_hw:
2155 ieee80211_unregister_hw(wl->hw);
2156
2157err:
2158 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002159}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002160EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002161
2162int wl1271_free_hw(struct wl1271 *wl)
2163{
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002164 platform_device_unregister(&wl1271_device);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002165 ieee80211_unregister_hw(wl->hw);
2166
2167 wl1271_debugfs_exit(wl);
2168
2169 kfree(wl->target_mem_map);
2170 vfree(wl->fw);
2171 wl->fw = NULL;
2172 kfree(wl->nvs);
2173 wl->nvs = NULL;
2174
2175 kfree(wl->fw_status);
2176 kfree(wl->tx_res_if);
2177
2178 ieee80211_free_hw(wl->hw);
2179
2180 return 0;
2181}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002182EXPORT_SYMBOL_GPL(wl1271_free_hw);
2183
2184MODULE_LICENSE("GPL");
2185MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2186MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");