blob: b61cd102752f65a4ef30fb84e2f97324b4d0ce51 [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.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200469 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200470 continue;
471 }
472
473 intr &= WL1271_INTR_MASK;
474
475 if (intr & WL1271_ACX_INTR_DATA) {
476 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
477
478 /* check for tx results */
479 if (wl->fw_status->tx_results_counter !=
480 (wl->tx_results_count & 0xff))
481 wl1271_tx_complete(wl);
482
483 wl1271_rx(wl, wl->fw_status);
484 }
485
486 if (intr & WL1271_ACX_INTR_EVENT_A) {
487 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
488 wl1271_event_handle(wl, 0);
489 }
490
491 if (intr & WL1271_ACX_INTR_EVENT_B) {
492 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
493 wl1271_event_handle(wl, 1);
494 }
495
496 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
497 wl1271_debug(DEBUG_IRQ,
498 "WL1271_ACX_INTR_INIT_COMPLETE");
499
500 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
501 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
502
503 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504 }
505
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200506 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
507 ieee80211_queue_work(wl->hw, &wl->irq_work);
508 else
509 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
510 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300511
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512 wl1271_ps_elp_sleep(wl);
513
514out:
515 mutex_unlock(&wl->mutex);
516}
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518static int wl1271_fetch_firmware(struct wl1271 *wl)
519{
520 const struct firmware *fw;
521 int ret;
522
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200523 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300524
525 if (ret < 0) {
526 wl1271_error("could not get firmware: %d", ret);
527 return ret;
528 }
529
530 if (fw->size % 4) {
531 wl1271_error("firmware size is not multiple of 32 bits: %zu",
532 fw->size);
533 ret = -EILSEQ;
534 goto out;
535 }
536
537 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300538 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300539
540 if (!wl->fw) {
541 wl1271_error("could not allocate memory for the firmware");
542 ret = -ENOMEM;
543 goto out;
544 }
545
546 memcpy(wl->fw, fw->data, wl->fw_len);
547
548 ret = 0;
549
550out:
551 release_firmware(fw);
552
553 return ret;
554}
555
556static int wl1271_fetch_nvs(struct wl1271 *wl)
557{
558 const struct firmware *fw;
559 int ret;
560
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200561 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300562
563 if (ret < 0) {
564 wl1271_error("could not get nvs file: %d", ret);
565 return ret;
566 }
567
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200568 if (fw->size != sizeof(struct wl1271_nvs_file)) {
569 wl1271_error("nvs size is not as expected: %zu != %zu",
570 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300571 ret = -EILSEQ;
572 goto out;
573 }
574
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200575 wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300576
577 if (!wl->nvs) {
578 wl1271_error("could not allocate memory for the nvs file");
579 ret = -ENOMEM;
580 goto out;
581 }
582
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200583 memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300585out:
586 release_firmware(fw);
587
588 return ret;
589}
590
591static void wl1271_fw_wakeup(struct wl1271 *wl)
592{
593 u32 elp_reg;
594
595 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300596 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597}
598
599static int wl1271_setup(struct wl1271 *wl)
600{
601 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
602 if (!wl->fw_status)
603 return -ENOMEM;
604
605 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
606 if (!wl->tx_res_if) {
607 kfree(wl->fw_status);
608 return -ENOMEM;
609 }
610
611 INIT_WORK(&wl->irq_work, wl1271_irq_work);
612 INIT_WORK(&wl->tx_work, wl1271_tx_work);
613 return 0;
614}
615
616static int wl1271_chip_wakeup(struct wl1271 *wl)
617{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300618 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300619 int ret = 0;
620
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200621 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622 wl1271_power_on(wl);
623 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200624 wl1271_io_reset(wl);
625 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626
627 /* We don't need a real memory partition here, because we only want
628 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300629 memset(&partition, 0, sizeof(partition));
630 partition.reg.start = REGISTERS_BASE;
631 partition.reg.size = REGISTERS_DOWN_SIZE;
632 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633
634 /* ELP module wake up */
635 wl1271_fw_wakeup(wl);
636
637 /* whal_FwCtrl_BootSm() */
638
639 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200640 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641
642 /* 1. check if chip id is valid */
643
644 switch (wl->chip.id) {
645 case CHIP_ID_1271_PG10:
646 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
647 wl->chip.id);
648
649 ret = wl1271_setup(wl);
650 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200651 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652 break;
653 case CHIP_ID_1271_PG20:
654 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
655 wl->chip.id);
656
657 ret = wl1271_setup(wl);
658 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200659 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 break;
661 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200662 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200664 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300665 }
666
667 if (wl->fw == NULL) {
668 ret = wl1271_fetch_firmware(wl);
669 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200670 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 }
672
673 /* No NVS from netlink, try to get it from the filesystem */
674 if (wl->nvs == NULL) {
675 ret = wl1271_fetch_nvs(wl);
676 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200677 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300678 }
679
680out:
681 return ret;
682}
683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300684int wl1271_plt_start(struct wl1271 *wl)
685{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200686 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 int ret;
688
689 mutex_lock(&wl->mutex);
690
691 wl1271_notice("power up");
692
693 if (wl->state != WL1271_STATE_OFF) {
694 wl1271_error("cannot go into PLT state because not "
695 "in off state: %d", wl->state);
696 ret = -EBUSY;
697 goto out;
698 }
699
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200700 while (retries) {
701 retries--;
702 ret = wl1271_chip_wakeup(wl);
703 if (ret < 0)
704 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200706 ret = wl1271_boot(wl);
707 if (ret < 0)
708 goto power_off;
709
710 ret = wl1271_plt_init(wl);
711 if (ret < 0)
712 goto irq_disable;
713
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 wl->state = WL1271_STATE_PLT;
715 wl1271_notice("firmware booted in PLT mode (%s)",
716 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717 goto out;
718
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200719irq_disable:
720 wl1271_disable_interrupts(wl);
721 mutex_unlock(&wl->mutex);
722 /* Unlocking the mutex in the middle of handling is
723 inherently unsafe. In this case we deem it safe to do,
724 because we need to let any possibly pending IRQ out of
725 the system (and while we are WL1271_STATE_OFF the IRQ
726 work function will not do anything.) Also, any other
727 possible concurrent operations will fail due to the
728 current state, hence the wl1271 struct should be safe. */
729 cancel_work_sync(&wl->irq_work);
730 mutex_lock(&wl->mutex);
731power_off:
732 wl1271_power_off(wl);
733 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200735 wl1271_error("firmware boot in PLT mode failed despite %d retries",
736 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737out:
738 mutex_unlock(&wl->mutex);
739
740 return ret;
741}
742
743int wl1271_plt_stop(struct wl1271 *wl)
744{
745 int ret = 0;
746
747 mutex_lock(&wl->mutex);
748
749 wl1271_notice("power down");
750
751 if (wl->state != WL1271_STATE_PLT) {
752 wl1271_error("cannot power down because not in PLT "
753 "state: %d", wl->state);
754 ret = -EBUSY;
755 goto out;
756 }
757
758 wl1271_disable_interrupts(wl);
759 wl1271_power_off(wl);
760
761 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300762 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300763
764out:
765 mutex_unlock(&wl->mutex);
766
767 return ret;
768}
769
770
771static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
772{
773 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200774 struct ieee80211_conf *conf = &hw->conf;
775 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
776 struct ieee80211_sta *sta = txinfo->control.sta;
777 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200779 /* peek into the rates configured in the STA entry */
780 spin_lock_irqsave(&wl->wl_lock, flags);
781 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
782 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
783 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
784 }
785 spin_unlock_irqrestore(&wl->wl_lock, flags);
786
787 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788 skb_queue_tail(&wl->tx_queue, skb);
789
790 /*
791 * The chip specific setup must run before the first TX packet -
792 * before that, the tx_work will not be initialized!
793 */
794
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300795 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796
797 /*
798 * The workqueue is slow to process the tx_queue and we need stop
799 * the queue here, otherwise the queue will get too long.
800 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200801 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
802 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300803
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200804 spin_lock_irqsave(&wl->wl_lock, flags);
805 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200806 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200807 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300808 }
809
810 return NETDEV_TX_OK;
811}
812
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300813static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
814 void *arg)
815{
816 struct net_device *dev;
817 struct wireless_dev *wdev;
818 struct wiphy *wiphy;
819 struct ieee80211_hw *hw;
820 struct wl1271 *wl;
821 struct wl1271 *wl_temp;
822 struct in_device *idev;
823 struct in_ifaddr *ifa = arg;
824 int ret = 0;
825
826 /* FIXME: this ugly function should probably be implemented in the
827 * mac80211, and here should only be a simple callback handling actual
828 * setting of the filters. Now we need to dig up references to
829 * various structures to gain access to what we need.
830 * Also, because of this, there is no "initial" setting of the filter
831 * in "op_start", because we don't want to dig up struct net_device
832 * there - the filter will be set upon first change of the interface
833 * IP address. */
834
835 dev = ifa->ifa_dev->dev;
836
837 wdev = dev->ieee80211_ptr;
838 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200839 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300840
841 wiphy = wdev->wiphy;
842 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200843 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300844
845 hw = wiphy_priv(wiphy);
846 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200847 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300848
849 /* Check that the interface is one supported by this driver. */
850 wl_temp = hw->priv;
851 list_for_each_entry(wl, &wl_list, list) {
852 if (wl == wl_temp)
853 break;
854 }
855 if (wl == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200856 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300857
858 /* Get the interface IP address for the device. "ifa" will become
859 NULL if:
860 - there is no IPV4 protocol address configured
861 - there are multiple (virtual) IPV4 addresses configured
862 When "ifa" is NULL, filtering will be disabled.
863 */
864 ifa = NULL;
865 idev = dev->ip_ptr;
866 if (idev)
867 ifa = idev->ifa_list;
868
869 if (ifa && ifa->ifa_next)
870 ifa = NULL;
871
872 mutex_lock(&wl->mutex);
873
874 if (wl->state == WL1271_STATE_OFF)
875 goto out;
876
877 ret = wl1271_ps_elp_wakeup(wl, false);
878 if (ret < 0)
879 goto out;
880 if (ifa)
881 ret = wl1271_acx_arp_ip_filter(wl, true,
882 (u8 *)&ifa->ifa_address,
883 ACX_IPV4_VERSION);
884 else
885 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
886 ACX_IPV4_VERSION);
887 wl1271_ps_elp_sleep(wl);
888
889out:
890 mutex_unlock(&wl->mutex);
891
Luciano Coelho17d72652009-11-23 23:22:15 +0200892 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300893}
894
895static struct notifier_block wl1271_dev_notifier = {
896 .notifier_call = wl1271_dev_notify,
897};
898
899
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900static int wl1271_op_start(struct ieee80211_hw *hw)
901{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200902 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
903
904 /*
905 * We have to delay the booting of the hardware because
906 * we need to know the local MAC address before downloading and
907 * initializing the firmware. The MAC address cannot be changed
908 * after boot, and without the proper MAC address, the firmware
909 * will not function properly.
910 *
911 * The MAC address is first known when the corresponding interface
912 * is added. That is where we will initialize the hardware.
913 */
914
915 return 0;
916}
917
918static void wl1271_op_stop(struct ieee80211_hw *hw)
919{
920 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
921}
922
923static int wl1271_op_add_interface(struct ieee80211_hw *hw,
924 struct ieee80211_vif *vif)
925{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200927 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928 int ret = 0;
929
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200930 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
931 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300932
933 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200934 if (wl->vif) {
935 ret = -EBUSY;
936 goto out;
937 }
938
939 wl->vif = vif;
940
941 switch (vif->type) {
942 case NL80211_IFTYPE_STATION:
943 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200944 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200945 break;
946 case NL80211_IFTYPE_ADHOC:
947 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200948 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200949 break;
950 default:
951 ret = -EOPNOTSUPP;
952 goto out;
953 }
954
955 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
957 if (wl->state != WL1271_STATE_OFF) {
958 wl1271_error("cannot start because not in off state: %d",
959 wl->state);
960 ret = -EBUSY;
961 goto out;
962 }
963
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200964 while (retries) {
965 retries--;
966 ret = wl1271_chip_wakeup(wl);
967 if (ret < 0)
968 goto power_off;
969
970 ret = wl1271_boot(wl);
971 if (ret < 0)
972 goto power_off;
973
974 ret = wl1271_hw_init(wl);
975 if (ret < 0)
976 goto irq_disable;
977
978 wl->state = WL1271_STATE_ON;
979 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 goto out;
981
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200982irq_disable:
983 wl1271_disable_interrupts(wl);
984 mutex_unlock(&wl->mutex);
985 /* Unlocking the mutex in the middle of handling is
986 inherently unsafe. In this case we deem it safe to do,
987 because we need to let any possibly pending IRQ out of
988 the system (and while we are WL1271_STATE_OFF the IRQ
989 work function will not do anything.) Also, any other
990 possible concurrent operations will fail due to the
991 current state, hence the wl1271 struct should be safe. */
992 cancel_work_sync(&wl->irq_work);
993 mutex_lock(&wl->mutex);
994power_off:
995 wl1271_power_off(wl);
996 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200998 wl1271_error("firmware boot failed despite %d retries",
999 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001000out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001001 mutex_unlock(&wl->mutex);
1002
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001003 if (!ret) {
1004 list_add(&wl->list, &wl_list);
1005 register_inetaddr_notifier(&wl1271_dev_notifier);
1006 }
1007
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008 return ret;
1009}
1010
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001011static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1012 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013{
1014 struct wl1271 *wl = hw->priv;
1015 int i;
1016
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001017 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1018
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001019 mutex_lock(&wl->mutex);
1020 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001022 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001024 list_del(&wl->list);
1025
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 WARN_ON(wl->state != WL1271_STATE_ON);
1027
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001028 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029 mutex_unlock(&wl->mutex);
1030 ieee80211_scan_completed(wl->hw, true);
1031 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032 }
1033
1034 wl->state = WL1271_STATE_OFF;
1035
1036 wl1271_disable_interrupts(wl);
1037
1038 mutex_unlock(&wl->mutex);
1039
1040 cancel_work_sync(&wl->irq_work);
1041 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042
1043 mutex_lock(&wl->mutex);
1044
1045 /* let's notify MAC80211 about the remaining pending TX frames */
1046 wl1271_tx_flush(wl);
1047 wl1271_power_off(wl);
1048
1049 memset(wl->bssid, 0, ETH_ALEN);
1050 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1051 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001053 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001054 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001057 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1059 wl->tx_blocks_available = 0;
1060 wl->tx_results_count = 0;
1061 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001062 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001063 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064 wl->time_offset = 0;
1065 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001066 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1067 wl->sta_rate_set = 0;
1068 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001069 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001070 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001071
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 for (i = 0; i < NUM_TX_QUEUES; i++)
1073 wl->tx_blocks_freed[i] = 0;
1074
1075 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001076
1077 kfree(wl->fw_status);
1078 wl->fw_status = NULL;
1079 kfree(wl->tx_res_if);
1080 wl->tx_res_if = NULL;
1081 kfree(wl->target_mem_map);
1082 wl->target_mem_map = NULL;
1083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 mutex_unlock(&wl->mutex);
1085}
1086
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001087static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1088{
1089 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1090 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1091
1092 /* combine requested filters with current filter config */
1093 filters = wl->filters | filters;
1094
1095 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1096
1097 if (filters & FIF_PROMISC_IN_BSS) {
1098 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1099 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1100 wl->rx_config |= CFG_BSSID_FILTER_EN;
1101 }
1102 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1103 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1104 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1105 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1106 }
1107 if (filters & FIF_OTHER_BSS) {
1108 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1109 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1110 }
1111 if (filters & FIF_CONTROL) {
1112 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1113 wl->rx_filter |= CFG_RX_CTL_EN;
1114 }
1115 if (filters & FIF_FCSFAIL) {
1116 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1117 wl->rx_filter |= CFG_RX_FCS_ERROR;
1118 }
1119}
1120
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001121static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001122{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001123 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001124 /* we need to use a dummy BSSID for now */
1125 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1126 0xad, 0xbe, 0xef };
1127
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001128 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1129
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001130 /* pass through frames from all BSS */
1131 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1132
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001133 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001134 if (ret < 0)
1135 goto out;
1136
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001137 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001138
1139out:
1140 return ret;
1141}
1142
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001143static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001144{
1145 int ret;
1146
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001147 /*
1148 * One of the side effects of the JOIN command is that is clears
1149 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1150 * to a WPA/WPA2 access point will therefore kill the data-path.
1151 * Currently there is no supported scenario for JOIN during
1152 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1153 * must be handled somehow.
1154 *
1155 */
1156 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1157 wl1271_info("JOIN while associated.");
1158
1159 if (set_assoc)
1160 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1161
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001162 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1163 if (ret < 0)
1164 goto out;
1165
1166 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1167
1168 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1169 goto out;
1170
1171 /*
1172 * The join command disable the keep-alive mode, shut down its process,
1173 * and also clear the template config, so we need to reset it all after
1174 * the join. The acx_aid starts the keep-alive process, and the order
1175 * of the commands below is relevant.
1176 */
1177 ret = wl1271_acx_keep_alive_mode(wl, true);
1178 if (ret < 0)
1179 goto out;
1180
1181 ret = wl1271_acx_aid(wl, wl->aid);
1182 if (ret < 0)
1183 goto out;
1184
1185 ret = wl1271_cmd_build_klv_null_data(wl);
1186 if (ret < 0)
1187 goto out;
1188
1189 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1190 ACX_KEEP_ALIVE_TPL_VALID);
1191 if (ret < 0)
1192 goto out;
1193
1194out:
1195 return ret;
1196}
1197
1198static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001199{
1200 int ret;
1201
1202 /* to stop listening to a channel, we disconnect */
1203 ret = wl1271_cmd_disconnect(wl);
1204 if (ret < 0)
1205 goto out;
1206
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001207 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001209
1210 /* stop filterting packets based on bssid */
1211 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001212
1213out:
1214 return ret;
1215}
1216
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001217static void wl1271_set_band_rate(struct wl1271 *wl)
1218{
1219 if (wl->band == IEEE80211_BAND_2GHZ)
1220 wl->basic_rate_set = wl->conf.tx.basic_rate;
1221 else
1222 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1223}
1224
1225static u32 wl1271_min_rate_get(struct wl1271 *wl)
1226{
1227 int i;
1228 u32 rate = 0;
1229
1230 if (!wl->basic_rate_set) {
1231 WARN_ON(1);
1232 wl->basic_rate_set = wl->conf.tx.basic_rate;
1233 }
1234
1235 for (i = 0; !rate; i++) {
1236 if ((wl->basic_rate_set >> i) & 0x1)
1237 rate = 1 << i;
1238 }
1239
1240 return rate;
1241}
1242
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1244{
1245 struct wl1271 *wl = hw->priv;
1246 struct ieee80211_conf *conf = &hw->conf;
1247 int channel, ret = 0;
1248
1249 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1250
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001251 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252 channel,
1253 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001254 conf->power_level,
1255 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
1257 mutex_lock(&wl->mutex);
1258
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001259 if (unlikely(wl->state == WL1271_STATE_OFF))
1260 goto out;
1261
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262 ret = wl1271_ps_elp_wakeup(wl, false);
1263 if (ret < 0)
1264 goto out;
1265
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001266 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001267 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1268 ((wl->band != conf->channel->band) ||
1269 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001270 wl->band = conf->channel->band;
1271 wl->channel = channel;
1272
1273 /*
1274 * FIXME: the mac80211 should really provide a fixed rate
1275 * to use here. for now, just use the smallest possible rate
1276 * for the band as a fixed rate for association frames and
1277 * other control messages.
1278 */
1279 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1280 wl1271_set_band_rate(wl);
1281
1282 wl->basic_rate = wl1271_min_rate_get(wl);
1283 ret = wl1271_acx_rate_policies(wl);
1284 if (ret < 0)
1285 wl1271_warning("rate policy for update channel "
1286 "failed %d", ret);
1287
1288 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001289 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001290 if (ret < 0)
1291 wl1271_warning("cmd join to update channel "
1292 "failed %d", ret);
1293 }
1294 }
1295
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001296 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001297 if (conf->flags & IEEE80211_CONF_IDLE &&
1298 test_bit(WL1271_FLAG_JOINED, &wl->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001299 wl1271_unjoin(wl);
Juuso Oikarinen8f648c02009-12-11 15:41:10 +02001300 else if (!(conf->flags & IEEE80211_CONF_IDLE))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001301 wl1271_dummy_join(wl);
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02001302
1303 if (conf->flags & IEEE80211_CONF_IDLE) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001304 wl->rate_set = wl1271_min_rate_get(wl);
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001305 wl->sta_rate_set = 0;
1306 wl1271_acx_rate_policies(wl);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001307 wl1271_acx_keep_alive_config(
1308 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1309 ACX_KEEP_ALIVE_TPL_INVALID);
Juuso Oikarinene1972812010-04-09 11:07:29 +03001310 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1311 } else
1312 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 }
1314
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001315 if (conf->flags & IEEE80211_CONF_PS &&
1316 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1317 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318
1319 /*
1320 * We enter PSM only if we're already associated.
1321 * If we're not, we'll enter it when joining an SSID,
1322 * through the bss_info_changed() hook.
1323 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001324 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001325 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001326 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1327 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001328 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001330 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001331 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001333 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001335 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001336 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1337 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 }
1339
1340 if (conf->power_level != wl->power_level) {
1341 ret = wl1271_acx_tx_power(wl, conf->power_level);
1342 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001343 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001344
1345 wl->power_level = conf->power_level;
1346 }
1347
1348out_sleep:
1349 wl1271_ps_elp_sleep(wl);
1350
1351out:
1352 mutex_unlock(&wl->mutex);
1353
1354 return ret;
1355}
1356
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001357struct wl1271_filter_params {
1358 bool enabled;
1359 int mc_list_length;
1360 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1361};
1362
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001363static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
1364 struct dev_addr_list *mc_list)
1365{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001366 struct wl1271_filter_params *fp;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001367 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001368 int i;
1369
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001370 if (unlikely(wl->state == WL1271_STATE_OFF))
1371 return 0;
1372
Juuso Oikarinen74441132009-10-13 12:47:53 +03001373 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001374 if (!fp) {
1375 wl1271_error("Out of memory setting filters.");
1376 return 0;
1377 }
1378
1379 /* update multicast filtering parameters */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001380 fp->enabled = true;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001381 if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
1382 mc_count = 0;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001383 fp->enabled = false;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001384 }
1385
1386 fp->mc_list_length = 0;
1387 for (i = 0; i < mc_count; i++) {
1388 if (mc_list->da_addrlen == ETH_ALEN) {
1389 memcpy(fp->mc_list[fp->mc_list_length],
1390 mc_list->da_addr, ETH_ALEN);
1391 fp->mc_list_length++;
1392 } else
1393 wl1271_warning("Unknown mc address length.");
Juuso Oikarinen74441132009-10-13 12:47:53 +03001394 mc_list = mc_list->next;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001395 }
1396
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001397 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001398}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001400#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1401 FIF_ALLMULTI | \
1402 FIF_FCSFAIL | \
1403 FIF_BCN_PRBRESP_PROMISC | \
1404 FIF_CONTROL | \
1405 FIF_OTHER_BSS)
1406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1408 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001409 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001411 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001412 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001413 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414
1415 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1416
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001417 mutex_lock(&wl->mutex);
1418
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001419 *total &= WL1271_SUPPORTED_FILTERS;
1420 changed &= WL1271_SUPPORTED_FILTERS;
1421
1422 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001423 goto out;
1424
1425 ret = wl1271_ps_elp_wakeup(wl, false);
1426 if (ret < 0)
1427 goto out;
1428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001430 if (*total & FIF_ALLMULTI)
1431 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1432 else if (fp)
1433 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1434 fp->mc_list,
1435 fp->mc_list_length);
1436 if (ret < 0)
1437 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001439 /* determine, whether supported filter values have changed */
1440 if (changed == 0)
1441 goto out_sleep;
1442
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001443 /* configure filters */
1444 wl->filters = *total;
1445 wl1271_configure_filters(wl, 0);
1446
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001447 /* apply configured filters */
1448 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1449 if (ret < 0)
1450 goto out_sleep;
1451
1452out_sleep:
1453 wl1271_ps_elp_sleep(wl);
1454
1455out:
1456 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001457 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458}
1459
1460static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1461 struct ieee80211_vif *vif,
1462 struct ieee80211_sta *sta,
1463 struct ieee80211_key_conf *key_conf)
1464{
1465 struct wl1271 *wl = hw->priv;
1466 const u8 *addr;
1467 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001468 u32 tx_seq_32 = 0;
1469 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001470 u8 key_type;
1471
1472 static const u8 bcast_addr[ETH_ALEN] =
1473 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1474
1475 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1476
1477 addr = sta ? sta->addr : bcast_addr;
1478
1479 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1480 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1481 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1482 key_conf->alg, key_conf->keyidx,
1483 key_conf->keylen, key_conf->flags);
1484 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1485
1486 if (is_zero_ether_addr(addr)) {
1487 /* We dont support TX only encryption */
1488 ret = -EOPNOTSUPP;
1489 goto out;
1490 }
1491
1492 mutex_lock(&wl->mutex);
1493
1494 ret = wl1271_ps_elp_wakeup(wl, false);
1495 if (ret < 0)
1496 goto out_unlock;
1497
1498 switch (key_conf->alg) {
1499 case ALG_WEP:
1500 key_type = KEY_WEP;
1501
1502 key_conf->hw_key_idx = key_conf->keyidx;
1503 break;
1504 case ALG_TKIP:
1505 key_type = KEY_TKIP;
1506
1507 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001508 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1509 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510 break;
1511 case ALG_CCMP:
1512 key_type = KEY_AES;
1513
1514 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001515 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1516 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517 break;
1518 default:
1519 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1520
1521 ret = -EOPNOTSUPP;
1522 goto out_sleep;
1523 }
1524
1525 switch (cmd) {
1526 case SET_KEY:
1527 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1528 key_conf->keyidx, key_type,
1529 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001530 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 if (ret < 0) {
1532 wl1271_error("Could not add or replace key");
1533 goto out_sleep;
1534 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001535
1536 /* the default WEP key needs to be configured at least once */
1537 if (key_type == KEY_WEP) {
1538 ret = wl1271_cmd_set_default_wep_key(wl,
1539 wl->default_key);
1540 if (ret < 0)
1541 goto out_sleep;
1542 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 break;
1544
1545 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001546 /* The wl1271 does not allow to remove unicast keys - they
1547 will be cleared automatically on next CMD_JOIN. Ignore the
1548 request silently, as we dont want the mac80211 to emit
1549 an error message. */
1550 if (!is_broadcast_ether_addr(addr))
1551 break;
1552
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001553 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1554 key_conf->keyidx, key_type,
1555 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001556 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 if (ret < 0) {
1558 wl1271_error("Could not remove key");
1559 goto out_sleep;
1560 }
1561 break;
1562
1563 default:
1564 wl1271_error("Unsupported key cmd 0x%x", cmd);
1565 ret = -EOPNOTSUPP;
1566 goto out_sleep;
1567
1568 break;
1569 }
1570
1571out_sleep:
1572 wl1271_ps_elp_sleep(wl);
1573
1574out_unlock:
1575 mutex_unlock(&wl->mutex);
1576
1577out:
1578 return ret;
1579}
1580
1581static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001582 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001583 struct cfg80211_scan_request *req)
1584{
1585 struct wl1271 *wl = hw->priv;
1586 int ret;
1587 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001588 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001589
1590 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1591
1592 if (req->n_ssids) {
1593 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001594 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595 }
1596
1597 mutex_lock(&wl->mutex);
1598
1599 ret = wl1271_ps_elp_wakeup(wl, false);
1600 if (ret < 0)
1601 goto out;
1602
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001603 if (wl1271_11a_enabled())
Kalle Valo818e3062010-03-18 12:26:35 +02001604 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1605 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001606 WL1271_SCAN_BAND_DUAL, 3);
1607 else
Kalle Valo818e3062010-03-18 12:26:35 +02001608 ret = wl1271_cmd_scan(hw->priv, ssid, len,
1609 req->ie, req->ie_len, 1, 0,
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001610 WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001611
1612 wl1271_ps_elp_sleep(wl);
1613
1614out:
1615 mutex_unlock(&wl->mutex);
1616
1617 return ret;
1618}
1619
1620static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1621{
1622 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001623 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001624
1625 mutex_lock(&wl->mutex);
1626
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001627 if (unlikely(wl->state == WL1271_STATE_OFF))
1628 goto out;
1629
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001630 ret = wl1271_ps_elp_wakeup(wl, false);
1631 if (ret < 0)
1632 goto out;
1633
1634 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1635 if (ret < 0)
1636 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1637
1638 wl1271_ps_elp_sleep(wl);
1639
1640out:
1641 mutex_unlock(&wl->mutex);
1642
1643 return ret;
1644}
1645
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001646static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1647{
1648 u8 *ptr = beacon->data +
1649 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1650
1651 /* find the location of the ssid in the beacon */
1652 while (ptr < beacon->data + beacon->len) {
1653 if (ptr[0] == WLAN_EID_SSID) {
1654 wl->ssid_len = ptr[1];
1655 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1656 return;
1657 }
1658 ptr += ptr[1];
1659 }
1660 wl1271_error("ad-hoc beacon template has no SSID!\n");
1661}
1662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1664 struct ieee80211_vif *vif,
1665 struct ieee80211_bss_conf *bss_conf,
1666 u32 changed)
1667{
1668 enum wl1271_cmd_ps_mode mode;
1669 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001670 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001671 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001672 int ret;
1673
1674 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1675
1676 mutex_lock(&wl->mutex);
1677
1678 ret = wl1271_ps_elp_wakeup(wl, false);
1679 if (ret < 0)
1680 goto out;
1681
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001682 if ((changed && BSS_CHANGED_BEACON_INT) &&
1683 (wl->bss_type == BSS_TYPE_IBSS)) {
1684 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1685 bss_conf->beacon_int);
1686
1687 wl->beacon_int = bss_conf->beacon_int;
1688 do_join = true;
1689 }
1690
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001691 if ((changed && BSS_CHANGED_BEACON) &&
1692 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001693 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1694
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001695 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1696
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001697 if (beacon) {
1698 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001699
1700 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001701 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1702 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001703 beacon->len, 0,
1704 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001705
1706 if (ret < 0) {
1707 dev_kfree_skb(beacon);
1708 goto out_sleep;
1709 }
1710
1711 hdr = (struct ieee80211_hdr *) beacon->data;
1712 hdr->frame_control = cpu_to_le16(
1713 IEEE80211_FTYPE_MGMT |
1714 IEEE80211_STYPE_PROBE_RESP);
1715
1716 ret = wl1271_cmd_template_set(wl,
1717 CMD_TEMPL_PROBE_RESPONSE,
1718 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001719 beacon->len, 0,
1720 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001721 dev_kfree_skb(beacon);
1722 if (ret < 0)
1723 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001724
1725 /* Need to update the SSID (for filtering etc) */
1726 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001727 }
1728 }
1729
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001730 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1731 (wl->bss_type == BSS_TYPE_IBSS)) {
1732 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1733 bss_conf->enable_beacon ? "enabled" : "disabled");
1734
1735 if (bss_conf->enable_beacon)
1736 wl->set_bss_type = BSS_TYPE_IBSS;
1737 else
1738 wl->set_bss_type = BSS_TYPE_STA_BSS;
1739 do_join = true;
1740 }
1741
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001742 if (changed & BSS_CHANGED_CQM) {
1743 bool enable = false;
1744 if (bss_conf->cqm_rssi_thold)
1745 enable = true;
1746 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1747 bss_conf->cqm_rssi_thold,
1748 bss_conf->cqm_rssi_hyst);
1749 if (ret < 0)
1750 goto out;
1751 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1752 }
1753
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001754 if ((changed & BSS_CHANGED_BSSID) &&
1755 /*
1756 * Now we know the correct bssid, so we send a new join command
1757 * and enable the BSSID filter
1758 */
1759 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001760 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001761
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001762 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001763 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001764 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001765
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001766 ret = wl1271_build_qos_null_data(wl);
1767 if (ret < 0)
1768 goto out_sleep;
1769
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001770 /* filter out all packets not from this BSSID */
1771 wl1271_configure_filters(wl, 0);
1772
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001773 /* Need to update the BSSID (for filtering etc) */
1774 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001775 }
1776
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001777 if (changed & BSS_CHANGED_ASSOC) {
1778 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001779 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001781 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001783 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001784 * use basic rates from AP, and determine lowest rate
1785 * to use with control frames.
1786 */
1787 rates = bss_conf->basic_rates;
1788 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1789 rates);
1790 wl->basic_rate = wl1271_min_rate_get(wl);
1791 ret = wl1271_acx_rate_policies(wl);
1792 if (ret < 0)
1793 goto out_sleep;
1794
1795 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001796 * with wl1271, we don't need to update the
1797 * beacon_int and dtim_period, because the firmware
1798 * updates it by itself when the first beacon is
1799 * received after a join.
1800 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1802 if (ret < 0)
1803 goto out_sleep;
1804
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001805 /*
1806 * The SSID is intentionally set to NULL here - the
1807 * firmware will set the probe request with a
1808 * broadcast SSID regardless of what we set in the
1809 * template.
1810 */
1811 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1812 NULL, 0, wl->band);
1813
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001814 /* enable the connection monitoring feature */
1815 ret = wl1271_acx_conn_monit_params(wl, true);
1816 if (ret < 0)
1817 goto out_sleep;
1818
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001819 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001820 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1821 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001823 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 if (ret < 0)
1825 goto out_sleep;
1826 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001827 } else {
1828 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001829 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001830 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001831
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001832 /* revert back to minimum rates for the current band */
1833 wl1271_set_band_rate(wl);
1834 wl->basic_rate = wl1271_min_rate_get(wl);
1835 ret = wl1271_acx_rate_policies(wl);
1836 if (ret < 0)
1837 goto out_sleep;
1838
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001839 /* disable connection monitor features */
1840 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001841
1842 /* Disable the keep-alive feature */
1843 ret = wl1271_acx_keep_alive_mode(wl, false);
1844
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001845 if (ret < 0)
1846 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001848
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001851 if (changed & BSS_CHANGED_ERP_SLOT) {
1852 if (bss_conf->use_short_slot)
1853 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1854 else
1855 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1856 if (ret < 0) {
1857 wl1271_warning("Set slot time failed %d", ret);
1858 goto out_sleep;
1859 }
1860 }
1861
1862 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1863 if (bss_conf->use_short_preamble)
1864 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1865 else
1866 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1867 }
1868
1869 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1870 if (bss_conf->use_cts_prot)
1871 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1872 else
1873 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1874 if (ret < 0) {
1875 wl1271_warning("Set ctsprotect failed %d", ret);
1876 goto out_sleep;
1877 }
1878 }
1879
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001880 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001881 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001882 if (ret < 0) {
1883 wl1271_warning("cmd join failed %d", ret);
1884 goto out_sleep;
1885 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001886 }
1887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888out_sleep:
1889 wl1271_ps_elp_sleep(wl);
1890
1891out:
1892 mutex_unlock(&wl->mutex);
1893}
1894
Kalle Valoc6999d82010-02-18 13:25:41 +02001895static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1896 const struct ieee80211_tx_queue_params *params)
1897{
1898 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001899 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001900 int ret;
1901
1902 mutex_lock(&wl->mutex);
1903
1904 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1905
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001906 ret = wl1271_ps_elp_wakeup(wl, false);
1907 if (ret < 0)
1908 goto out;
1909
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001910 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001911 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1912 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001913 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001914 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001915 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001916
Kalle Valo4695dc92010-03-18 12:26:38 +02001917 if (params->uapsd)
1918 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1919 else
1920 ps_scheme = CONF_PS_SCHEME_LEGACY;
1921
Kalle Valoc6999d82010-02-18 13:25:41 +02001922 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1923 CONF_CHANNEL_TYPE_EDCF,
1924 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001925 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001926 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001927 goto out_sleep;
1928
1929out_sleep:
1930 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001931
1932out:
1933 mutex_unlock(&wl->mutex);
1934
1935 return ret;
1936}
1937
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938
1939/* can't be const, mac80211 writes to this */
1940static struct ieee80211_rate wl1271_rates[] = {
1941 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001945 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1946 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001947 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1948 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001949 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1950 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1952 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001953 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1954 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1956 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001957 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1958 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001960 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1961 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001963 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1964 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001965 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001966 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1967 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001969 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1970 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001972 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1973 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001975 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1976 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001978 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1979 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001980};
1981
1982/* can't be const, mac80211 writes to this */
1983static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001984 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1985 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1986 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1987 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1988 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1989 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1990 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1991 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1992 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1993 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1994 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1995 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1996 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997};
1998
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001999/* mapping to indexes for wl1271_rates */
2000const static u8 wl1271_rate_to_idx_2ghz[] = {
2001 /* MCS rates are used only with 11n */
2002 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2003 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2004 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2005 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2006 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2007 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2008 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2009 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2010
2011 11, /* CONF_HW_RXTX_RATE_54 */
2012 10, /* CONF_HW_RXTX_RATE_48 */
2013 9, /* CONF_HW_RXTX_RATE_36 */
2014 8, /* CONF_HW_RXTX_RATE_24 */
2015
2016 /* TI-specific rate */
2017 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2018
2019 7, /* CONF_HW_RXTX_RATE_18 */
2020 6, /* CONF_HW_RXTX_RATE_12 */
2021 3, /* CONF_HW_RXTX_RATE_11 */
2022 5, /* CONF_HW_RXTX_RATE_9 */
2023 4, /* CONF_HW_RXTX_RATE_6 */
2024 2, /* CONF_HW_RXTX_RATE_5_5 */
2025 1, /* CONF_HW_RXTX_RATE_2 */
2026 0 /* CONF_HW_RXTX_RATE_1 */
2027};
2028
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029/* can't be const, mac80211 writes to this */
2030static struct ieee80211_supported_band wl1271_band_2ghz = {
2031 .channels = wl1271_channels,
2032 .n_channels = ARRAY_SIZE(wl1271_channels),
2033 .bitrates = wl1271_rates,
2034 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2035};
2036
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002037/* 5 GHz data rates for WL1273 */
2038static struct ieee80211_rate wl1271_rates_5ghz[] = {
2039 { .bitrate = 60,
2040 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2041 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2042 { .bitrate = 90,
2043 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2044 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2045 { .bitrate = 120,
2046 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2047 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2048 { .bitrate = 180,
2049 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2050 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2051 { .bitrate = 240,
2052 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2053 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2054 { .bitrate = 360,
2055 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2056 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2057 { .bitrate = 480,
2058 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2059 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2060 { .bitrate = 540,
2061 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2062 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2063};
2064
2065/* 5 GHz band channels for WL1273 */
2066static struct ieee80211_channel wl1271_channels_5ghz[] = {
2067 { .hw_value = 183, .center_freq = 4915},
2068 { .hw_value = 184, .center_freq = 4920},
2069 { .hw_value = 185, .center_freq = 4925},
2070 { .hw_value = 187, .center_freq = 4935},
2071 { .hw_value = 188, .center_freq = 4940},
2072 { .hw_value = 189, .center_freq = 4945},
2073 { .hw_value = 192, .center_freq = 4960},
2074 { .hw_value = 196, .center_freq = 4980},
2075 { .hw_value = 7, .center_freq = 5035},
2076 { .hw_value = 8, .center_freq = 5040},
2077 { .hw_value = 9, .center_freq = 5045},
2078 { .hw_value = 11, .center_freq = 5055},
2079 { .hw_value = 12, .center_freq = 5060},
2080 { .hw_value = 16, .center_freq = 5080},
2081 { .hw_value = 34, .center_freq = 5170},
2082 { .hw_value = 36, .center_freq = 5180},
2083 { .hw_value = 38, .center_freq = 5190},
2084 { .hw_value = 40, .center_freq = 5200},
2085 { .hw_value = 42, .center_freq = 5210},
2086 { .hw_value = 44, .center_freq = 5220},
2087 { .hw_value = 46, .center_freq = 5230},
2088 { .hw_value = 48, .center_freq = 5240},
2089 { .hw_value = 52, .center_freq = 5260},
2090 { .hw_value = 56, .center_freq = 5280},
2091 { .hw_value = 60, .center_freq = 5300},
2092 { .hw_value = 64, .center_freq = 5320},
2093 { .hw_value = 100, .center_freq = 5500},
2094 { .hw_value = 104, .center_freq = 5520},
2095 { .hw_value = 108, .center_freq = 5540},
2096 { .hw_value = 112, .center_freq = 5560},
2097 { .hw_value = 116, .center_freq = 5580},
2098 { .hw_value = 120, .center_freq = 5600},
2099 { .hw_value = 124, .center_freq = 5620},
2100 { .hw_value = 128, .center_freq = 5640},
2101 { .hw_value = 132, .center_freq = 5660},
2102 { .hw_value = 136, .center_freq = 5680},
2103 { .hw_value = 140, .center_freq = 5700},
2104 { .hw_value = 149, .center_freq = 5745},
2105 { .hw_value = 153, .center_freq = 5765},
2106 { .hw_value = 157, .center_freq = 5785},
2107 { .hw_value = 161, .center_freq = 5805},
2108 { .hw_value = 165, .center_freq = 5825},
2109};
2110
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002111/* mapping to indexes for wl1271_rates_5ghz */
2112const static u8 wl1271_rate_to_idx_5ghz[] = {
2113 /* MCS rates are used only with 11n */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2115 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2116 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2117 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2118 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2119 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2120 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2121 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2122
2123 7, /* CONF_HW_RXTX_RATE_54 */
2124 6, /* CONF_HW_RXTX_RATE_48 */
2125 5, /* CONF_HW_RXTX_RATE_36 */
2126 4, /* CONF_HW_RXTX_RATE_24 */
2127
2128 /* TI-specific rate */
2129 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2130
2131 3, /* CONF_HW_RXTX_RATE_18 */
2132 2, /* CONF_HW_RXTX_RATE_12 */
2133 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2134 1, /* CONF_HW_RXTX_RATE_9 */
2135 0, /* CONF_HW_RXTX_RATE_6 */
2136 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2137 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2138 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2139};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002140
2141static struct ieee80211_supported_band wl1271_band_5ghz = {
2142 .channels = wl1271_channels_5ghz,
2143 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2144 .bitrates = wl1271_rates_5ghz,
2145 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2146};
2147
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002148const static u8 *wl1271_band_rate_to_idx[] = {
2149 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2150 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2151};
2152
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153static const struct ieee80211_ops wl1271_ops = {
2154 .start = wl1271_op_start,
2155 .stop = wl1271_op_stop,
2156 .add_interface = wl1271_op_add_interface,
2157 .remove_interface = wl1271_op_remove_interface,
2158 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002159 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 .configure_filter = wl1271_op_configure_filter,
2161 .tx = wl1271_op_tx,
2162 .set_key = wl1271_op_set_key,
2163 .hw_scan = wl1271_op_hw_scan,
2164 .bss_info_changed = wl1271_op_bss_info_changed,
2165 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002166 .conf_tx = wl1271_op_conf_tx,
Kalle Valoc8c90872010-02-18 13:25:53 +02002167 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002168};
2169
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002170
2171u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2172{
2173 u8 idx;
2174
2175 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2176
2177 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2178 wl1271_error("Illegal RX rate from HW: %d", rate);
2179 return 0;
2180 }
2181
2182 idx = wl1271_band_rate_to_idx[wl->band][rate];
2183 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2184 wl1271_error("Unsupported RX rate from HW: %d", rate);
2185 return 0;
2186 }
2187
2188 return idx;
2189}
2190
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002191static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2192 struct device_attribute *attr,
2193 char *buf)
2194{
2195 struct wl1271 *wl = dev_get_drvdata(dev);
2196 ssize_t len;
2197
2198 /* FIXME: what's the maximum length of buf? page size?*/
2199 len = 500;
2200
2201 mutex_lock(&wl->mutex);
2202 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2203 wl->sg_enabled);
2204 mutex_unlock(&wl->mutex);
2205
2206 return len;
2207
2208}
2209
2210static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2211 struct device_attribute *attr,
2212 const char *buf, size_t count)
2213{
2214 struct wl1271 *wl = dev_get_drvdata(dev);
2215 unsigned long res;
2216 int ret;
2217
2218 ret = strict_strtoul(buf, 10, &res);
2219
2220 if (ret < 0) {
2221 wl1271_warning("incorrect value written to bt_coex_mode");
2222 return count;
2223 }
2224
2225 mutex_lock(&wl->mutex);
2226
2227 res = !!res;
2228
2229 if (res == wl->sg_enabled)
2230 goto out;
2231
2232 wl->sg_enabled = res;
2233
2234 if (wl->state == WL1271_STATE_OFF)
2235 goto out;
2236
2237 ret = wl1271_ps_elp_wakeup(wl, false);
2238 if (ret < 0)
2239 goto out;
2240
2241 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2242 wl1271_ps_elp_sleep(wl);
2243
2244 out:
2245 mutex_unlock(&wl->mutex);
2246 return count;
2247}
2248
2249static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2250 wl1271_sysfs_show_bt_coex_state,
2251 wl1271_sysfs_store_bt_coex_state);
2252
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002253static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2254 struct device_attribute *attr,
2255 char *buf)
2256{
2257 struct wl1271 *wl = dev_get_drvdata(dev);
2258 ssize_t len;
2259
2260 /* FIXME: what's the maximum length of buf? page size?*/
2261 len = 500;
2262
2263 mutex_lock(&wl->mutex);
2264 if (wl->hw_pg_ver >= 0)
2265 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2266 else
2267 len = snprintf(buf, len, "n/a\n");
2268 mutex_unlock(&wl->mutex);
2269
2270 return len;
2271}
2272
2273static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2274 wl1271_sysfs_show_hw_pg_ver, NULL);
2275
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002276int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002277{
2278 int ret;
2279
2280 if (wl->mac80211_registered)
2281 return 0;
2282
2283 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2284
2285 ret = ieee80211_register_hw(wl->hw);
2286 if (ret < 0) {
2287 wl1271_error("unable to register mac80211 hw: %d", ret);
2288 return ret;
2289 }
2290
2291 wl->mac80211_registered = true;
2292
2293 wl1271_notice("loaded");
2294
2295 return 0;
2296}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002297EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002299void wl1271_unregister_hw(struct wl1271 *wl)
2300{
2301 ieee80211_unregister_hw(wl->hw);
2302 wl->mac80211_registered = false;
2303
2304}
2305EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2306
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002307int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002309 /* The tx descriptor buffer and the TKIP space. */
2310 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2311 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312
2313 /* unit us */
2314 /* FIXME: find a proper value */
2315 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002316 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317
2318 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002319 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002320 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002321 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002322 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002323 IEEE80211_HW_CONNECTION_MONITOR |
2324 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002325
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002326 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2327 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002328 wl->hw->wiphy->max_scan_ssids = 1;
2329 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2330
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002331 if (wl1271_11a_enabled())
2332 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2333
Kalle Valo12bd8942010-03-18 12:26:33 +02002334 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002335 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002336
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002337 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338
2339 return 0;
2340}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002341EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002342
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002344
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002345struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002346{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002348 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002350 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351
2352 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2353 if (!hw) {
2354 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002355 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002356 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002357 }
2358
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002359 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2360 if (!plat_dev) {
2361 wl1271_error("could not allocate platform_device");
2362 ret = -ENOMEM;
2363 goto err_plat_alloc;
2364 }
2365
2366 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 wl = hw->priv;
2369 memset(wl, 0, sizeof(*wl));
2370
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002371 INIT_LIST_HEAD(&wl->list);
2372
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002374 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375
2376 skb_queue_head_init(&wl->tx_queue);
2377
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002378 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002380 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002381 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382 wl->rx_counter = 0;
2383 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2384 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002385 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002387 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002388 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002389 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2390 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002391 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002392 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002393 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002394 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002395 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002397 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398 wl->tx_frames[i] = NULL;
2399
2400 spin_lock_init(&wl->wl_lock);
2401
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002402 wl->state = WL1271_STATE_OFF;
2403 mutex_init(&wl->mutex);
2404
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002405 /* Apply default driver configuration. */
2406 wl1271_conf_init(wl);
2407
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002408 wl1271_debugfs_init(wl);
2409
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002410 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002411 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002412 if (ret) {
2413 wl1271_error("couldn't register platform device");
2414 goto err_hw;
2415 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002416 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002417
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002418 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002419 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002420 if (ret < 0) {
2421 wl1271_error("failed to create sysfs file bt_coex_state");
2422 goto err_platform;
2423 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002424
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002425 /* Create sysfs file to get HW PG version */
2426 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2427 if (ret < 0) {
2428 wl1271_error("failed to create sysfs file hw_pg_ver");
2429 goto err_bt_coex_state;
2430 }
2431
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002432 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002433
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002434err_bt_coex_state:
2435 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2436
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002437err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002438 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002439
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002440err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002441 wl1271_debugfs_exit(wl);
2442 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002443
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002444err_plat_alloc:
2445 ieee80211_free_hw(hw);
2446
2447err_hw_alloc:
2448
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002449 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002450}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002451EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002452
2453int wl1271_free_hw(struct wl1271 *wl)
2454{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002455 platform_device_unregister(wl->plat_dev);
2456 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002457
2458 wl1271_debugfs_exit(wl);
2459
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002460 vfree(wl->fw);
2461 wl->fw = NULL;
2462 kfree(wl->nvs);
2463 wl->nvs = NULL;
2464
2465 kfree(wl->fw_status);
2466 kfree(wl->tx_res_if);
2467
2468 ieee80211_free_hw(wl->hw);
2469
2470 return 0;
2471}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002472EXPORT_SYMBOL_GPL(wl1271_free_hw);
2473
2474MODULE_LICENSE("GPL");
2475MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2476MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");