blob: abf9f22ee96862fa1f7277842fde8d2ce852461b [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
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200573static int wl1271_update_mac_addr(struct wl1271 *wl)
574{
575 int ret = 0;
576 u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
577
578 /* get mac address from the NVS */
579 wl->mac_addr[0] = nvs_ptr[11];
580 wl->mac_addr[1] = nvs_ptr[10];
581 wl->mac_addr[2] = nvs_ptr[6];
582 wl->mac_addr[3] = nvs_ptr[5];
583 wl->mac_addr[4] = nvs_ptr[4];
584 wl->mac_addr[5] = nvs_ptr[3];
585
586 /* FIXME: if it is a zero-address, we should bail out. Now, instead,
587 we randomize an address */
588 if (is_zero_ether_addr(wl->mac_addr)) {
589 static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
590 memcpy(wl->mac_addr, nokia_oui, 3);
591 get_random_bytes(wl->mac_addr + 3, 3);
Juuso Oikarinene2e77b52010-02-18 13:25:46 +0200592
593 /* update this address to the NVS */
594 nvs_ptr[11] = wl->mac_addr[0];
595 nvs_ptr[10] = wl->mac_addr[1];
596 nvs_ptr[6] = wl->mac_addr[2];
597 nvs_ptr[5] = wl->mac_addr[3];
598 nvs_ptr[4] = wl->mac_addr[4];
599 nvs_ptr[3] = wl->mac_addr[5];
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200600 }
601
602 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
603
604 return ret;
605}
606
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300607static int wl1271_fetch_nvs(struct wl1271 *wl)
608{
609 const struct firmware *fw;
610 int ret;
611
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200612 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300613
614 if (ret < 0) {
615 wl1271_error("could not get nvs file: %d", ret);
616 return ret;
617 }
618
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200619 if (fw->size != sizeof(struct wl1271_nvs_file)) {
620 wl1271_error("nvs size is not as expected: %zu != %zu",
621 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 ret = -EILSEQ;
623 goto out;
624 }
625
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200626 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627
628 if (!wl->nvs) {
629 wl1271_error("could not allocate memory for the nvs file");
630 ret = -ENOMEM;
631 goto out;
632 }
633
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200634 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300635
Juuso Oikarinen7b21b6f2010-02-18 13:25:43 +0200636 ret = wl1271_update_mac_addr(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637
638out:
639 release_firmware(fw);
640
641 return ret;
642}
643
644static void wl1271_fw_wakeup(struct wl1271 *wl)
645{
646 u32 elp_reg;
647
648 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300649 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300650}
651
652static int wl1271_setup(struct wl1271 *wl)
653{
654 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
655 if (!wl->fw_status)
656 return -ENOMEM;
657
658 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
659 if (!wl->tx_res_if) {
660 kfree(wl->fw_status);
661 return -ENOMEM;
662 }
663
664 INIT_WORK(&wl->irq_work, wl1271_irq_work);
665 INIT_WORK(&wl->tx_work, wl1271_tx_work);
666 return 0;
667}
668
669static int wl1271_chip_wakeup(struct wl1271 *wl)
670{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300671 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672 int ret = 0;
673
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200674 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675 wl1271_power_on(wl);
676 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200677 wl1271_io_reset(wl);
678 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679
680 /* We don't need a real memory partition here, because we only want
681 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300682 memset(&partition, 0, sizeof(partition));
683 partition.reg.start = REGISTERS_BASE;
684 partition.reg.size = REGISTERS_DOWN_SIZE;
685 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686
687 /* ELP module wake up */
688 wl1271_fw_wakeup(wl);
689
690 /* whal_FwCtrl_BootSm() */
691
692 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200693 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300694
695 /* 1. check if chip id is valid */
696
697 switch (wl->chip.id) {
698 case CHIP_ID_1271_PG10:
699 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
700 wl->chip.id);
701
702 ret = wl1271_setup(wl);
703 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200704 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705 break;
706 case CHIP_ID_1271_PG20:
707 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
708 wl->chip.id);
709
710 ret = wl1271_setup(wl);
711 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200712 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713 break;
714 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200715 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200717 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300718 }
719
720 if (wl->fw == NULL) {
721 ret = wl1271_fetch_firmware(wl);
722 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300724 }
725
726 /* No NVS from netlink, try to get it from the filesystem */
727 if (wl->nvs == NULL) {
728 ret = wl1271_fetch_nvs(wl);
729 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200730 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731 }
732
733out:
734 return ret;
735}
736
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737int wl1271_plt_start(struct wl1271 *wl)
738{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200739 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300740 int ret;
741
742 mutex_lock(&wl->mutex);
743
744 wl1271_notice("power up");
745
746 if (wl->state != WL1271_STATE_OFF) {
747 wl1271_error("cannot go into PLT state because not "
748 "in off state: %d", wl->state);
749 ret = -EBUSY;
750 goto out;
751 }
752
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200753 while (retries) {
754 retries--;
755 ret = wl1271_chip_wakeup(wl);
756 if (ret < 0)
757 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300758
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200759 ret = wl1271_boot(wl);
760 if (ret < 0)
761 goto power_off;
762
763 ret = wl1271_plt_init(wl);
764 if (ret < 0)
765 goto irq_disable;
766
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200767 wl->state = WL1271_STATE_PLT;
768 wl1271_notice("firmware booted in PLT mode (%s)",
769 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 goto out;
771
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200772irq_disable:
773 wl1271_disable_interrupts(wl);
774 mutex_unlock(&wl->mutex);
775 /* Unlocking the mutex in the middle of handling is
776 inherently unsafe. In this case we deem it safe to do,
777 because we need to let any possibly pending IRQ out of
778 the system (and while we are WL1271_STATE_OFF the IRQ
779 work function will not do anything.) Also, any other
780 possible concurrent operations will fail due to the
781 current state, hence the wl1271 struct should be safe. */
782 cancel_work_sync(&wl->irq_work);
783 mutex_lock(&wl->mutex);
784power_off:
785 wl1271_power_off(wl);
786 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200788 wl1271_error("firmware boot in PLT mode failed despite %d retries",
789 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790out:
791 mutex_unlock(&wl->mutex);
792
793 return ret;
794}
795
796int wl1271_plt_stop(struct wl1271 *wl)
797{
798 int ret = 0;
799
800 mutex_lock(&wl->mutex);
801
802 wl1271_notice("power down");
803
804 if (wl->state != WL1271_STATE_PLT) {
805 wl1271_error("cannot power down because not in PLT "
806 "state: %d", wl->state);
807 ret = -EBUSY;
808 goto out;
809 }
810
811 wl1271_disable_interrupts(wl);
812 wl1271_power_off(wl);
813
814 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300815 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816
817out:
818 mutex_unlock(&wl->mutex);
819
820 return ret;
821}
822
823
824static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
825{
826 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200827 struct ieee80211_conf *conf = &hw->conf;
828 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
829 struct ieee80211_sta *sta = txinfo->control.sta;
830 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200832 /* peek into the rates configured in the STA entry */
833 spin_lock_irqsave(&wl->wl_lock, flags);
834 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
835 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
836 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
837 }
838 spin_unlock_irqrestore(&wl->wl_lock, flags);
839
840 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841 skb_queue_tail(&wl->tx_queue, skb);
842
843 /*
844 * The chip specific setup must run before the first TX packet -
845 * before that, the tx_work will not be initialized!
846 */
847
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300848 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849
850 /*
851 * The workqueue is slow to process the tx_queue and we need stop
852 * the queue here, otherwise the queue will get too long.
853 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200854 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
855 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200857 spin_lock_irqsave(&wl->wl_lock, flags);
858 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200859 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200860 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861 }
862
863 return NETDEV_TX_OK;
864}
865
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300866static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
867 void *arg)
868{
869 struct net_device *dev;
870 struct wireless_dev *wdev;
871 struct wiphy *wiphy;
872 struct ieee80211_hw *hw;
873 struct wl1271 *wl;
874 struct wl1271 *wl_temp;
875 struct in_device *idev;
876 struct in_ifaddr *ifa = arg;
877 int ret = 0;
878
879 /* FIXME: this ugly function should probably be implemented in the
880 * mac80211, and here should only be a simple callback handling actual
881 * setting of the filters. Now we need to dig up references to
882 * various structures to gain access to what we need.
883 * Also, because of this, there is no "initial" setting of the filter
884 * in "op_start", because we don't want to dig up struct net_device
885 * there - the filter will be set upon first change of the interface
886 * IP address. */
887
888 dev = ifa->ifa_dev->dev;
889
890 wdev = dev->ieee80211_ptr;
891 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200892 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300893
894 wiphy = wdev->wiphy;
895 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200896 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300897
898 hw = wiphy_priv(wiphy);
899 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200900 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300901
902 /* Check that the interface is one supported by this driver. */
903 wl_temp = hw->priv;
904 list_for_each_entry(wl, &wl_list, list) {
905 if (wl == wl_temp)
906 break;
907 }
908 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200909 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300910
911 /* Get the interface IP address for the device. "ifa" will become
912 NULL if:
913 - there is no IPV4 protocol address configured
914 - there are multiple (virtual) IPV4 addresses configured
915 When "ifa" is NULL, filtering will be disabled.
916 */
917 ifa = NULL;
918 idev = dev->ip_ptr;
919 if (idev)
920 ifa = idev->ifa_list;
921
922 if (ifa && ifa->ifa_next)
923 ifa = NULL;
924
925 mutex_lock(&wl->mutex);
926
927 if (wl->state == WL1271_STATE_OFF)
928 goto out;
929
930 ret = wl1271_ps_elp_wakeup(wl, false);
931 if (ret < 0)
932 goto out;
933 if (ifa)
934 ret = wl1271_acx_arp_ip_filter(wl, true,
935 (u8 *)&ifa->ifa_address,
936 ACX_IPV4_VERSION);
937 else
938 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
939 ACX_IPV4_VERSION);
940 wl1271_ps_elp_sleep(wl);
941
942out:
943 mutex_unlock(&wl->mutex);
944
Luciano Coelho17d72652009-11-23 23:22:15 +0200945 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300946}
947
948static struct notifier_block wl1271_dev_notifier = {
949 .notifier_call = wl1271_dev_notify,
950};
951
952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953static int wl1271_op_start(struct ieee80211_hw *hw)
954{
955 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200956 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957 int ret = 0;
958
959 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
960
961 mutex_lock(&wl->mutex);
962
963 if (wl->state != WL1271_STATE_OFF) {
964 wl1271_error("cannot start because not in off state: %d",
965 wl->state);
966 ret = -EBUSY;
967 goto out;
968 }
969
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200970 while (retries) {
971 retries--;
972 ret = wl1271_chip_wakeup(wl);
973 if (ret < 0)
974 goto power_off;
975
976 ret = wl1271_boot(wl);
977 if (ret < 0)
978 goto power_off;
979
980 ret = wl1271_hw_init(wl);
981 if (ret < 0)
982 goto irq_disable;
983
984 wl->state = WL1271_STATE_ON;
985 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986 goto out;
987
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200988irq_disable:
989 wl1271_disable_interrupts(wl);
990 mutex_unlock(&wl->mutex);
991 /* Unlocking the mutex in the middle of handling is
992 inherently unsafe. In this case we deem it safe to do,
993 because we need to let any possibly pending IRQ out of
994 the system (and while we are WL1271_STATE_OFF the IRQ
995 work function will not do anything.) Also, any other
996 possible concurrent operations will fail due to the
997 current state, hence the wl1271 struct should be safe. */
998 cancel_work_sync(&wl->irq_work);
999 mutex_lock(&wl->mutex);
1000power_off:
1001 wl1271_power_off(wl);
1002 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001003
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001004 wl1271_error("firmware boot failed despite %d retries",
1005 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001006out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 mutex_unlock(&wl->mutex);
1008
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001009 if (!ret) {
1010 list_add(&wl->list, &wl_list);
1011 register_inetaddr_notifier(&wl1271_dev_notifier);
1012 }
1013
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001014 return ret;
1015}
1016
1017static void wl1271_op_stop(struct ieee80211_hw *hw)
1018{
1019 struct wl1271 *wl = hw->priv;
1020 int i;
1021
1022 wl1271_info("down");
1023
1024 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1025
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001026 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1027 list_del(&wl->list);
1028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 mutex_lock(&wl->mutex);
1030
1031 WARN_ON(wl->state != WL1271_STATE_ON);
1032
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001033 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 mutex_unlock(&wl->mutex);
1035 ieee80211_scan_completed(wl->hw, true);
1036 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 }
1038
1039 wl->state = WL1271_STATE_OFF;
1040
1041 wl1271_disable_interrupts(wl);
1042
1043 mutex_unlock(&wl->mutex);
1044
1045 cancel_work_sync(&wl->irq_work);
1046 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
1048 mutex_lock(&wl->mutex);
1049
1050 /* let's notify MAC80211 about the remaining pending TX frames */
1051 wl1271_tx_flush(wl);
1052 wl1271_power_off(wl);
1053
1054 memset(wl->bssid, 0, ETH_ALEN);
1055 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1056 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001058 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001059
1060 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001061 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1063 wl->tx_blocks_available = 0;
1064 wl->tx_results_count = 0;
1065 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001066 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001067 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068 wl->time_offset = 0;
1069 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001070 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1071 wl->sta_rate_set = 0;
1072 wl->flags = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001073
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074 for (i = 0; i < NUM_TX_QUEUES; i++)
1075 wl->tx_blocks_freed[i] = 0;
1076
1077 wl1271_debugfs_reset(wl);
1078 mutex_unlock(&wl->mutex);
1079}
1080
1081static int wl1271_op_add_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001082 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083{
1084 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085 int ret = 0;
1086
John W. Linvillee5539bc2009-08-18 10:50:34 -04001087 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Johannes Berg1ed32e42009-12-23 13:15:45 +01001088 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089
1090 mutex_lock(&wl->mutex);
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001091 if (wl->vif) {
1092 ret = -EBUSY;
1093 goto out;
1094 }
1095
Johannes Berg1ed32e42009-12-23 13:15:45 +01001096 wl->vif = vif;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097
Johannes Berg1ed32e42009-12-23 13:15:45 +01001098 switch (vif->type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 case NL80211_IFTYPE_STATION:
1100 wl->bss_type = BSS_TYPE_STA_BSS;
1101 break;
1102 case NL80211_IFTYPE_ADHOC:
1103 wl->bss_type = BSS_TYPE_IBSS;
1104 break;
1105 default:
1106 ret = -EOPNOTSUPP;
1107 goto out;
1108 }
1109
1110 /* FIXME: what if conf->mac_addr changes? */
1111
1112out:
1113 mutex_unlock(&wl->mutex);
1114 return ret;
1115}
1116
1117static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
Johannes Berg1ed32e42009-12-23 13:15:45 +01001118 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119{
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001120 struct wl1271 *wl = hw->priv;
1121
1122 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03001124 wl->vif = NULL;
1125 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126}
1127
1128#if 0
1129static int wl1271_op_config_interface(struct ieee80211_hw *hw,
1130 struct ieee80211_vif *vif,
1131 struct ieee80211_if_conf *conf)
1132{
1133 struct wl1271 *wl = hw->priv;
1134 struct sk_buff *beacon;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135 int ret;
1136
David S. Miller32646902009-09-17 10:18:30 -07001137 wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
1138 conf->bssid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001139 wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
1140 conf->ssid_len);
1141
1142 mutex_lock(&wl->mutex);
1143
1144 ret = wl1271_ps_elp_wakeup(wl, false);
1145 if (ret < 0)
1146 goto out;
1147
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001148 if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
1149 wl1271_debug(DEBUG_MAC80211, "bssid changed");
1150
1151 memcpy(wl->bssid, conf->bssid, ETH_ALEN);
1152
Juuso Oikarinen15305492010-02-22 08:38:32 +02001153 ret = wl1271_cmd_join(wl, wl->bss_type);
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001154 if (ret < 0)
1155 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001156
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001157 ret = wl1271_cmd_build_null_data(wl);
1158 if (ret < 0)
1159 goto out_sleep;
1160 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161
1162 wl->ssid_len = conf->ssid_len;
1163 if (wl->ssid_len)
1164 memcpy(wl->ssid, conf->ssid, wl->ssid_len);
1165
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166 if (conf->changed & IEEE80211_IFCC_BEACON) {
1167 beacon = ieee80211_beacon_get(hw, vif);
1168 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1169 beacon->data, beacon->len);
1170
1171 if (ret < 0) {
1172 dev_kfree_skb(beacon);
1173 goto out_sleep;
1174 }
1175
1176 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
1177 beacon->data, beacon->len);
1178
1179 dev_kfree_skb(beacon);
1180
1181 if (ret < 0)
1182 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001183 }
1184
1185out_sleep:
1186 wl1271_ps_elp_sleep(wl);
1187
1188out:
1189 mutex_unlock(&wl->mutex);
1190
1191 return ret;
1192}
1193#endif
1194
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001195static int wl1271_join_channel(struct wl1271 *wl, int channel)
1196{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001197 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001198 /* we need to use a dummy BSSID for now */
1199 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1200 0xad, 0xbe, 0xef };
1201
1202 /* disable mac filter, so we hear everything */
1203 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1204
1205 wl->channel = channel;
1206 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1207
Juuso Oikarinen15305492010-02-22 08:38:32 +02001208 /* the dummy join is performed always with STATION BSS type to allow
1209 also ad-hoc mode to listen to the surroundings without sending any
1210 beacons yet. */
1211 ret = wl1271_cmd_join(wl, BSS_TYPE_STA_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001212 if (ret < 0)
1213 goto out;
1214
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001215 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001216
1217out:
1218 return ret;
1219}
1220
1221static int wl1271_unjoin_channel(struct wl1271 *wl)
1222{
1223 int ret;
1224
1225 /* to stop listening to a channel, we disconnect */
1226 ret = wl1271_cmd_disconnect(wl);
1227 if (ret < 0)
1228 goto out;
1229
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001230 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001231 wl->channel = 0;
1232 memset(wl->bssid, 0, ETH_ALEN);
1233 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1234
1235out:
1236 return ret;
1237}
1238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1240{
1241 struct wl1271 *wl = hw->priv;
1242 struct ieee80211_conf *conf = &hw->conf;
1243 int channel, ret = 0;
1244
1245 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1246
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001247 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248 channel,
1249 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001250 conf->power_level,
1251 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252
1253 mutex_lock(&wl->mutex);
1254
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001255 wl->band = conf->channel->band;
1256
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001257 ret = wl1271_ps_elp_wakeup(wl, false);
1258 if (ret < 0)
1259 goto out;
1260
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001261 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001262 if (conf->flags & IEEE80211_CONF_IDLE &&
1263 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001264 wl1271_unjoin_channel(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001265 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001266 wl1271_join_channel(wl, channel);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001267
1268 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001269 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1270 wl->sta_rate_set = 0;
1271 wl1271_acx_rate_policies(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001272 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273 }
1274
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001275 /* if the channel changes while joined, join again */
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001276 if (channel != wl->channel &&
1277 test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1278 wl->channel = channel;
1279 /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
Juuso Oikarinen15305492010-02-22 08:38:32 +02001280 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinenddb01a52010-02-18 13:25:37 +02001281 if (ret < 0)
1282 wl1271_warning("cmd join to update channel failed %d",
1283 ret);
1284 } else
1285 wl->channel = channel;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001286
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001287 if (conf->flags & IEEE80211_CONF_PS &&
1288 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1289 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290
1291 /*
1292 * We enter PSM only if we're already associated.
1293 * If we're not, we'll enter it when joining an SSID,
1294 * through the bss_info_changed() hook.
1295 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001296 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001297 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001298 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1299 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001300 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001302 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001303 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001305 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001307 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001308 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1309 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 }
1311
1312 if (conf->power_level != wl->power_level) {
1313 ret = wl1271_acx_tx_power(wl, conf->power_level);
1314 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001315 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
1317 wl->power_level = conf->power_level;
1318 }
1319
1320out_sleep:
1321 wl1271_ps_elp_sleep(wl);
1322
1323out:
1324 mutex_unlock(&wl->mutex);
1325
1326 return ret;
1327}
1328
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001329struct wl1271_filter_params {
1330 bool enabled;
1331 int mc_list_length;
1332 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1333};
1334
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001335static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1336 struct dev_addr_list *mc_list)
1337{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001338 struct wl1271_filter_params *fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001339 int i;
1340
Juuso Oikarinen74441132009-10-13 12:47:53 +03001341 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001342 if (!fp) {
1343 wl1271_error("Out of memory setting filters.");
1344 return 0;
1345 }
1346
1347 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001348 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001349 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1350 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001351 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001352 }
1353
1354 fp->mc_list_length = 0;
1355 for (i = 0; i < mc_count; i++) {
1356 if (mc_list->da_addrlen == ETH_ALEN) {
1357 memcpy(fp->mc_list[fp->mc_list_length],
1358 mc_list->da_addr, ETH_ALEN);
1359 fp->mc_list_length++;
1360 } else
1361 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001362 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001363 }
1364
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001365 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001366}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001368#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1369 FIF_ALLMULTI | \
1370 FIF_FCSFAIL | \
1371 FIF_BCN_PRBRESP_PROMISC | \
1372 FIF_CONTROL | \
1373 FIF_OTHER_BSS)
1374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1376 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001377 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001379 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001381 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
1383 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1384
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001385 mutex_lock(&wl->mutex);
1386
1387 if (wl->state == WL1271_STATE_OFF)
1388 goto out;
1389
1390 ret = wl1271_ps_elp_wakeup(wl, false);
1391 if (ret < 0)
1392 goto out;
1393
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394 *total &= WL1271_SUPPORTED_FILTERS;
1395 changed &= WL1271_SUPPORTED_FILTERS;
1396
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001397 if (*total & FIF_ALLMULTI)
1398 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1399 else if (fp)
1400 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1401 fp->mc_list,
1402 fp->mc_list_length);
1403 if (ret < 0)
1404 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001406 kfree(fp);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001407
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001408 /* FIXME: We still need to set our filters properly */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001409
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001410 /* determine, whether supported filter values have changed */
1411 if (changed == 0)
1412 goto out_sleep;
1413
1414 /* apply configured filters */
1415 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1416 if (ret < 0)
1417 goto out_sleep;
1418
1419out_sleep:
1420 wl1271_ps_elp_sleep(wl);
1421
1422out:
1423 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424}
1425
1426static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1427 struct ieee80211_vif *vif,
1428 struct ieee80211_sta *sta,
1429 struct ieee80211_key_conf *key_conf)
1430{
1431 struct wl1271 *wl = hw->priv;
1432 const u8 *addr;
1433 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001434 u32 tx_seq_32 = 0;
1435 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436 u8 key_type;
1437
1438 static const u8 bcast_addr[ETH_ALEN] =
1439 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1440
1441 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1442
1443 addr = sta ? sta->addr : bcast_addr;
1444
1445 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1446 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1447 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1448 key_conf->alg, key_conf->keyidx,
1449 key_conf->keylen, key_conf->flags);
1450 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1451
1452 if (is_zero_ether_addr(addr)) {
1453 /* We dont support TX only encryption */
1454 ret = -EOPNOTSUPP;
1455 goto out;
1456 }
1457
1458 mutex_lock(&wl->mutex);
1459
1460 ret = wl1271_ps_elp_wakeup(wl, false);
1461 if (ret < 0)
1462 goto out_unlock;
1463
1464 switch (key_conf->alg) {
1465 case ALG_WEP:
1466 key_type = KEY_WEP;
1467
1468 key_conf->hw_key_idx = key_conf->keyidx;
1469 break;
1470 case ALG_TKIP:
1471 key_type = KEY_TKIP;
1472
1473 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001474 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1475 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476 break;
1477 case ALG_CCMP:
1478 key_type = KEY_AES;
1479
1480 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001481 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1482 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001483 break;
1484 default:
1485 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1486
1487 ret = -EOPNOTSUPP;
1488 goto out_sleep;
1489 }
1490
1491 switch (cmd) {
1492 case SET_KEY:
1493 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1494 key_conf->keyidx, key_type,
1495 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001496 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497 if (ret < 0) {
1498 wl1271_error("Could not add or replace key");
1499 goto out_sleep;
1500 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001501
1502 /* the default WEP key needs to be configured at least once */
1503 if (key_type == KEY_WEP) {
1504 ret = wl1271_cmd_set_default_wep_key(wl,
1505 wl->default_key);
1506 if (ret < 0)
1507 goto out_sleep;
1508 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 break;
1510
1511 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001512 /* The wl1271 does not allow to remove unicast keys - they
1513 will be cleared automatically on next CMD_JOIN. Ignore the
1514 request silently, as we dont want the mac80211 to emit
1515 an error message. */
1516 if (!is_broadcast_ether_addr(addr))
1517 break;
1518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1520 key_conf->keyidx, key_type,
1521 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001522 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 if (ret < 0) {
1524 wl1271_error("Could not remove key");
1525 goto out_sleep;
1526 }
1527 break;
1528
1529 default:
1530 wl1271_error("Unsupported key cmd 0x%x", cmd);
1531 ret = -EOPNOTSUPP;
1532 goto out_sleep;
1533
1534 break;
1535 }
1536
1537out_sleep:
1538 wl1271_ps_elp_sleep(wl);
1539
1540out_unlock:
1541 mutex_unlock(&wl->mutex);
1542
1543out:
1544 return ret;
1545}
1546
1547static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
1548 struct cfg80211_scan_request *req)
1549{
1550 struct wl1271 *wl = hw->priv;
1551 int ret;
1552 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001553 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554
1555 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1556
1557 if (req->n_ssids) {
1558 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001559 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560 }
1561
1562 mutex_lock(&wl->mutex);
1563
1564 ret = wl1271_ps_elp_wakeup(wl, false);
1565 if (ret < 0)
1566 goto out;
1567
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001568 if (wl1271_11a_enabled())
1569 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1570 WL1271_SCAN_BAND_DUAL, 3);
1571 else
1572 ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
1573 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
1575 wl1271_ps_elp_sleep(wl);
1576
1577out:
1578 mutex_unlock(&wl->mutex);
1579
1580 return ret;
1581}
1582
1583static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1584{
1585 struct wl1271 *wl = hw->priv;
1586 int ret;
1587
1588 mutex_lock(&wl->mutex);
1589
1590 ret = wl1271_ps_elp_wakeup(wl, false);
1591 if (ret < 0)
1592 goto out;
1593
1594 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1595 if (ret < 0)
1596 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1597
1598 wl1271_ps_elp_sleep(wl);
1599
1600out:
1601 mutex_unlock(&wl->mutex);
1602
1603 return ret;
1604}
1605
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001606static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1607{
1608 u8 *ptr = beacon->data +
1609 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1610
1611 /* find the location of the ssid in the beacon */
1612 while (ptr < beacon->data + beacon->len) {
1613 if (ptr[0] == WLAN_EID_SSID) {
1614 wl->ssid_len = ptr[1];
1615 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1616 return;
1617 }
1618 ptr += ptr[1];
1619 }
1620 wl1271_error("ad-hoc beacon template has no SSID!\n");
1621}
1622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001623static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1624 struct ieee80211_vif *vif,
1625 struct ieee80211_bss_conf *bss_conf,
1626 u32 changed)
1627{
1628 enum wl1271_cmd_ps_mode mode;
1629 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001630 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631 int ret;
1632
1633 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1634
1635 mutex_lock(&wl->mutex);
1636
1637 ret = wl1271_ps_elp_wakeup(wl, false);
1638 if (ret < 0)
1639 goto out;
1640
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001641 if (wl->bss_type == BSS_TYPE_IBSS) {
1642 /* FIXME: This implements rudimentary ad-hoc support -
1643 proper templates are on the wish list and notification
1644 on when they change. This patch will update the templates
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001645 on every call to this function. */
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001646 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1647
1648 if (beacon) {
1649 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001650
1651 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001652 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1653 beacon->data,
1654 beacon->len);
1655
1656 if (ret < 0) {
1657 dev_kfree_skb(beacon);
1658 goto out_sleep;
1659 }
1660
1661 hdr = (struct ieee80211_hdr *) beacon->data;
1662 hdr->frame_control = cpu_to_le16(
1663 IEEE80211_FTYPE_MGMT |
1664 IEEE80211_STYPE_PROBE_RESP);
1665
1666 ret = wl1271_cmd_template_set(wl,
1667 CMD_TEMPL_PROBE_RESPONSE,
1668 beacon->data,
1669 beacon->len);
1670 dev_kfree_skb(beacon);
1671 if (ret < 0)
1672 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001673
1674 /* Need to update the SSID (for filtering etc) */
1675 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001676 }
1677 }
1678
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001679 if ((changed & BSS_CHANGED_BSSID) &&
1680 /*
1681 * Now we know the correct bssid, so we send a new join command
1682 * and enable the BSSID filter
1683 */
1684 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
1685 wl->rx_config |= CFG_BSSID_FILTER_EN;
1686 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
1687 ret = wl1271_cmd_build_null_data(wl);
1688 if (ret < 0) {
1689 wl1271_warning("cmd buld null data failed %d",
1690 ret);
1691 goto out_sleep;
1692 }
1693
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001694 /* Need to update the BSSID (for filtering etc) */
1695 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001696 }
1697
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698 if (changed & BSS_CHANGED_ASSOC) {
1699 if (bss_conf->assoc) {
1700 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001701 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001703 /*
1704 * with wl1271, we don't need to update the
1705 * beacon_int and dtim_period, because the firmware
1706 * updates it by itself when the first beacon is
1707 * received after a join.
1708 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1710 if (ret < 0)
1711 goto out_sleep;
1712
1713 ret = wl1271_acx_aid(wl, wl->aid);
1714 if (ret < 0)
1715 goto out_sleep;
1716
1717 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001718 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1719 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001721 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722 if (ret < 0)
1723 goto out_sleep;
1724 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001725 } else {
1726 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001727 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001728 wl->aid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001730
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001732
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001733 if (changed & BSS_CHANGED_ERP_SLOT) {
1734 if (bss_conf->use_short_slot)
1735 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1736 else
1737 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1738 if (ret < 0) {
1739 wl1271_warning("Set slot time failed %d", ret);
1740 goto out_sleep;
1741 }
1742 }
1743
1744 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1745 if (bss_conf->use_short_preamble)
1746 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1747 else
1748 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1749 }
1750
1751 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1752 if (bss_conf->use_cts_prot)
1753 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1754 else
1755 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1756 if (ret < 0) {
1757 wl1271_warning("Set ctsprotect failed %d", ret);
1758 goto out_sleep;
1759 }
1760 }
1761
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001762 if (do_join) {
Juuso Oikarinen15305492010-02-22 08:38:32 +02001763 ret = wl1271_cmd_join(wl, wl->bss_type);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001764 if (ret < 0) {
1765 wl1271_warning("cmd join failed %d", ret);
1766 goto out_sleep;
1767 }
1768 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1769 }
1770
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001771out_sleep:
1772 wl1271_ps_elp_sleep(wl);
1773
1774out:
1775 mutex_unlock(&wl->mutex);
1776}
1777
Kalle Valoc6999d82010-02-18 13:25:41 +02001778static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1779 const struct ieee80211_tx_queue_params *params)
1780{
1781 struct wl1271 *wl = hw->priv;
1782 int ret;
1783
1784 mutex_lock(&wl->mutex);
1785
1786 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1787
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001788 ret = wl1271_ps_elp_wakeup(wl, false);
1789 if (ret < 0)
1790 goto out;
1791
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001792 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001793 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1794 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001795 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001796 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001797 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001798
1799 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1800 CONF_CHANNEL_TYPE_EDCF,
1801 wl1271_tx_get_queue(queue),
1802 CONF_PS_SCHEME_LEGACY_PSPOLL,
1803 CONF_ACK_POLICY_LEGACY, 0, 0);
1804 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001805 goto out_sleep;
1806
1807out_sleep:
1808 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001809
1810out:
1811 mutex_unlock(&wl->mutex);
1812
1813 return ret;
1814}
1815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816
1817/* can't be const, mac80211 writes to this */
1818static struct ieee80211_rate wl1271_rates[] = {
1819 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001820 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1821 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001823 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1824 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001825 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1826 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001827 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1828 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1830 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001831 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1832 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1834 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001835 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1836 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001838 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1839 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001841 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1842 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001844 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1845 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001847 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1848 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001850 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1851 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001852 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001853 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1854 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001856 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1857 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001858};
1859
1860/* can't be const, mac80211 writes to this */
1861static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001862 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1863 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1864 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1865 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1866 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1867 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1868 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1869 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1870 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1871 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1872 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1873 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1874 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875};
1876
1877/* can't be const, mac80211 writes to this */
1878static struct ieee80211_supported_band wl1271_band_2ghz = {
1879 .channels = wl1271_channels,
1880 .n_channels = ARRAY_SIZE(wl1271_channels),
1881 .bitrates = wl1271_rates,
1882 .n_bitrates = ARRAY_SIZE(wl1271_rates),
1883};
1884
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03001885/* 5 GHz data rates for WL1273 */
1886static struct ieee80211_rate wl1271_rates_5ghz[] = {
1887 { .bitrate = 60,
1888 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1889 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
1890 { .bitrate = 90,
1891 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1892 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
1893 { .bitrate = 120,
1894 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1895 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
1896 { .bitrate = 180,
1897 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1898 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
1899 { .bitrate = 240,
1900 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1901 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
1902 { .bitrate = 360,
1903 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1904 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
1905 { .bitrate = 480,
1906 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1907 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
1908 { .bitrate = 540,
1909 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1910 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
1911};
1912
1913/* 5 GHz band channels for WL1273 */
1914static struct ieee80211_channel wl1271_channels_5ghz[] = {
1915 { .hw_value = 183, .center_freq = 4915},
1916 { .hw_value = 184, .center_freq = 4920},
1917 { .hw_value = 185, .center_freq = 4925},
1918 { .hw_value = 187, .center_freq = 4935},
1919 { .hw_value = 188, .center_freq = 4940},
1920 { .hw_value = 189, .center_freq = 4945},
1921 { .hw_value = 192, .center_freq = 4960},
1922 { .hw_value = 196, .center_freq = 4980},
1923 { .hw_value = 7, .center_freq = 5035},
1924 { .hw_value = 8, .center_freq = 5040},
1925 { .hw_value = 9, .center_freq = 5045},
1926 { .hw_value = 11, .center_freq = 5055},
1927 { .hw_value = 12, .center_freq = 5060},
1928 { .hw_value = 16, .center_freq = 5080},
1929 { .hw_value = 34, .center_freq = 5170},
1930 { .hw_value = 36, .center_freq = 5180},
1931 { .hw_value = 38, .center_freq = 5190},
1932 { .hw_value = 40, .center_freq = 5200},
1933 { .hw_value = 42, .center_freq = 5210},
1934 { .hw_value = 44, .center_freq = 5220},
1935 { .hw_value = 46, .center_freq = 5230},
1936 { .hw_value = 48, .center_freq = 5240},
1937 { .hw_value = 52, .center_freq = 5260},
1938 { .hw_value = 56, .center_freq = 5280},
1939 { .hw_value = 60, .center_freq = 5300},
1940 { .hw_value = 64, .center_freq = 5320},
1941 { .hw_value = 100, .center_freq = 5500},
1942 { .hw_value = 104, .center_freq = 5520},
1943 { .hw_value = 108, .center_freq = 5540},
1944 { .hw_value = 112, .center_freq = 5560},
1945 { .hw_value = 116, .center_freq = 5580},
1946 { .hw_value = 120, .center_freq = 5600},
1947 { .hw_value = 124, .center_freq = 5620},
1948 { .hw_value = 128, .center_freq = 5640},
1949 { .hw_value = 132, .center_freq = 5660},
1950 { .hw_value = 136, .center_freq = 5680},
1951 { .hw_value = 140, .center_freq = 5700},
1952 { .hw_value = 149, .center_freq = 5745},
1953 { .hw_value = 153, .center_freq = 5765},
1954 { .hw_value = 157, .center_freq = 5785},
1955 { .hw_value = 161, .center_freq = 5805},
1956 { .hw_value = 165, .center_freq = 5825},
1957};
1958
1959
1960static struct ieee80211_supported_band wl1271_band_5ghz = {
1961 .channels = wl1271_channels_5ghz,
1962 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
1963 .bitrates = wl1271_rates_5ghz,
1964 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
1965};
1966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967static const struct ieee80211_ops wl1271_ops = {
1968 .start = wl1271_op_start,
1969 .stop = wl1271_op_stop,
1970 .add_interface = wl1271_op_add_interface,
1971 .remove_interface = wl1271_op_remove_interface,
1972 .config = wl1271_op_config,
1973/* .config_interface = wl1271_op_config_interface, */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001974 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975 .configure_filter = wl1271_op_configure_filter,
1976 .tx = wl1271_op_tx,
1977 .set_key = wl1271_op_set_key,
1978 .hw_scan = wl1271_op_hw_scan,
1979 .bss_info_changed = wl1271_op_bss_info_changed,
1980 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02001981 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02001982 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983};
1984
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02001985static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
1986 struct device_attribute *attr,
1987 char *buf)
1988{
1989 struct wl1271 *wl = dev_get_drvdata(dev);
1990 ssize_t len;
1991
1992 /* FIXME: what's the maximum length of buf? page size?*/
1993 len = 500;
1994
1995 mutex_lock(&wl->mutex);
1996 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
1997 wl->sg_enabled);
1998 mutex_unlock(&wl->mutex);
1999
2000 return len;
2001
2002}
2003
2004static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2005 struct device_attribute *attr,
2006 const char *buf, size_t count)
2007{
2008 struct wl1271 *wl = dev_get_drvdata(dev);
2009 unsigned long res;
2010 int ret;
2011
2012 ret = strict_strtoul(buf, 10, &res);
2013
2014 if (ret < 0) {
2015 wl1271_warning("incorrect value written to bt_coex_mode");
2016 return count;
2017 }
2018
2019 mutex_lock(&wl->mutex);
2020
2021 res = !!res;
2022
2023 if (res == wl->sg_enabled)
2024 goto out;
2025
2026 wl->sg_enabled = res;
2027
2028 if (wl->state == WL1271_STATE_OFF)
2029 goto out;
2030
2031 ret = wl1271_ps_elp_wakeup(wl, false);
2032 if (ret < 0)
2033 goto out;
2034
2035 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2036 wl1271_ps_elp_sleep(wl);
2037
2038 out:
2039 mutex_unlock(&wl->mutex);
2040 return count;
2041}
2042
2043static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2044 wl1271_sysfs_show_bt_coex_state,
2045 wl1271_sysfs_store_bt_coex_state);
2046
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002047int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048{
2049 int ret;
2050
2051 if (wl->mac80211_registered)
2052 return 0;
2053
2054 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2055
2056 ret = ieee80211_register_hw(wl->hw);
2057 if (ret < 0) {
2058 wl1271_error("unable to register mac80211 hw: %d", ret);
2059 return ret;
2060 }
2061
2062 wl->mac80211_registered = true;
2063
2064 wl1271_notice("loaded");
2065
2066 return 0;
2067}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002068EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002070int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002072 /* The tx descriptor buffer and the TKIP space. */
2073 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2074 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075
2076 /* unit us */
2077 /* FIXME: find a proper value */
2078 wl->hw->channel_change_time = 10000;
2079
2080 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen19221672009-10-08 21:56:35 +03002081 IEEE80211_HW_NOISE_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002082 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002083 IEEE80211_HW_SUPPORTS_PS |
2084 IEEE80211_HW_HAS_RATE_CONTROL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002085
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002086 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2087 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002088 wl->hw->wiphy->max_scan_ssids = 1;
2089 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2090
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002091 if (wl1271_11a_enabled())
2092 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2093
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002094 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002095
2096 return 0;
2097}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002098EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002099
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002100#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002101
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002102struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002103{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002104 struct ieee80211_hw *hw;
2105 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002106 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107
2108 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2109 if (!hw) {
2110 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002111 ret = -ENOMEM;
2112 goto err;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113 }
2114
2115 wl = hw->priv;
2116 memset(wl, 0, sizeof(*wl));
2117
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002118 INIT_LIST_HEAD(&wl->list);
2119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002120 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121
2122 skb_queue_head_init(&wl->tx_queue);
2123
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002124 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002126 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127 wl->rx_counter = 0;
2128 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2129 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002130 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002132 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002133 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2134 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002135 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002136 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002137 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002138 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002139
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002140 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002141 wl->tx_frames[i] = NULL;
2142
2143 spin_lock_init(&wl->wl_lock);
2144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 wl->state = WL1271_STATE_OFF;
2146 mutex_init(&wl->mutex);
2147
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002148 /* Apply default driver configuration. */
2149 wl1271_conf_init(wl);
2150
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002151 wl1271_debugfs_init(wl);
2152
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002153 /* Register platform device */
2154 ret = platform_device_register(&wl1271_device);
2155 if (ret) {
2156 wl1271_error("couldn't register platform device");
2157 goto err_hw;
2158 }
2159 dev_set_drvdata(&wl1271_device.dev, wl);
2160
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002161 /* Create sysfs file to control bt coex state */
2162 ret = device_create_file(&wl1271_device.dev, &dev_attr_bt_coex_state);
2163 if (ret < 0) {
2164 wl1271_error("failed to create sysfs file bt_coex_state");
2165 goto err_platform;
2166 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002167
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002168 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002169
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002170err_platform:
2171 platform_device_unregister(&wl1271_device);
2172
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002173err_hw:
2174 ieee80211_unregister_hw(wl->hw);
2175
2176err:
2177 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002178}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002179EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002180
2181int wl1271_free_hw(struct wl1271 *wl)
2182{
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002183 platform_device_unregister(&wl1271_device);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002184 ieee80211_unregister_hw(wl->hw);
2185
2186 wl1271_debugfs_exit(wl);
2187
2188 kfree(wl->target_mem_map);
2189 vfree(wl->fw);
2190 wl->fw = NULL;
2191 kfree(wl->nvs);
2192 wl->nvs = NULL;
2193
2194 kfree(wl->fw_status);
2195 kfree(wl->tx_res_if);
2196
2197 ieee80211_free_hw(wl->hw);
2198
2199 return 0;
2200}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002201EXPORT_SYMBOL_GPL(wl1271_free_hw);
2202
2203MODULE_LICENSE("GPL");
2204MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2205MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");