blob: b0837255de6fe7a57b257714545acb80aef0fe8f [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinen01c09162009-10-13 12:47:55 +030031#include <linux/inetdevice.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030047
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020048#define WL1271_BOOT_RETRIES 3
49
Juuso Oikarinen8a080482009-10-13 12:47:44 +030050static struct conf_drv_settings default_conf = {
51 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020052 .params = {
53 [CONF_SG_BT_PER_THRESHOLD] = 7500,
54 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
55 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
56 [CONF_SG_BT_LOAD_RATIO] = 50,
57 [CONF_SG_AUTO_PS_MODE] = 0,
58 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
59 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
60 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
61 [CONF_SG_BEACON_MISS_PERCENT] = 60,
62 [CONF_SG_RATE_ADAPT_THRESH] = 12,
63 [CONF_SG_RATE_ADAPT_SNR] = 0,
64 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
66 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
67 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
69 /* Note: with UPSD, this should be 4 */
70 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
71 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
74 /* Note: with UPDS, this should be 15 */
75 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
76 /* Note: with UPDS, this should be 50 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
78 /* Note: with UPDS, this should be 10 */
79 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
80 [CONF_SG_RXT] = 1200,
81 [CONF_SG_TXT] = 1000,
82 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
83 [CONF_SG_PS_POLL_TIMEOUT] = 10,
84 [CONF_SG_UPSD_TIMEOUT] = 10,
85 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
87 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
94 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
96 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
97 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
98 [CONF_SG_HV3_MAX_SERVED] = 6,
99 [CONF_SG_DHCP_TIME] = 5000,
100 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
101 },
102 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300103 },
104 .rx = {
105 .rx_msdu_life_time = 512000,
106 .packet_detection_threshold = 0,
107 .ps_poll_timeout = 15,
108 .upsd_timeout = 15,
109 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200110 .rx_cca_threshold = 0,
111 .irq_blk_threshold = 0xFFFF,
112 .irq_pkt_threshold = 0,
113 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300114 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
115 },
116 .tx = {
117 .tx_energy_detection = 0,
118 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300119 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 .short_retry_limit = 10,
121 .long_retry_limit = 10,
122 .aflags = 0
123 },
124 .ac_conf_count = 4,
125 .ac_conf = {
126 [0] = {
127 .ac = CONF_TX_AC_BE,
128 .cw_min = 15,
129 .cw_max = 63,
130 .aifsn = 3,
131 .tx_op_limit = 0,
132 },
133 [1] = {
134 .ac = CONF_TX_AC_BK,
135 .cw_min = 15,
136 .cw_max = 63,
137 .aifsn = 7,
138 .tx_op_limit = 0,
139 },
140 [2] = {
141 .ac = CONF_TX_AC_VI,
142 .cw_min = 15,
143 .cw_max = 63,
144 .aifsn = CONF_TX_AIFS_PIFS,
145 .tx_op_limit = 3008,
146 },
147 [3] = {
148 .ac = CONF_TX_AC_VO,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = CONF_TX_AIFS_PIFS,
152 .tx_op_limit = 1504,
153 },
154 },
155 .tid_conf_count = 7,
156 .tid_conf = {
157 [0] = {
158 .queue_id = 0,
159 .channel_type = CONF_CHANNEL_TYPE_DCF,
160 .tsid = CONF_TX_AC_BE,
161 .ps_scheme = CONF_PS_SCHEME_LEGACY,
162 .ack_policy = CONF_ACK_POLICY_LEGACY,
163 .apsd_conf = {0, 0},
164 },
165 [1] = {
166 .queue_id = 1,
167 .channel_type = CONF_CHANNEL_TYPE_DCF,
168 .tsid = CONF_TX_AC_BE,
169 .ps_scheme = CONF_PS_SCHEME_LEGACY,
170 .ack_policy = CONF_ACK_POLICY_LEGACY,
171 .apsd_conf = {0, 0},
172 },
173 [2] = {
174 .queue_id = 2,
175 .channel_type = CONF_CHANNEL_TYPE_DCF,
176 .tsid = CONF_TX_AC_BE,
177 .ps_scheme = CONF_PS_SCHEME_LEGACY,
178 .ack_policy = CONF_ACK_POLICY_LEGACY,
179 .apsd_conf = {0, 0},
180 },
181 [3] = {
182 .queue_id = 3,
183 .channel_type = CONF_CHANNEL_TYPE_DCF,
184 .tsid = CONF_TX_AC_BE,
185 .ps_scheme = CONF_PS_SCHEME_LEGACY,
186 .ack_policy = CONF_ACK_POLICY_LEGACY,
187 .apsd_conf = {0, 0},
188 },
189 [4] = {
190 .queue_id = 4,
191 .channel_type = CONF_CHANNEL_TYPE_DCF,
192 .tsid = CONF_TX_AC_BE,
193 .ps_scheme = CONF_PS_SCHEME_LEGACY,
194 .ack_policy = CONF_ACK_POLICY_LEGACY,
195 .apsd_conf = {0, 0},
196 },
197 [5] = {
198 .queue_id = 5,
199 .channel_type = CONF_CHANNEL_TYPE_DCF,
200 .tsid = CONF_TX_AC_BE,
201 .ps_scheme = CONF_PS_SCHEME_LEGACY,
202 .ack_policy = CONF_ACK_POLICY_LEGACY,
203 .apsd_conf = {0, 0},
204 },
205 [6] = {
206 .queue_id = 6,
207 .channel_type = CONF_CHANNEL_TYPE_DCF,
208 .tsid = CONF_TX_AC_BE,
209 .ps_scheme = CONF_PS_SCHEME_LEGACY,
210 .ack_policy = CONF_ACK_POLICY_LEGACY,
211 .apsd_conf = {0, 0},
212 }
213 },
214 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200215 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300216 .tx_compl_threshold = 4,
217 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
218 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 },
220 .conn = {
221 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300222 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300223 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
224 .bcn_filt_ie_count = 1,
225 .bcn_filt_ie = {
226 [0] = {
227 .ie = WLAN_EID_CHANNEL_SWITCH,
228 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
229 }
230 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200231 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300232 .bss_lose_timeout = 100,
233 .beacon_rx_timeout = 10000,
234 .broadcast_timeout = 20000,
235 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200236 .ps_poll_threshold = 20,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300237 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200238 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200239 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300240 .keep_alive_interval = 55000,
241 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300242 },
243 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200245 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 },
248 .itrim = {
249 .enable = false,
250 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200251 },
252 .pm_config = {
253 .host_clk_settling_time = 5000,
254 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300255 },
256 .roam_trigger = {
257 /* FIXME: due to firmware bug, must use value 1 for now */
258 .trigger_pacing = 1,
259 .avg_weight_rssi_beacon = 20,
260 .avg_weight_rssi_data = 10,
261 .avg_weight_snr_beacon = 20,
262 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 }
264};
265
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200266static void wl1271_device_release(struct device *dev)
267{
268
269}
270
271static struct platform_device wl1271_device = {
272 .name = "wl1271",
273 .id = -1,
274
275 /* device model insists to have a release function */
276 .dev = {
277 .release = wl1271_device_release,
278 },
279};
280
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300281static LIST_HEAD(wl_list);
282
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300283static void wl1271_conf_init(struct wl1271 *wl)
284{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300285
286 /*
287 * This function applies the default configuration to the driver. This
288 * function is invoked upon driver load (spi probe.)
289 *
290 * The configuration is stored in a run-time structure in order to
291 * facilitate for run-time adjustment of any of the parameters. Making
292 * changes to the configuration structure will apply the new values on
293 * the next interface up (wl1271_op_start.)
294 */
295
296 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300297 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300298}
299
300
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300301static int wl1271_plt_init(struct wl1271 *wl)
302{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200303 struct conf_tx_ac_category *conf_ac;
304 struct conf_tx_tid *conf_tid;
305 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300306
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200307 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200308 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200309 return ret;
310
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200311 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200312 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200313 return ret;
314
Luciano Coelho12419cc2010-02-18 13:25:44 +0200315 ret = wl1271_init_templates_config(wl);
316 if (ret < 0)
317 return ret;
318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300319 ret = wl1271_acx_init_mem_config(wl);
320 if (ret < 0)
321 return ret;
322
Luciano Coelho12419cc2010-02-18 13:25:44 +0200323 /* PHY layer config */
324 ret = wl1271_init_phy_config(wl);
325 if (ret < 0)
326 goto out_free_memmap;
327
328 ret = wl1271_acx_dco_itrim_params(wl);
329 if (ret < 0)
330 goto out_free_memmap;
331
332 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200333 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200334 if (ret < 0)
335 goto out_free_memmap;
336
337 /* Bluetooth WLAN coexistence */
338 ret = wl1271_init_pta(wl);
339 if (ret < 0)
340 goto out_free_memmap;
341
342 /* Energy detection */
343 ret = wl1271_init_energy_detection(wl);
344 if (ret < 0)
345 goto out_free_memmap;
346
347 /* Default fragmentation threshold */
348 ret = wl1271_acx_frag_threshold(wl);
349 if (ret < 0)
350 goto out_free_memmap;
351
352 /* Default TID configuration */
353 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
354 conf_tid = &wl->conf.tx.tid_conf[i];
355 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
356 conf_tid->channel_type,
357 conf_tid->tsid,
358 conf_tid->ps_scheme,
359 conf_tid->ack_policy,
360 conf_tid->apsd_conf[0],
361 conf_tid->apsd_conf[1]);
362 if (ret < 0)
363 goto out_free_memmap;
364 }
365
366 /* Default AC configuration */
367 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
368 conf_ac = &wl->conf.tx.ac_conf[i];
369 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
370 conf_ac->cw_max, conf_ac->aifsn,
371 conf_ac->tx_op_limit);
372 if (ret < 0)
373 goto out_free_memmap;
374 }
375
376 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200377 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300378 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200379 goto out_free_memmap;
380
381 /* Configure for CAM power saving (ie. always active) */
382 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
383 if (ret < 0)
384 goto out_free_memmap;
385
386 /* configure PM */
387 ret = wl1271_acx_pm_config(wl);
388 if (ret < 0)
389 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300390
391 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200392
393 out_free_memmap:
394 kfree(wl->target_mem_map);
395 wl->target_mem_map = NULL;
396
397 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300398}
399
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300400static void wl1271_fw_status(struct wl1271 *wl,
401 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300402{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200403 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300404 u32 total = 0;
405 int i;
406
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200407 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300408
409 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
410 "drv_rx_counter = %d, tx_results_counter = %d)",
411 status->intr,
412 status->fw_rx_counter,
413 status->drv_rx_counter,
414 status->tx_results_counter);
415
416 /* update number of available TX blocks */
417 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300418 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
419 wl->tx_blocks_freed[i];
420
421 wl->tx_blocks_freed[i] =
422 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300423 wl->tx_blocks_available += cnt;
424 total += cnt;
425 }
426
427 /* if more blocks are available now, schedule some tx work */
428 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300429 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300430
431 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200432 getnstimeofday(&ts);
433 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
434 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300435}
436
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200437#define WL1271_IRQ_MAX_LOOPS 10
438
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300439static void wl1271_irq_work(struct work_struct *work)
440{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300441 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300442 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200443 int loopcount = WL1271_IRQ_MAX_LOOPS;
444 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300445 struct wl1271 *wl =
446 container_of(work, struct wl1271, irq_work);
447
448 mutex_lock(&wl->mutex);
449
450 wl1271_debug(DEBUG_IRQ, "IRQ work");
451
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200452 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300453 goto out;
454
455 ret = wl1271_ps_elp_wakeup(wl, true);
456 if (ret < 0)
457 goto out;
458
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200459 spin_lock_irqsave(&wl->wl_lock, flags);
460 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
461 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
462 spin_unlock_irqrestore(&wl->wl_lock, flags);
463 loopcount--;
464
465 wl1271_fw_status(wl, wl->fw_status);
466 intr = le32_to_cpu(wl->fw_status->intr);
467 if (!intr) {
468 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
469 continue;
470 }
471
472 intr &= WL1271_INTR_MASK;
473
474 if (intr & WL1271_ACX_INTR_DATA) {
475 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
476
477 /* check for tx results */
478 if (wl->fw_status->tx_results_counter !=
479 (wl->tx_results_count & 0xff))
480 wl1271_tx_complete(wl);
481
482 wl1271_rx(wl, wl->fw_status);
483 }
484
485 if (intr & WL1271_ACX_INTR_EVENT_A) {
486 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
487 wl1271_event_handle(wl, 0);
488 }
489
490 if (intr & WL1271_ACX_INTR_EVENT_B) {
491 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
492 wl1271_event_handle(wl, 1);
493 }
494
495 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
496 wl1271_debug(DEBUG_IRQ,
497 "WL1271_ACX_INTR_INIT_COMPLETE");
498
499 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
500 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
501
502 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300503 }
504
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200505 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
506 ieee80211_queue_work(wl->hw, &wl->irq_work);
507 else
508 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
509 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300510
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511 wl1271_ps_elp_sleep(wl);
512
513out:
514 mutex_unlock(&wl->mutex);
515}
516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300517static int wl1271_fetch_firmware(struct wl1271 *wl)
518{
519 const struct firmware *fw;
520 int ret;
521
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200522 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523
524 if (ret < 0) {
525 wl1271_error("could not get firmware: %d", ret);
526 return ret;
527 }
528
529 if (fw->size % 4) {
530 wl1271_error("firmware size is not multiple of 32 bits: %zu",
531 fw->size);
532 ret = -EILSEQ;
533 goto out;
534 }
535
536 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300537 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300538
539 if (!wl->fw) {
540 wl1271_error("could not allocate memory for the firmware");
541 ret = -ENOMEM;
542 goto out;
543 }
544
545 memcpy(wl->fw, fw->data, wl->fw_len);
546
547 ret = 0;
548
549out:
550 release_firmware(fw);
551
552 return ret;
553}
554
555static int wl1271_fetch_nvs(struct wl1271 *wl)
556{
557 const struct firmware *fw;
558 int ret;
559
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200560 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300561
562 if (ret < 0) {
563 wl1271_error("could not get nvs file: %d", ret);
564 return ret;
565 }
566
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200567 if (fw->size != sizeof(struct wl1271_nvs_file)) {
568 wl1271_error("nvs size is not as expected: %zu != %zu",
569 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300570 ret = -EILSEQ;
571 goto out;
572 }
573
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200574 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575
576 if (!wl->nvs) {
577 wl1271_error("could not allocate memory for the nvs file");
578 ret = -ENOMEM;
579 goto out;
580 }
581
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200582 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300583
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584out:
585 release_firmware(fw);
586
587 return ret;
588}
589
590static void wl1271_fw_wakeup(struct wl1271 *wl)
591{
592 u32 elp_reg;
593
594 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300595 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596}
597
598static int wl1271_setup(struct wl1271 *wl)
599{
600 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
601 if (!wl->fw_status)
602 return -ENOMEM;
603
604 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
605 if (!wl->tx_res_if) {
606 kfree(wl->fw_status);
607 return -ENOMEM;
608 }
609
610 INIT_WORK(&wl->irq_work, wl1271_irq_work);
611 INIT_WORK(&wl->tx_work, wl1271_tx_work);
612 return 0;
613}
614
615static int wl1271_chip_wakeup(struct wl1271 *wl)
616{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300617 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300618 int ret = 0;
619
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200620 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621 wl1271_power_on(wl);
622 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200623 wl1271_io_reset(wl);
624 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300625
626 /* We don't need a real memory partition here, because we only want
627 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300628 memset(&partition, 0, sizeof(partition));
629 partition.reg.start = REGISTERS_BASE;
630 partition.reg.size = REGISTERS_DOWN_SIZE;
631 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300632
633 /* ELP module wake up */
634 wl1271_fw_wakeup(wl);
635
636 /* whal_FwCtrl_BootSm() */
637
638 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200639 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300640
641 /* 1. check if chip id is valid */
642
643 switch (wl->chip.id) {
644 case CHIP_ID_1271_PG10:
645 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
646 wl->chip.id);
647
648 ret = wl1271_setup(wl);
649 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200650 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651 break;
652 case CHIP_ID_1271_PG20:
653 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
654 wl->chip.id);
655
656 ret = wl1271_setup(wl);
657 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200658 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659 break;
660 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200661 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 }
665
666 if (wl->fw == NULL) {
667 ret = wl1271_fetch_firmware(wl);
668 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200669 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300670 }
671
672 /* No NVS from netlink, try to get it from the filesystem */
673 if (wl->nvs == NULL) {
674 ret = wl1271_fetch_nvs(wl);
675 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200676 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 }
678
679out:
680 return ret;
681}
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683int wl1271_plt_start(struct wl1271 *wl)
684{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 int ret;
687
688 mutex_lock(&wl->mutex);
689
690 wl1271_notice("power up");
691
692 if (wl->state != WL1271_STATE_OFF) {
693 wl1271_error("cannot go into PLT state because not "
694 "in off state: %d", wl->state);
695 ret = -EBUSY;
696 goto out;
697 }
698
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200699 while (retries) {
700 retries--;
701 ret = wl1271_chip_wakeup(wl);
702 if (ret < 0)
703 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300704
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200705 ret = wl1271_boot(wl);
706 if (ret < 0)
707 goto power_off;
708
709 ret = wl1271_plt_init(wl);
710 if (ret < 0)
711 goto irq_disable;
712
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200713 wl->state = WL1271_STATE_PLT;
714 wl1271_notice("firmware booted in PLT mode (%s)",
715 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300716 goto out;
717
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718irq_disable:
719 wl1271_disable_interrupts(wl);
720 mutex_unlock(&wl->mutex);
721 /* Unlocking the mutex in the middle of handling is
722 inherently unsafe. In this case we deem it safe to do,
723 because we need to let any possibly pending IRQ out of
724 the system (and while we are WL1271_STATE_OFF the IRQ
725 work function will not do anything.) Also, any other
726 possible concurrent operations will fail due to the
727 current state, hence the wl1271 struct should be safe. */
728 cancel_work_sync(&wl->irq_work);
729 mutex_lock(&wl->mutex);
730power_off:
731 wl1271_power_off(wl);
732 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300733
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200734 wl1271_error("firmware boot in PLT mode failed despite %d retries",
735 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300736out:
737 mutex_unlock(&wl->mutex);
738
739 return ret;
740}
741
742int wl1271_plt_stop(struct wl1271 *wl)
743{
744 int ret = 0;
745
746 mutex_lock(&wl->mutex);
747
748 wl1271_notice("power down");
749
750 if (wl->state != WL1271_STATE_PLT) {
751 wl1271_error("cannot power down because not in PLT "
752 "state: %d", wl->state);
753 ret = -EBUSY;
754 goto out;
755 }
756
757 wl1271_disable_interrupts(wl);
758 wl1271_power_off(wl);
759
760 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300761 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
763out:
764 mutex_unlock(&wl->mutex);
765
766 return ret;
767}
768
769
770static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
771{
772 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200773 struct ieee80211_conf *conf = &hw->conf;
774 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
775 struct ieee80211_sta *sta = txinfo->control.sta;
776 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200778 /* peek into the rates configured in the STA entry */
779 spin_lock_irqsave(&wl->wl_lock, flags);
780 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
781 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
782 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
783 }
784 spin_unlock_irqrestore(&wl->wl_lock, flags);
785
786 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787 skb_queue_tail(&wl->tx_queue, skb);
788
789 /*
790 * The chip specific setup must run before the first TX packet -
791 * before that, the tx_work will not be initialized!
792 */
793
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300794 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795
796 /*
797 * The workqueue is slow to process the tx_queue and we need stop
798 * the queue here, otherwise the queue will get too long.
799 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200800 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
801 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300802
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200803 spin_lock_irqsave(&wl->wl_lock, flags);
804 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200805 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200806 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807 }
808
809 return NETDEV_TX_OK;
810}
811
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300812static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
813 void *arg)
814{
815 struct net_device *dev;
816 struct wireless_dev *wdev;
817 struct wiphy *wiphy;
818 struct ieee80211_hw *hw;
819 struct wl1271 *wl;
820 struct wl1271 *wl_temp;
821 struct in_device *idev;
822 struct in_ifaddr *ifa = arg;
823 int ret = 0;
824
825 /* FIXME: this ugly function should probably be implemented in the
826 * mac80211, and here should only be a simple callback handling actual
827 * setting of the filters. Now we need to dig up references to
828 * various structures to gain access to what we need.
829 * Also, because of this, there is no "initial" setting of the filter
830 * in "op_start", because we don't want to dig up struct net_device
831 * there - the filter will be set upon first change of the interface
832 * IP address. */
833
834 dev = ifa->ifa_dev->dev;
835
836 wdev = dev->ieee80211_ptr;
837 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200838 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300839
840 wiphy = wdev->wiphy;
841 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200842 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300843
844 hw = wiphy_priv(wiphy);
845 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200846 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300847
848 /* Check that the interface is one supported by this driver. */
849 wl_temp = hw->priv;
850 list_for_each_entry(wl, &wl_list, list) {
851 if (wl == wl_temp)
852 break;
853 }
854 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200855 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300856
857 /* Get the interface IP address for the device. "ifa" will become
858 NULL if:
859 - there is no IPV4 protocol address configured
860 - there are multiple (virtual) IPV4 addresses configured
861 When "ifa" is NULL, filtering will be disabled.
862 */
863 ifa = NULL;
864 idev = dev->ip_ptr;
865 if (idev)
866 ifa = idev->ifa_list;
867
868 if (ifa && ifa->ifa_next)
869 ifa = NULL;
870
871 mutex_lock(&wl->mutex);
872
873 if (wl->state == WL1271_STATE_OFF)
874 goto out;
875
876 ret = wl1271_ps_elp_wakeup(wl, false);
877 if (ret < 0)
878 goto out;
879 if (ifa)
880 ret = wl1271_acx_arp_ip_filter(wl, true,
881 (u8 *)&ifa->ifa_address,
882 ACX_IPV4_VERSION);
883 else
884 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
885 ACX_IPV4_VERSION);
886 wl1271_ps_elp_sleep(wl);
887
888out:
889 mutex_unlock(&wl->mutex);
890
Luciano Coelho17d72652009-11-23 23:22:15 +0200891 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300892}
893
894static struct notifier_block wl1271_dev_notifier = {
895 .notifier_call = wl1271_dev_notify,
896};
897
898
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899static int wl1271_op_start(struct ieee80211_hw *hw)
900{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200901 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
902
903 /*
904 * We have to delay the booting of the hardware because
905 * we need to know the local MAC address before downloading and
906 * initializing the firmware. The MAC address cannot be changed
907 * after boot, and without the proper MAC address, the firmware
908 * will not function properly.
909 *
910 * The MAC address is first known when the corresponding interface
911 * is added. That is where we will initialize the hardware.
912 */
913
914 return 0;
915}
916
917static void wl1271_op_stop(struct ieee80211_hw *hw)
918{
919 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
920}
921
922static int wl1271_op_add_interface(struct ieee80211_hw *hw,
923 struct ieee80211_vif *vif)
924{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200926 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 int ret = 0;
928
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200929 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
930 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931
932 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200933 if (wl->vif) {
934 ret = -EBUSY;
935 goto out;
936 }
937
938 wl->vif = vif;
939
940 switch (vif->type) {
941 case NL80211_IFTYPE_STATION:
942 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200943 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200944 break;
945 case NL80211_IFTYPE_ADHOC:
946 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200947 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200948 break;
949 default:
950 ret = -EOPNOTSUPP;
951 goto out;
952 }
953
954 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955
956 if (wl->state != WL1271_STATE_OFF) {
957 wl1271_error("cannot start because not in off state: %d",
958 wl->state);
959 ret = -EBUSY;
960 goto out;
961 }
962
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200963 while (retries) {
964 retries--;
965 ret = wl1271_chip_wakeup(wl);
966 if (ret < 0)
967 goto power_off;
968
969 ret = wl1271_boot(wl);
970 if (ret < 0)
971 goto power_off;
972
973 ret = wl1271_hw_init(wl);
974 if (ret < 0)
975 goto irq_disable;
976
977 wl->state = WL1271_STATE_ON;
978 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 goto out;
980
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200981irq_disable:
982 wl1271_disable_interrupts(wl);
983 mutex_unlock(&wl->mutex);
984 /* Unlocking the mutex in the middle of handling is
985 inherently unsafe. In this case we deem it safe to do,
986 because we need to let any possibly pending IRQ out of
987 the system (and while we are WL1271_STATE_OFF the IRQ
988 work function will not do anything.) Also, any other
989 possible concurrent operations will fail due to the
990 current state, hence the wl1271 struct should be safe. */
991 cancel_work_sync(&wl->irq_work);
992 mutex_lock(&wl->mutex);
993power_off:
994 wl1271_power_off(wl);
995 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200997 wl1271_error("firmware boot failed despite %d retries",
998 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300999out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 mutex_unlock(&wl->mutex);
1001
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001002 if (!ret) {
1003 list_add(&wl->list, &wl_list);
1004 register_inetaddr_notifier(&wl1271_dev_notifier);
1005 }
1006
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001007 return ret;
1008}
1009
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001010static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1011 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012{
1013 struct wl1271 *wl = hw->priv;
1014 int i;
1015
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001016 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1017
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001018 mutex_lock(&wl->mutex);
1019 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001021 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001023 list_del(&wl->list);
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 WARN_ON(wl->state != WL1271_STATE_ON);
1026
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001027 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 mutex_unlock(&wl->mutex);
1029 ieee80211_scan_completed(wl->hw, true);
1030 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 }
1032
1033 wl->state = WL1271_STATE_OFF;
1034
1035 wl1271_disable_interrupts(wl);
1036
1037 mutex_unlock(&wl->mutex);
1038
1039 cancel_work_sync(&wl->irq_work);
1040 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
1042 mutex_lock(&wl->mutex);
1043
1044 /* let's notify MAC80211 about the remaining pending TX frames */
1045 wl1271_tx_flush(wl);
1046 wl1271_power_off(wl);
1047
1048 memset(wl->bssid, 0, ETH_ALEN);
1049 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1050 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001052 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001053 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
1055 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001056 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1058 wl->tx_blocks_available = 0;
1059 wl->tx_results_count = 0;
1060 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001061 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001062 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 wl->time_offset = 0;
1064 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001065 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1066 wl->sta_rate_set = 0;
1067 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001068 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001069 wl->filters = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 for (i = 0; i < NUM_TX_QUEUES; i++)
1072 wl->tx_blocks_freed[i] = 0;
1073
1074 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001075
1076 kfree(wl->fw_status);
1077 wl->fw_status = NULL;
1078 kfree(wl->tx_res_if);
1079 wl->tx_res_if = NULL;
1080 kfree(wl->target_mem_map);
1081 wl->target_mem_map = NULL;
1082
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 mutex_unlock(&wl->mutex);
1084}
1085
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001086static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1087{
1088 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1089 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1090
1091 /* combine requested filters with current filter config */
1092 filters = wl->filters | filters;
1093
1094 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1095
1096 if (filters & FIF_PROMISC_IN_BSS) {
1097 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1098 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1099 wl->rx_config |= CFG_BSSID_FILTER_EN;
1100 }
1101 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1102 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1103 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1104 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1105 }
1106 if (filters & FIF_OTHER_BSS) {
1107 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1108 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1109 }
1110 if (filters & FIF_CONTROL) {
1111 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1112 wl->rx_filter |= CFG_RX_CTL_EN;
1113 }
1114 if (filters & FIF_FCSFAIL) {
1115 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1116 wl->rx_filter |= CFG_RX_FCS_ERROR;
1117 }
1118}
1119
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001120static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001121{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001122 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001123 /* we need to use a dummy BSSID for now */
1124 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1125 0xad, 0xbe, 0xef };
1126
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001127 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1128
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001129 /* pass through frames from all BSS */
1130 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1131
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001132 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133 if (ret < 0)
1134 goto out;
1135
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001136 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001137
1138out:
1139 return ret;
1140}
1141
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001142static int wl1271_join(struct wl1271 *wl)
1143{
1144 int ret;
1145
1146 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1147 if (ret < 0)
1148 goto out;
1149
1150 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1151
1152 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1153 goto out;
1154
1155 /*
1156 * The join command disable the keep-alive mode, shut down its process,
1157 * and also clear the template config, so we need to reset it all after
1158 * the join. The acx_aid starts the keep-alive process, and the order
1159 * of the commands below is relevant.
1160 */
1161 ret = wl1271_acx_keep_alive_mode(wl, true);
1162 if (ret < 0)
1163 goto out;
1164
1165 ret = wl1271_acx_aid(wl, wl->aid);
1166 if (ret < 0)
1167 goto out;
1168
1169 ret = wl1271_cmd_build_klv_null_data(wl);
1170 if (ret < 0)
1171 goto out;
1172
1173 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1174 ACX_KEEP_ALIVE_TPL_VALID);
1175 if (ret < 0)
1176 goto out;
1177
1178out:
1179 return ret;
1180}
1181
1182static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001183{
1184 int ret;
1185
1186 /* to stop listening to a channel, we disconnect */
1187 ret = wl1271_cmd_disconnect(wl);
1188 if (ret < 0)
1189 goto out;
1190
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001191 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001192 wl->channel = 0;
1193 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001194
1195 /* stop filterting packets based on bssid */
1196 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001197
1198out:
1199 return ret;
1200}
1201
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001202static void wl1271_set_band_rate(struct wl1271 *wl)
1203{
1204 if (wl->band == IEEE80211_BAND_2GHZ)
1205 wl->basic_rate_set = wl->conf.tx.basic_rate;
1206 else
1207 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1208}
1209
1210static u32 wl1271_min_rate_get(struct wl1271 *wl)
1211{
1212 int i;
1213 u32 rate = 0;
1214
1215 if (!wl->basic_rate_set) {
1216 WARN_ON(1);
1217 wl->basic_rate_set = wl->conf.tx.basic_rate;
1218 }
1219
1220 for (i = 0; !rate; i++) {
1221 if ((wl->basic_rate_set >> i) & 0x1)
1222 rate = 1 << i;
1223 }
1224
1225 return rate;
1226}
1227
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1229{
1230 struct wl1271 *wl = hw->priv;
1231 struct ieee80211_conf *conf = &hw->conf;
1232 int channel, ret = 0;
1233
1234 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1235
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001236 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237 channel,
1238 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001239 conf->power_level,
1240 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241
1242 mutex_lock(&wl->mutex);
1243
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001244 if (unlikely(wl->state == WL1271_STATE_OFF))
1245 goto out;
1246
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 ret = wl1271_ps_elp_wakeup(wl, false);
1248 if (ret < 0)
1249 goto out;
1250
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001251 /* if the channel changes while joined, join again */
1252 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
1253 wl->band = conf->channel->band;
1254 wl->channel = channel;
1255
1256 /*
1257 * FIXME: the mac80211 should really provide a fixed rate
1258 * to use here. for now, just use the smallest possible rate
1259 * for the band as a fixed rate for association frames and
1260 * other control messages.
1261 */
1262 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1263 wl1271_set_band_rate(wl);
1264
1265 wl->basic_rate = wl1271_min_rate_get(wl);
1266 ret = wl1271_acx_rate_policies(wl);
1267 if (ret < 0)
1268 wl1271_warning("rate policy for update channel "
1269 "failed %d", ret);
1270
1271 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001272 ret = wl1271_join(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001273 if (ret < 0)
1274 wl1271_warning("cmd join to update channel "
1275 "failed %d", ret);
1276 }
1277 }
1278
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001279 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001280 if (conf->flags & IEEE80211_CONF_IDLE &&
1281 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001282 wl1271_unjoin(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001283 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001284 wl1271_dummy_join(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001285
1286 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001287 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001288 wl->sta_rate_set = 0;
1289 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001290 wl1271_acx_keep_alive_config(
1291 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1292 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinene1972812010-04-09 11:07:29 +03001293 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1294 } else
1295 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 }
1297
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001298 if (conf->flags & IEEE80211_CONF_PS &&
1299 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1300 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
1302 /*
1303 * We enter PSM only if we're already associated.
1304 * If we're not, we'll enter it when joining an SSID,
1305 * through the bss_info_changed() hook.
1306 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001307 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001308 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001309 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1310 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001311 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001313 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001314 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001316 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001318 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001319 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1320 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323 if (conf->power_level != wl->power_level) {
1324 ret = wl1271_acx_tx_power(wl, conf->power_level);
1325 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001326 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001327
1328 wl->power_level = conf->power_level;
1329 }
1330
1331out_sleep:
1332 wl1271_ps_elp_sleep(wl);
1333
1334out:
1335 mutex_unlock(&wl->mutex);
1336
1337 return ret;
1338}
1339
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001340struct wl1271_filter_params {
1341 bool enabled;
1342 int mc_list_length;
1343 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1344};
1345
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1347 struct dev_addr_list *mc_list)
1348{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001349 struct wl1271_filter_params *fp;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001350 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001351 int i;
1352
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001353 if (unlikely(wl->state == WL1271_STATE_OFF))
1354 return 0;
1355
Juuso Oikarinen74441132009-10-13 12:47:53 +03001356 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001357 if (!fp) {
1358 wl1271_error("Out of memory setting filters.");
1359 return 0;
1360 }
1361
1362 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001363 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1365 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001366 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001367 }
1368
1369 fp->mc_list_length = 0;
1370 for (i = 0; i < mc_count; i++) {
1371 if (mc_list->da_addrlen == ETH_ALEN) {
1372 memcpy(fp->mc_list[fp->mc_list_length],
1373 mc_list->da_addr, ETH_ALEN);
1374 fp->mc_list_length++;
1375 } else
1376 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001377 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001378 }
1379
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001380 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001381}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1384 FIF_ALLMULTI | \
1385 FIF_FCSFAIL | \
1386 FIF_BCN_PRBRESP_PROMISC | \
1387 FIF_CONTROL | \
1388 FIF_OTHER_BSS)
1389
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001390static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1391 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001392 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001396 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397
1398 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1399
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001400 mutex_lock(&wl->mutex);
1401
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001402 *total &= WL1271_SUPPORTED_FILTERS;
1403 changed &= WL1271_SUPPORTED_FILTERS;
1404
1405 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001406 goto out;
1407
1408 ret = wl1271_ps_elp_wakeup(wl, false);
1409 if (ret < 0)
1410 goto out;
1411
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001413 if (*total & FIF_ALLMULTI)
1414 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1415 else if (fp)
1416 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1417 fp->mc_list,
1418 fp->mc_list_length);
1419 if (ret < 0)
1420 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001421
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001422 /* determine, whether supported filter values have changed */
1423 if (changed == 0)
1424 goto out_sleep;
1425
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001426 /* configure filters */
1427 wl->filters = *total;
1428 wl1271_configure_filters(wl, 0);
1429
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001430 /* apply configured filters */
1431 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1432 if (ret < 0)
1433 goto out_sleep;
1434
1435out_sleep:
1436 wl1271_ps_elp_sleep(wl);
1437
1438out:
1439 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001440 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441}
1442
1443static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1444 struct ieee80211_vif *vif,
1445 struct ieee80211_sta *sta,
1446 struct ieee80211_key_conf *key_conf)
1447{
1448 struct wl1271 *wl = hw->priv;
1449 const u8 *addr;
1450 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001451 u32 tx_seq_32 = 0;
1452 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001453 u8 key_type;
1454
1455 static const u8 bcast_addr[ETH_ALEN] =
1456 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1457
1458 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1459
1460 addr = sta ? sta->addr : bcast_addr;
1461
1462 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1463 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1464 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1465 key_conf->alg, key_conf->keyidx,
1466 key_conf->keylen, key_conf->flags);
1467 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1468
1469 if (is_zero_ether_addr(addr)) {
1470 /* We dont support TX only encryption */
1471 ret = -EOPNOTSUPP;
1472 goto out;
1473 }
1474
1475 mutex_lock(&wl->mutex);
1476
1477 ret = wl1271_ps_elp_wakeup(wl, false);
1478 if (ret < 0)
1479 goto out_unlock;
1480
1481 switch (key_conf->alg) {
1482 case ALG_WEP:
1483 key_type = KEY_WEP;
1484
1485 key_conf->hw_key_idx = key_conf->keyidx;
1486 break;
1487 case ALG_TKIP:
1488 key_type = KEY_TKIP;
1489
1490 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001491 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1492 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 break;
1494 case ALG_CCMP:
1495 key_type = KEY_AES;
1496
1497 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001498 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1499 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500 break;
1501 default:
1502 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1503
1504 ret = -EOPNOTSUPP;
1505 goto out_sleep;
1506 }
1507
1508 switch (cmd) {
1509 case SET_KEY:
1510 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1511 key_conf->keyidx, key_type,
1512 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001513 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514 if (ret < 0) {
1515 wl1271_error("Could not add or replace key");
1516 goto out_sleep;
1517 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001518
1519 /* the default WEP key needs to be configured at least once */
1520 if (key_type == KEY_WEP) {
1521 ret = wl1271_cmd_set_default_wep_key(wl,
1522 wl->default_key);
1523 if (ret < 0)
1524 goto out_sleep;
1525 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 break;
1527
1528 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001529 /* The wl1271 does not allow to remove unicast keys - they
1530 will be cleared automatically on next CMD_JOIN. Ignore the
1531 request silently, as we dont want the mac80211 to emit
1532 an error message. */
1533 if (!is_broadcast_ether_addr(addr))
1534 break;
1535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1537 key_conf->keyidx, key_type,
1538 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001539 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540 if (ret < 0) {
1541 wl1271_error("Could not remove key");
1542 goto out_sleep;
1543 }
1544 break;
1545
1546 default:
1547 wl1271_error("Unsupported key cmd 0x%x", cmd);
1548 ret = -EOPNOTSUPP;
1549 goto out_sleep;
1550
1551 break;
1552 }
1553
1554out_sleep:
1555 wl1271_ps_elp_sleep(wl);
1556
1557out_unlock:
1558 mutex_unlock(&wl->mutex);
1559
1560out:
1561 return ret;
1562}
1563
1564static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001565 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 struct cfg80211_scan_request *req)
1567{
1568 struct wl1271 *wl = hw->priv;
1569 int ret;
1570 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001571 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001572
1573 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1574
1575 if (req->n_ssids) {
1576 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001577 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 }
1579
1580 mutex_lock(&wl->mutex);
1581
1582 ret = wl1271_ps_elp_wakeup(wl, false);
1583 if (ret < 0)
1584 goto out;
1585
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001586 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001587 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1588 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001589 WL1271_SCAN_BAND_DUAL, 3);
1590 else
Kalle Valo818e3062010-03-18 12:26:35 +02001591 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1592 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001593 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001594
1595 wl1271_ps_elp_sleep(wl);
1596
1597out:
1598 mutex_unlock(&wl->mutex);
1599
1600 return ret;
1601}
1602
1603static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1604{
1605 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001606 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001607
1608 mutex_lock(&wl->mutex);
1609
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001610 if (unlikely(wl->state == WL1271_STATE_OFF))
1611 goto out;
1612
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001613 ret = wl1271_ps_elp_wakeup(wl, false);
1614 if (ret < 0)
1615 goto out;
1616
1617 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1618 if (ret < 0)
1619 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1620
1621 wl1271_ps_elp_sleep(wl);
1622
1623out:
1624 mutex_unlock(&wl->mutex);
1625
1626 return ret;
1627}
1628
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001629static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1630{
1631 u8 *ptr = beacon->data +
1632 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1633
1634 /* find the location of the ssid in the beacon */
1635 while (ptr < beacon->data + beacon->len) {
1636 if (ptr[0] == WLAN_EID_SSID) {
1637 wl->ssid_len = ptr[1];
1638 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1639 return;
1640 }
1641 ptr += ptr[1];
1642 }
1643 wl1271_error("ad-hoc beacon template has no SSID!\n");
1644}
1645
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001646static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1647 struct ieee80211_vif *vif,
1648 struct ieee80211_bss_conf *bss_conf,
1649 u32 changed)
1650{
1651 enum wl1271_cmd_ps_mode mode;
1652 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001653 bool do_join = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 int ret;
1655
1656 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1657
1658 mutex_lock(&wl->mutex);
1659
1660 ret = wl1271_ps_elp_wakeup(wl, false);
1661 if (ret < 0)
1662 goto out;
1663
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001664 if ((changed && BSS_CHANGED_BEACON_INT) &&
1665 (wl->bss_type == BSS_TYPE_IBSS)) {
1666 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1667 bss_conf->beacon_int);
1668
1669 wl->beacon_int = bss_conf->beacon_int;
1670 do_join = true;
1671 }
1672
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001673 if ((changed && BSS_CHANGED_BEACON) &&
1674 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001675 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1676
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001677 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1678
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001679 if (beacon) {
1680 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001681
1682 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001683 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1684 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001685 beacon->len, 0,
1686 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001687
1688 if (ret < 0) {
1689 dev_kfree_skb(beacon);
1690 goto out_sleep;
1691 }
1692
1693 hdr = (struct ieee80211_hdr *) beacon->data;
1694 hdr->frame_control = cpu_to_le16(
1695 IEEE80211_FTYPE_MGMT |
1696 IEEE80211_STYPE_PROBE_RESP);
1697
1698 ret = wl1271_cmd_template_set(wl,
1699 CMD_TEMPL_PROBE_RESPONSE,
1700 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001701 beacon->len, 0,
1702 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001703 dev_kfree_skb(beacon);
1704 if (ret < 0)
1705 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001706
1707 /* Need to update the SSID (for filtering etc) */
1708 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001709 }
1710 }
1711
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001712 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1713 (wl->bss_type == BSS_TYPE_IBSS)) {
1714 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1715 bss_conf->enable_beacon ? "enabled" : "disabled");
1716
1717 if (bss_conf->enable_beacon)
1718 wl->set_bss_type = BSS_TYPE_IBSS;
1719 else
1720 wl->set_bss_type = BSS_TYPE_STA_BSS;
1721 do_join = true;
1722 }
1723
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001724 if (changed & BSS_CHANGED_CQM) {
1725 bool enable = false;
1726 if (bss_conf->cqm_rssi_thold)
1727 enable = true;
1728 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1729 bss_conf->cqm_rssi_thold,
1730 bss_conf->cqm_rssi_hyst);
1731 if (ret < 0)
1732 goto out;
1733 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1734 }
1735
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001736 if ((changed & BSS_CHANGED_BSSID) &&
1737 /*
1738 * Now we know the correct bssid, so we send a new join command
1739 * and enable the BSSID filter
1740 */
1741 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001742 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001743
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001744 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001745 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001746 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001747
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001748 ret = wl1271_build_qos_null_data(wl);
1749 if (ret < 0)
1750 goto out_sleep;
1751
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001752 /* filter out all packets not from this BSSID */
1753 wl1271_configure_filters(wl, 0);
1754
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001755 /* Need to update the BSSID (for filtering etc) */
1756 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001757 }
1758
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001759 if (changed & BSS_CHANGED_ASSOC) {
1760 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001761 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001762 wl->aid = bss_conf->aid;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001763 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001764
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001765 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001766 * use basic rates from AP, and determine lowest rate
1767 * to use with control frames.
1768 */
1769 rates = bss_conf->basic_rates;
1770 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1771 rates);
1772 wl->basic_rate = wl1271_min_rate_get(wl);
1773 ret = wl1271_acx_rate_policies(wl);
1774 if (ret < 0)
1775 goto out_sleep;
1776
1777 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001778 * with wl1271, we don't need to update the
1779 * beacon_int and dtim_period, because the firmware
1780 * updates it by itself when the first beacon is
1781 * received after a join.
1782 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001783 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1784 if (ret < 0)
1785 goto out_sleep;
1786
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001787 /*
1788 * The SSID is intentionally set to NULL here - the
1789 * firmware will set the probe request with a
1790 * broadcast SSID regardless of what we set in the
1791 * template.
1792 */
1793 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1794 NULL, 0, wl->band);
1795
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001796 /* enable the connection monitoring feature */
1797 ret = wl1271_acx_conn_monit_params(wl, true);
1798 if (ret < 0)
1799 goto out_sleep;
1800
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001802 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1803 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001805 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 if (ret < 0)
1807 goto out_sleep;
1808 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001809 } else {
1810 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001811 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001812 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001813
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001814 /* revert back to minimum rates for the current band */
1815 wl1271_set_band_rate(wl);
1816 wl->basic_rate = wl1271_min_rate_get(wl);
1817 ret = wl1271_acx_rate_policies(wl);
1818 if (ret < 0)
1819 goto out_sleep;
1820
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001821 /* disable connection monitor features */
1822 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001823
1824 /* Disable the keep-alive feature */
1825 ret = wl1271_acx_keep_alive_mode(wl, false);
1826
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001827 if (ret < 0)
1828 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001830
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001832
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833 if (changed & BSS_CHANGED_ERP_SLOT) {
1834 if (bss_conf->use_short_slot)
1835 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1836 else
1837 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1838 if (ret < 0) {
1839 wl1271_warning("Set slot time failed %d", ret);
1840 goto out_sleep;
1841 }
1842 }
1843
1844 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1845 if (bss_conf->use_short_preamble)
1846 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1847 else
1848 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1849 }
1850
1851 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1852 if (bss_conf->use_cts_prot)
1853 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1854 else
1855 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1856 if (ret < 0) {
1857 wl1271_warning("Set ctsprotect failed %d", ret);
1858 goto out_sleep;
1859 }
1860 }
1861
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001862 if (do_join) {
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001863 ret = wl1271_join(wl);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001864 if (ret < 0) {
1865 wl1271_warning("cmd join failed %d", ret);
1866 goto out_sleep;
1867 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001868 }
1869
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001870out_sleep:
1871 wl1271_ps_elp_sleep(wl);
1872
1873out:
1874 mutex_unlock(&wl->mutex);
1875}
1876
Kalle Valoc6999d82010-02-18 13:25:41 +02001877static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1878 const struct ieee80211_tx_queue_params *params)
1879{
1880 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001881 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001882 int ret;
1883
1884 mutex_lock(&wl->mutex);
1885
1886 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1887
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001888 ret = wl1271_ps_elp_wakeup(wl, false);
1889 if (ret < 0)
1890 goto out;
1891
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001892 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001893 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1894 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001895 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001896 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001897 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001898
Kalle Valo4695dc92010-03-18 12:26:38 +02001899 if (params->uapsd)
1900 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1901 else
1902 ps_scheme = CONF_PS_SCHEME_LEGACY;
1903
Kalle Valoc6999d82010-02-18 13:25:41 +02001904 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1905 CONF_CHANNEL_TYPE_EDCF,
1906 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001907 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001908 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001909 goto out_sleep;
1910
1911out_sleep:
1912 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001913
1914out:
1915 mutex_unlock(&wl->mutex);
1916
1917 return ret;
1918}
1919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920
1921/* can't be const, mac80211 writes to this */
1922static struct ieee80211_rate wl1271_rates[] = {
1923 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001924 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1925 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001927 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1928 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1930 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001931 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1932 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001933 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1934 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001935 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1936 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1938 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001939 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1940 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001941 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001945 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1946 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001948 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1949 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001951 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1952 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001953 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001954 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1955 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001957 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1958 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962};
1963
1964/* can't be const, mac80211 writes to this */
1965static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001966 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1967 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1968 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1969 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1970 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1971 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1972 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1973 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1974 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1975 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1976 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1977 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1978 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979};
1980
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001981/* mapping to indexes for wl1271_rates */
1982const static u8 wl1271_rate_to_idx_2ghz[] = {
1983 /* MCS rates are used only with 11n */
1984 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1985 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1986 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1987 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1988 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
1989 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
1990 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
1991 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
1992
1993 11, /* CONF_HW_RXTX_RATE_54 */
1994 10, /* CONF_HW_RXTX_RATE_48 */
1995 9, /* CONF_HW_RXTX_RATE_36 */
1996 8, /* CONF_HW_RXTX_RATE_24 */
1997
1998 /* TI-specific rate */
1999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2000
2001 7, /* CONF_HW_RXTX_RATE_18 */
2002 6, /* CONF_HW_RXTX_RATE_12 */
2003 3, /* CONF_HW_RXTX_RATE_11 */
2004 5, /* CONF_HW_RXTX_RATE_9 */
2005 4, /* CONF_HW_RXTX_RATE_6 */
2006 2, /* CONF_HW_RXTX_RATE_5_5 */
2007 1, /* CONF_HW_RXTX_RATE_2 */
2008 0 /* CONF_HW_RXTX_RATE_1 */
2009};
2010
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002011/* can't be const, mac80211 writes to this */
2012static struct ieee80211_supported_band wl1271_band_2ghz = {
2013 .channels = wl1271_channels,
2014 .n_channels = ARRAY_SIZE(wl1271_channels),
2015 .bitrates = wl1271_rates,
2016 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2017};
2018
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002019/* 5 GHz data rates for WL1273 */
2020static struct ieee80211_rate wl1271_rates_5ghz[] = {
2021 { .bitrate = 60,
2022 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2023 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2024 { .bitrate = 90,
2025 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2026 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2027 { .bitrate = 120,
2028 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2029 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2030 { .bitrate = 180,
2031 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2032 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2033 { .bitrate = 240,
2034 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2035 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2036 { .bitrate = 360,
2037 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2038 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2039 { .bitrate = 480,
2040 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2041 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2042 { .bitrate = 540,
2043 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2044 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2045};
2046
2047/* 5 GHz band channels for WL1273 */
2048static struct ieee80211_channel wl1271_channels_5ghz[] = {
2049 { .hw_value = 183, .center_freq = 4915},
2050 { .hw_value = 184, .center_freq = 4920},
2051 { .hw_value = 185, .center_freq = 4925},
2052 { .hw_value = 187, .center_freq = 4935},
2053 { .hw_value = 188, .center_freq = 4940},
2054 { .hw_value = 189, .center_freq = 4945},
2055 { .hw_value = 192, .center_freq = 4960},
2056 { .hw_value = 196, .center_freq = 4980},
2057 { .hw_value = 7, .center_freq = 5035},
2058 { .hw_value = 8, .center_freq = 5040},
2059 { .hw_value = 9, .center_freq = 5045},
2060 { .hw_value = 11, .center_freq = 5055},
2061 { .hw_value = 12, .center_freq = 5060},
2062 { .hw_value = 16, .center_freq = 5080},
2063 { .hw_value = 34, .center_freq = 5170},
2064 { .hw_value = 36, .center_freq = 5180},
2065 { .hw_value = 38, .center_freq = 5190},
2066 { .hw_value = 40, .center_freq = 5200},
2067 { .hw_value = 42, .center_freq = 5210},
2068 { .hw_value = 44, .center_freq = 5220},
2069 { .hw_value = 46, .center_freq = 5230},
2070 { .hw_value = 48, .center_freq = 5240},
2071 { .hw_value = 52, .center_freq = 5260},
2072 { .hw_value = 56, .center_freq = 5280},
2073 { .hw_value = 60, .center_freq = 5300},
2074 { .hw_value = 64, .center_freq = 5320},
2075 { .hw_value = 100, .center_freq = 5500},
2076 { .hw_value = 104, .center_freq = 5520},
2077 { .hw_value = 108, .center_freq = 5540},
2078 { .hw_value = 112, .center_freq = 5560},
2079 { .hw_value = 116, .center_freq = 5580},
2080 { .hw_value = 120, .center_freq = 5600},
2081 { .hw_value = 124, .center_freq = 5620},
2082 { .hw_value = 128, .center_freq = 5640},
2083 { .hw_value = 132, .center_freq = 5660},
2084 { .hw_value = 136, .center_freq = 5680},
2085 { .hw_value = 140, .center_freq = 5700},
2086 { .hw_value = 149, .center_freq = 5745},
2087 { .hw_value = 153, .center_freq = 5765},
2088 { .hw_value = 157, .center_freq = 5785},
2089 { .hw_value = 161, .center_freq = 5805},
2090 { .hw_value = 165, .center_freq = 5825},
2091};
2092
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002093/* mapping to indexes for wl1271_rates_5ghz */
2094const static u8 wl1271_rate_to_idx_5ghz[] = {
2095 /* MCS rates are used only with 11n */
2096 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2097 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2098 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2099 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2100 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2101 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2102 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2103 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2104
2105 7, /* CONF_HW_RXTX_RATE_54 */
2106 6, /* CONF_HW_RXTX_RATE_48 */
2107 5, /* CONF_HW_RXTX_RATE_36 */
2108 4, /* CONF_HW_RXTX_RATE_24 */
2109
2110 /* TI-specific rate */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2112
2113 3, /* CONF_HW_RXTX_RATE_18 */
2114 2, /* CONF_HW_RXTX_RATE_12 */
2115 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2116 1, /* CONF_HW_RXTX_RATE_9 */
2117 0, /* CONF_HW_RXTX_RATE_6 */
2118 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2119 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2120 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2121};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002122
2123static struct ieee80211_supported_band wl1271_band_5ghz = {
2124 .channels = wl1271_channels_5ghz,
2125 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2126 .bitrates = wl1271_rates_5ghz,
2127 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2128};
2129
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002130const static u8 *wl1271_band_rate_to_idx[] = {
2131 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2132 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2133};
2134
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135static const struct ieee80211_ops wl1271_ops = {
2136 .start = wl1271_op_start,
2137 .stop = wl1271_op_stop,
2138 .add_interface = wl1271_op_add_interface,
2139 .remove_interface = wl1271_op_remove_interface,
2140 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002141 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142 .configure_filter = wl1271_op_configure_filter,
2143 .tx = wl1271_op_tx,
2144 .set_key = wl1271_op_set_key,
2145 .hw_scan = wl1271_op_hw_scan,
2146 .bss_info_changed = wl1271_op_bss_info_changed,
2147 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002148 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002149 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002150};
2151
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002152
2153u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2154{
2155 u8 idx;
2156
2157 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2158
2159 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2160 wl1271_error("Illegal RX rate from HW: %d", rate);
2161 return 0;
2162 }
2163
2164 idx = wl1271_band_rate_to_idx[wl->band][rate];
2165 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2166 wl1271_error("Unsupported RX rate from HW: %d", rate);
2167 return 0;
2168 }
2169
2170 return idx;
2171}
2172
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002173static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2174 struct device_attribute *attr,
2175 char *buf)
2176{
2177 struct wl1271 *wl = dev_get_drvdata(dev);
2178 ssize_t len;
2179
2180 /* FIXME: what's the maximum length of buf? page size?*/
2181 len = 500;
2182
2183 mutex_lock(&wl->mutex);
2184 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2185 wl->sg_enabled);
2186 mutex_unlock(&wl->mutex);
2187
2188 return len;
2189
2190}
2191
2192static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2193 struct device_attribute *attr,
2194 const char *buf, size_t count)
2195{
2196 struct wl1271 *wl = dev_get_drvdata(dev);
2197 unsigned long res;
2198 int ret;
2199
2200 ret = strict_strtoul(buf, 10, &res);
2201
2202 if (ret < 0) {
2203 wl1271_warning("incorrect value written to bt_coex_mode");
2204 return count;
2205 }
2206
2207 mutex_lock(&wl->mutex);
2208
2209 res = !!res;
2210
2211 if (res == wl->sg_enabled)
2212 goto out;
2213
2214 wl->sg_enabled = res;
2215
2216 if (wl->state == WL1271_STATE_OFF)
2217 goto out;
2218
2219 ret = wl1271_ps_elp_wakeup(wl, false);
2220 if (ret < 0)
2221 goto out;
2222
2223 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2224 wl1271_ps_elp_sleep(wl);
2225
2226 out:
2227 mutex_unlock(&wl->mutex);
2228 return count;
2229}
2230
2231static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2232 wl1271_sysfs_show_bt_coex_state,
2233 wl1271_sysfs_store_bt_coex_state);
2234
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002235int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236{
2237 int ret;
2238
2239 if (wl->mac80211_registered)
2240 return 0;
2241
2242 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2243
2244 ret = ieee80211_register_hw(wl->hw);
2245 if (ret < 0) {
2246 wl1271_error("unable to register mac80211 hw: %d", ret);
2247 return ret;
2248 }
2249
2250 wl->mac80211_registered = true;
2251
2252 wl1271_notice("loaded");
2253
2254 return 0;
2255}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002256EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002258void wl1271_unregister_hw(struct wl1271 *wl)
2259{
2260 ieee80211_unregister_hw(wl->hw);
2261 wl->mac80211_registered = false;
2262
2263}
2264EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2265
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002266int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002267{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002268 /* The tx descriptor buffer and the TKIP space. */
2269 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2270 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271
2272 /* unit us */
2273 /* FIXME: find a proper value */
2274 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002275 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276
2277 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002278 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002279 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002280 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002281 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002282 IEEE80211_HW_CONNECTION_MONITOR |
2283 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002285 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2286 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287 wl->hw->wiphy->max_scan_ssids = 1;
2288 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2289
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002290 if (wl1271_11a_enabled())
2291 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2292
Kalle Valo12bd8942010-03-18 12:26:33 +02002293 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002294 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002295
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002296 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297
2298 return 0;
2299}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002300EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002303
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002304struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002307 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002309 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002310
2311 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2312 if (!hw) {
2313 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002314 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002315 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316 }
2317
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002318 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2319 if (!plat_dev) {
2320 wl1271_error("could not allocate platform_device");
2321 ret = -ENOMEM;
2322 goto err_plat_alloc;
2323 }
2324
2325 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2326
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002327 wl = hw->priv;
2328 memset(wl, 0, sizeof(*wl));
2329
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002330 INIT_LIST_HEAD(&wl->list);
2331
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002333 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334
2335 skb_queue_head_init(&wl->tx_queue);
2336
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002337 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002339 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 wl->rx_counter = 0;
2342 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2343 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002344 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002346 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002347 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002348 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2349 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002350 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002351 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002352 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002353 wl->sg_enabled = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002354
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002355 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 wl->tx_frames[i] = NULL;
2357
2358 spin_lock_init(&wl->wl_lock);
2359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360 wl->state = WL1271_STATE_OFF;
2361 mutex_init(&wl->mutex);
2362
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002363 /* Apply default driver configuration. */
2364 wl1271_conf_init(wl);
2365
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002366 wl1271_debugfs_init(wl);
2367
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002368 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002369 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002370 if (ret) {
2371 wl1271_error("couldn't register platform device");
2372 goto err_hw;
2373 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002374 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002375
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002376 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002377 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002378 if (ret < 0) {
2379 wl1271_error("failed to create sysfs file bt_coex_state");
2380 goto err_platform;
2381 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002382
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002383 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002384
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002385err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002386 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002387
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002388err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002389 wl1271_debugfs_exit(wl);
2390 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002391
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002392err_plat_alloc:
2393 ieee80211_free_hw(hw);
2394
2395err_hw_alloc:
2396
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002397 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002398}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002399EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002400
2401int wl1271_free_hw(struct wl1271 *wl)
2402{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002403 platform_device_unregister(wl->plat_dev);
2404 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002405
2406 wl1271_debugfs_exit(wl);
2407
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002408 vfree(wl->fw);
2409 wl->fw = NULL;
2410 kfree(wl->nvs);
2411 wl->nvs = NULL;
2412
2413 kfree(wl->fw_status);
2414 kfree(wl->tx_res_if);
2415
2416 ieee80211_free_hw(wl->hw);
2417
2418 return 0;
2419}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002420EXPORT_SYMBOL_GPL(wl1271_free_hw);
2421
2422MODULE_LICENSE("GPL");
2423MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2424MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");