blob: 5970fde49d40c7c9302d81c4a462822bb031bfac [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
35#include "wl1271.h"
36#include "wl12xx_80211.h"
37#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020038#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl1271_event.h"
40#include "wl1271_tx.h"
41#include "wl1271_rx.h"
42#include "wl1271_ps.h"
43#include "wl1271_init.h"
44#include "wl1271_debugfs.h"
45#include "wl1271_cmd.h"
46#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020047#include "wl1271_testmode.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030048
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020049#define WL1271_BOOT_RETRIES 3
50
Juuso Oikarinen8a080482009-10-13 12:47:44 +030051static struct conf_drv_settings default_conf = {
52 .sg = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020053 .params = {
54 [CONF_SG_BT_PER_THRESHOLD] = 7500,
55 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
56 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
57 [CONF_SG_BT_LOAD_RATIO] = 50,
58 [CONF_SG_AUTO_PS_MODE] = 0,
59 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
60 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
61 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
62 [CONF_SG_BEACON_MISS_PERCENT] = 60,
63 [CONF_SG_RATE_ADAPT_THRESH] = 12,
64 [CONF_SG_RATE_ADAPT_SNR] = 0,
65 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
67 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
68 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
70 /* Note: with UPSD, this should be 4 */
71 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
72 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
74 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
75 /* Note: with UPDS, this should be 15 */
76 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
77 /* Note: with UPDS, this should be 50 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
79 /* Note: with UPDS, this should be 10 */
80 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
81 [CONF_SG_RXT] = 1200,
82 [CONF_SG_TXT] = 1000,
83 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
84 [CONF_SG_PS_POLL_TIMEOUT] = 10,
85 [CONF_SG_UPSD_TIMEOUT] = 10,
86 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
88 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
91 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
94 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
95 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
97 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
98 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
99 [CONF_SG_HV3_MAX_SERVED] = 6,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
102 },
103 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300104 },
105 .rx = {
106 .rx_msdu_life_time = 512000,
107 .packet_detection_threshold = 0,
108 .ps_poll_timeout = 15,
109 .upsd_timeout = 15,
110 .rts_threshold = 2347,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200111 .rx_cca_threshold = 0,
112 .irq_blk_threshold = 0xFFFF,
113 .irq_pkt_threshold = 0,
114 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300115 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
116 },
117 .tx = {
118 .tx_energy_detection = 0,
119 .rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300120 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300121 .short_retry_limit = 10,
122 .long_retry_limit = 10,
123 .aflags = 0
124 },
125 .ac_conf_count = 4,
126 .ac_conf = {
127 [0] = {
128 .ac = CONF_TX_AC_BE,
129 .cw_min = 15,
130 .cw_max = 63,
131 .aifsn = 3,
132 .tx_op_limit = 0,
133 },
134 [1] = {
135 .ac = CONF_TX_AC_BK,
136 .cw_min = 15,
137 .cw_max = 63,
138 .aifsn = 7,
139 .tx_op_limit = 0,
140 },
141 [2] = {
142 .ac = CONF_TX_AC_VI,
143 .cw_min = 15,
144 .cw_max = 63,
145 .aifsn = CONF_TX_AIFS_PIFS,
146 .tx_op_limit = 3008,
147 },
148 [3] = {
149 .ac = CONF_TX_AC_VO,
150 .cw_min = 15,
151 .cw_max = 63,
152 .aifsn = CONF_TX_AIFS_PIFS,
153 .tx_op_limit = 1504,
154 },
155 },
156 .tid_conf_count = 7,
157 .tid_conf = {
158 [0] = {
159 .queue_id = 0,
160 .channel_type = CONF_CHANNEL_TYPE_DCF,
161 .tsid = CONF_TX_AC_BE,
162 .ps_scheme = CONF_PS_SCHEME_LEGACY,
163 .ack_policy = CONF_ACK_POLICY_LEGACY,
164 .apsd_conf = {0, 0},
165 },
166 [1] = {
167 .queue_id = 1,
168 .channel_type = CONF_CHANNEL_TYPE_DCF,
169 .tsid = CONF_TX_AC_BE,
170 .ps_scheme = CONF_PS_SCHEME_LEGACY,
171 .ack_policy = CONF_ACK_POLICY_LEGACY,
172 .apsd_conf = {0, 0},
173 },
174 [2] = {
175 .queue_id = 2,
176 .channel_type = CONF_CHANNEL_TYPE_DCF,
177 .tsid = CONF_TX_AC_BE,
178 .ps_scheme = CONF_PS_SCHEME_LEGACY,
179 .ack_policy = CONF_ACK_POLICY_LEGACY,
180 .apsd_conf = {0, 0},
181 },
182 [3] = {
183 .queue_id = 3,
184 .channel_type = CONF_CHANNEL_TYPE_DCF,
185 .tsid = CONF_TX_AC_BE,
186 .ps_scheme = CONF_PS_SCHEME_LEGACY,
187 .ack_policy = CONF_ACK_POLICY_LEGACY,
188 .apsd_conf = {0, 0},
189 },
190 [4] = {
191 .queue_id = 4,
192 .channel_type = CONF_CHANNEL_TYPE_DCF,
193 .tsid = CONF_TX_AC_BE,
194 .ps_scheme = CONF_PS_SCHEME_LEGACY,
195 .ack_policy = CONF_ACK_POLICY_LEGACY,
196 .apsd_conf = {0, 0},
197 },
198 [5] = {
199 .queue_id = 5,
200 .channel_type = CONF_CHANNEL_TYPE_DCF,
201 .tsid = CONF_TX_AC_BE,
202 .ps_scheme = CONF_PS_SCHEME_LEGACY,
203 .ack_policy = CONF_ACK_POLICY_LEGACY,
204 .apsd_conf = {0, 0},
205 },
206 [6] = {
207 .queue_id = 6,
208 .channel_type = CONF_CHANNEL_TYPE_DCF,
209 .tsid = CONF_TX_AC_BE,
210 .ps_scheme = CONF_PS_SCHEME_LEGACY,
211 .ack_policy = CONF_ACK_POLICY_LEGACY,
212 .apsd_conf = {0, 0},
213 }
214 },
215 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200216 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300217 .tx_compl_threshold = 4,
218 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
219 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300224 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
225 .bcn_filt_ie_count = 1,
226 .bcn_filt_ie = {
227 [0] = {
228 .ie = WLAN_EID_CHANNEL_SWITCH,
229 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
230 }
231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200237 .ps_poll_threshold = 20,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300238 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200239 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200240 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300241 .keep_alive_interval = 55000,
242 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 },
244 .init = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 .radioparam = {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200246 .fem = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 }
Luciano Coelho6e92b412009-12-11 15:40:50 +0200248 },
249 .itrim = {
250 .enable = false,
251 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200252 },
253 .pm_config = {
254 .host_clk_settling_time = 5000,
255 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 },
257 .roam_trigger = {
258 /* FIXME: due to firmware bug, must use value 1 for now */
259 .trigger_pacing = 1,
260 .avg_weight_rssi_beacon = 20,
261 .avg_weight_rssi_data = 10,
262 .avg_weight_snr_beacon = 20,
263 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300264 }
265};
266
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200267static void wl1271_device_release(struct device *dev)
268{
269
270}
271
272static struct platform_device wl1271_device = {
273 .name = "wl1271",
274 .id = -1,
275
276 /* device model insists to have a release function */
277 .dev = {
278 .release = wl1271_device_release,
279 },
280};
281
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300282static LIST_HEAD(wl_list);
283
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300284static void wl1271_conf_init(struct wl1271 *wl)
285{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300286
287 /*
288 * This function applies the default configuration to the driver. This
289 * function is invoked upon driver load (spi probe.)
290 *
291 * The configuration is stored in a run-time structure in order to
292 * facilitate for run-time adjustment of any of the parameters. Making
293 * changes to the configuration structure will apply the new values on
294 * the next interface up (wl1271_op_start.)
295 */
296
297 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300298 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300299}
300
301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300302static int wl1271_plt_init(struct wl1271 *wl)
303{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200304 struct conf_tx_ac_category *conf_ac;
305 struct conf_tx_tid *conf_tid;
306 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300307
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200308 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200309 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200310 return ret;
311
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200312 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200313 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200314 return ret;
315
Luciano Coelho12419cc2010-02-18 13:25:44 +0200316 ret = wl1271_init_templates_config(wl);
317 if (ret < 0)
318 return ret;
319
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300320 ret = wl1271_acx_init_mem_config(wl);
321 if (ret < 0)
322 return ret;
323
Luciano Coelho12419cc2010-02-18 13:25:44 +0200324 /* PHY layer config */
325 ret = wl1271_init_phy_config(wl);
326 if (ret < 0)
327 goto out_free_memmap;
328
329 ret = wl1271_acx_dco_itrim_params(wl);
330 if (ret < 0)
331 goto out_free_memmap;
332
333 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200334 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200335 if (ret < 0)
336 goto out_free_memmap;
337
338 /* Bluetooth WLAN coexistence */
339 ret = wl1271_init_pta(wl);
340 if (ret < 0)
341 goto out_free_memmap;
342
343 /* Energy detection */
344 ret = wl1271_init_energy_detection(wl);
345 if (ret < 0)
346 goto out_free_memmap;
347
348 /* Default fragmentation threshold */
349 ret = wl1271_acx_frag_threshold(wl);
350 if (ret < 0)
351 goto out_free_memmap;
352
353 /* Default TID configuration */
354 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
355 conf_tid = &wl->conf.tx.tid_conf[i];
356 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
357 conf_tid->channel_type,
358 conf_tid->tsid,
359 conf_tid->ps_scheme,
360 conf_tid->ack_policy,
361 conf_tid->apsd_conf[0],
362 conf_tid->apsd_conf[1]);
363 if (ret < 0)
364 goto out_free_memmap;
365 }
366
367 /* Default AC configuration */
368 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
369 conf_ac = &wl->conf.tx.ac_conf[i];
370 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
371 conf_ac->cw_max, conf_ac->aifsn,
372 conf_ac->tx_op_limit);
373 if (ret < 0)
374 goto out_free_memmap;
375 }
376
377 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200378 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300379 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200380 goto out_free_memmap;
381
382 /* Configure for CAM power saving (ie. always active) */
383 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
384 if (ret < 0)
385 goto out_free_memmap;
386
387 /* configure PM */
388 ret = wl1271_acx_pm_config(wl);
389 if (ret < 0)
390 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300391
392 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200393
394 out_free_memmap:
395 kfree(wl->target_mem_map);
396 wl->target_mem_map = NULL;
397
398 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399}
400
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300401static void wl1271_fw_status(struct wl1271 *wl,
402 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300403{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200404 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405 u32 total = 0;
406 int i;
407
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200408 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300409
410 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
411 "drv_rx_counter = %d, tx_results_counter = %d)",
412 status->intr,
413 status->fw_rx_counter,
414 status->drv_rx_counter,
415 status->tx_results_counter);
416
417 /* update number of available TX blocks */
418 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300419 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
420 wl->tx_blocks_freed[i];
421
422 wl->tx_blocks_freed[i] =
423 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300424 wl->tx_blocks_available += cnt;
425 total += cnt;
426 }
427
428 /* if more blocks are available now, schedule some tx work */
429 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300430 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300431
432 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200433 getnstimeofday(&ts);
434 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
435 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436}
437
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200438#define WL1271_IRQ_MAX_LOOPS 10
439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300440static void wl1271_irq_work(struct work_struct *work)
441{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300443 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200444 int loopcount = WL1271_IRQ_MAX_LOOPS;
445 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300446 struct wl1271 *wl =
447 container_of(work, struct wl1271, irq_work);
448
449 mutex_lock(&wl->mutex);
450
451 wl1271_debug(DEBUG_IRQ, "IRQ work");
452
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200453 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300454 goto out;
455
456 ret = wl1271_ps_elp_wakeup(wl, true);
457 if (ret < 0)
458 goto out;
459
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200460 spin_lock_irqsave(&wl->wl_lock, flags);
461 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
462 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
463 spin_unlock_irqrestore(&wl->wl_lock, flags);
464 loopcount--;
465
466 wl1271_fw_status(wl, wl->fw_status);
467 intr = le32_to_cpu(wl->fw_status->intr);
468 if (!intr) {
469 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200470 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200471 continue;
472 }
473
474 intr &= WL1271_INTR_MASK;
475
476 if (intr & WL1271_ACX_INTR_DATA) {
477 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
478
479 /* check for tx results */
480 if (wl->fw_status->tx_results_counter !=
481 (wl->tx_results_count & 0xff))
482 wl1271_tx_complete(wl);
483
484 wl1271_rx(wl, wl->fw_status);
485 }
486
487 if (intr & WL1271_ACX_INTR_EVENT_A) {
488 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
489 wl1271_event_handle(wl, 0);
490 }
491
492 if (intr & WL1271_ACX_INTR_EVENT_B) {
493 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
494 wl1271_event_handle(wl, 1);
495 }
496
497 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
498 wl1271_debug(DEBUG_IRQ,
499 "WL1271_ACX_INTR_INIT_COMPLETE");
500
501 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
502 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
503
504 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300505 }
506
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200507 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
508 ieee80211_queue_work(wl->hw, &wl->irq_work);
509 else
510 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
511 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300513 wl1271_ps_elp_sleep(wl);
514
515out:
516 mutex_unlock(&wl->mutex);
517}
518
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300519static int wl1271_fetch_firmware(struct wl1271 *wl)
520{
521 const struct firmware *fw;
522 int ret;
523
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200524 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300525
526 if (ret < 0) {
527 wl1271_error("could not get firmware: %d", ret);
528 return ret;
529 }
530
531 if (fw->size % 4) {
532 wl1271_error("firmware size is not multiple of 32 bits: %zu",
533 fw->size);
534 ret = -EILSEQ;
535 goto out;
536 }
537
538 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300539 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300540
541 if (!wl->fw) {
542 wl1271_error("could not allocate memory for the firmware");
543 ret = -ENOMEM;
544 goto out;
545 }
546
547 memcpy(wl->fw, fw->data, wl->fw_len);
548
549 ret = 0;
550
551out:
552 release_firmware(fw);
553
554 return ret;
555}
556
557static int wl1271_fetch_nvs(struct wl1271 *wl)
558{
559 const struct firmware *fw;
560 int ret;
561
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200562 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300563
564 if (ret < 0) {
565 wl1271_error("could not get nvs file: %d", ret);
566 return ret;
567 }
568
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300569 /*
570 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
571 * configurations) can be removed when those NVS files stop floating
572 * around.
573 */
574 if (fw->size != sizeof(struct wl1271_nvs_file) &&
575 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
576 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200577 wl1271_error("nvs size is not as expected: %zu != %zu",
578 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300579 ret = -EILSEQ;
580 goto out;
581 }
582
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300583 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584
585 if (!wl->nvs) {
586 wl1271_error("could not allocate memory for the nvs file");
587 ret = -ENOMEM;
588 goto out;
589 }
590
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300591 memcpy(wl->nvs, fw->data, fw->size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300592
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300593out:
594 release_firmware(fw);
595
596 return ret;
597}
598
599static void wl1271_fw_wakeup(struct wl1271 *wl)
600{
601 u32 elp_reg;
602
603 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300604 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300605}
606
607static int wl1271_setup(struct wl1271 *wl)
608{
609 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
610 if (!wl->fw_status)
611 return -ENOMEM;
612
613 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
614 if (!wl->tx_res_if) {
615 kfree(wl->fw_status);
616 return -ENOMEM;
617 }
618
619 INIT_WORK(&wl->irq_work, wl1271_irq_work);
620 INIT_WORK(&wl->tx_work, wl1271_tx_work);
621 return 0;
622}
623
624static int wl1271_chip_wakeup(struct wl1271 *wl)
625{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300626 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300627 int ret = 0;
628
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200629 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300630 wl1271_power_on(wl);
631 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200632 wl1271_io_reset(wl);
633 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300634
635 /* We don't need a real memory partition here, because we only want
636 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300637 memset(&partition, 0, sizeof(partition));
638 partition.reg.start = REGISTERS_BASE;
639 partition.reg.size = REGISTERS_DOWN_SIZE;
640 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641
642 /* ELP module wake up */
643 wl1271_fw_wakeup(wl);
644
645 /* whal_FwCtrl_BootSm() */
646
647 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200648 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300649
650 /* 1. check if chip id is valid */
651
652 switch (wl->chip.id) {
653 case CHIP_ID_1271_PG10:
654 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
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 case CHIP_ID_1271_PG20:
662 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
663 wl->chip.id);
664
665 ret = wl1271_setup(wl);
666 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200667 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300668 break;
669 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200670 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200672 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300673 }
674
675 if (wl->fw == NULL) {
676 ret = wl1271_fetch_firmware(wl);
677 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200678 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679 }
680
681 /* No NVS from netlink, try to get it from the filesystem */
682 if (wl->nvs == NULL) {
683 ret = wl1271_fetch_nvs(wl);
684 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200685 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 }
687
688out:
689 return ret;
690}
691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692int wl1271_plt_start(struct wl1271 *wl)
693{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200694 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300695 int ret;
696
697 mutex_lock(&wl->mutex);
698
699 wl1271_notice("power up");
700
701 if (wl->state != WL1271_STATE_OFF) {
702 wl1271_error("cannot go into PLT state because not "
703 "in off state: %d", wl->state);
704 ret = -EBUSY;
705 goto out;
706 }
707
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200708 while (retries) {
709 retries--;
710 ret = wl1271_chip_wakeup(wl);
711 if (ret < 0)
712 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200714 ret = wl1271_boot(wl);
715 if (ret < 0)
716 goto power_off;
717
718 ret = wl1271_plt_init(wl);
719 if (ret < 0)
720 goto irq_disable;
721
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200722 wl->state = WL1271_STATE_PLT;
723 wl1271_notice("firmware booted in PLT mode (%s)",
724 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300725 goto out;
726
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200727irq_disable:
728 wl1271_disable_interrupts(wl);
729 mutex_unlock(&wl->mutex);
730 /* Unlocking the mutex in the middle of handling is
731 inherently unsafe. In this case we deem it safe to do,
732 because we need to let any possibly pending IRQ out of
733 the system (and while we are WL1271_STATE_OFF the IRQ
734 work function will not do anything.) Also, any other
735 possible concurrent operations will fail due to the
736 current state, hence the wl1271 struct should be safe. */
737 cancel_work_sync(&wl->irq_work);
738 mutex_lock(&wl->mutex);
739power_off:
740 wl1271_power_off(wl);
741 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300742
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200743 wl1271_error("firmware boot in PLT mode failed despite %d retries",
744 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300745out:
746 mutex_unlock(&wl->mutex);
747
748 return ret;
749}
750
751int wl1271_plt_stop(struct wl1271 *wl)
752{
753 int ret = 0;
754
755 mutex_lock(&wl->mutex);
756
757 wl1271_notice("power down");
758
759 if (wl->state != WL1271_STATE_PLT) {
760 wl1271_error("cannot power down because not in PLT "
761 "state: %d", wl->state);
762 ret = -EBUSY;
763 goto out;
764 }
765
766 wl1271_disable_interrupts(wl);
767 wl1271_power_off(wl);
768
769 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300770 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
772out:
773 mutex_unlock(&wl->mutex);
774
775 return ret;
776}
777
778
779static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
780{
781 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200782 struct ieee80211_conf *conf = &hw->conf;
783 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
784 struct ieee80211_sta *sta = txinfo->control.sta;
785 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200787 /* peek into the rates configured in the STA entry */
788 spin_lock_irqsave(&wl->wl_lock, flags);
789 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
790 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
791 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
792 }
793 spin_unlock_irqrestore(&wl->wl_lock, flags);
794
795 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796 skb_queue_tail(&wl->tx_queue, skb);
797
798 /*
799 * The chip specific setup must run before the first TX packet -
800 * before that, the tx_work will not be initialized!
801 */
802
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300803 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804
805 /*
806 * The workqueue is slow to process the tx_queue and we need stop
807 * the queue here, otherwise the queue will get too long.
808 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200809 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
810 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300811
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200812 spin_lock_irqsave(&wl->wl_lock, flags);
813 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200814 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200815 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 }
817
818 return NETDEV_TX_OK;
819}
820
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300821static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
822 void *arg)
823{
824 struct net_device *dev;
825 struct wireless_dev *wdev;
826 struct wiphy *wiphy;
827 struct ieee80211_hw *hw;
828 struct wl1271 *wl;
829 struct wl1271 *wl_temp;
830 struct in_device *idev;
831 struct in_ifaddr *ifa = arg;
832 int ret = 0;
833
834 /* FIXME: this ugly function should probably be implemented in the
835 * mac80211, and here should only be a simple callback handling actual
836 * setting of the filters. Now we need to dig up references to
837 * various structures to gain access to what we need.
838 * Also, because of this, there is no "initial" setting of the filter
839 * in "op_start", because we don't want to dig up struct net_device
840 * there - the filter will be set upon first change of the interface
841 * IP address. */
842
843 dev = ifa->ifa_dev->dev;
844
845 wdev = dev->ieee80211_ptr;
846 if (wdev == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200847 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300848
849 wiphy = wdev->wiphy;
850 if (wiphy == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200851 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300852
853 hw = wiphy_priv(wiphy);
854 if (hw == NULL)
Luciano Coelho17d72652009-11-23 23:22:15 +0200855 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300856
857 /* Check that the interface is one supported by this driver. */
858 wl_temp = hw->priv;
859 list_for_each_entry(wl, &wl_list, list) {
860 if (wl == wl_temp)
861 break;
862 }
Dan Carpenter8607b792010-05-08 18:25:51 +0200863 if (wl != wl_temp)
Luciano Coelho17d72652009-11-23 23:22:15 +0200864 return NOTIFY_DONE;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300865
866 /* Get the interface IP address for the device. "ifa" will become
867 NULL if:
868 - there is no IPV4 protocol address configured
869 - there are multiple (virtual) IPV4 addresses configured
870 When "ifa" is NULL, filtering will be disabled.
871 */
872 ifa = NULL;
873 idev = dev->ip_ptr;
874 if (idev)
875 ifa = idev->ifa_list;
876
877 if (ifa && ifa->ifa_next)
878 ifa = NULL;
879
880 mutex_lock(&wl->mutex);
881
882 if (wl->state == WL1271_STATE_OFF)
883 goto out;
884
885 ret = wl1271_ps_elp_wakeup(wl, false);
886 if (ret < 0)
887 goto out;
888 if (ifa)
889 ret = wl1271_acx_arp_ip_filter(wl, true,
890 (u8 *)&ifa->ifa_address,
891 ACX_IPV4_VERSION);
892 else
893 ret = wl1271_acx_arp_ip_filter(wl, false, NULL,
894 ACX_IPV4_VERSION);
895 wl1271_ps_elp_sleep(wl);
896
897out:
898 mutex_unlock(&wl->mutex);
899
Luciano Coelho17d72652009-11-23 23:22:15 +0200900 return NOTIFY_OK;
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300901}
902
903static struct notifier_block wl1271_dev_notifier = {
904 .notifier_call = wl1271_dev_notify,
905};
906
907
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300908static int wl1271_op_start(struct ieee80211_hw *hw)
909{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200910 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
911
912 /*
913 * We have to delay the booting of the hardware because
914 * we need to know the local MAC address before downloading and
915 * initializing the firmware. The MAC address cannot be changed
916 * after boot, and without the proper MAC address, the firmware
917 * will not function properly.
918 *
919 * The MAC address is first known when the corresponding interface
920 * is added. That is where we will initialize the hardware.
921 */
922
923 return 0;
924}
925
926static void wl1271_op_stop(struct ieee80211_hw *hw)
927{
928 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
929}
930
931static int wl1271_op_add_interface(struct ieee80211_hw *hw,
932 struct ieee80211_vif *vif)
933{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200935 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936 int ret = 0;
937
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200938 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
939 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
941 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200942 if (wl->vif) {
943 ret = -EBUSY;
944 goto out;
945 }
946
947 wl->vif = vif;
948
949 switch (vif->type) {
950 case NL80211_IFTYPE_STATION:
951 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200952 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200953 break;
954 case NL80211_IFTYPE_ADHOC:
955 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200956 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200957 break;
958 default:
959 ret = -EOPNOTSUPP;
960 goto out;
961 }
962
963 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300964
965 if (wl->state != WL1271_STATE_OFF) {
966 wl1271_error("cannot start because not in off state: %d",
967 wl->state);
968 ret = -EBUSY;
969 goto out;
970 }
971
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200972 while (retries) {
973 retries--;
974 ret = wl1271_chip_wakeup(wl);
975 if (ret < 0)
976 goto power_off;
977
978 ret = wl1271_boot(wl);
979 if (ret < 0)
980 goto power_off;
981
982 ret = wl1271_hw_init(wl);
983 if (ret < 0)
984 goto irq_disable;
985
986 wl->state = WL1271_STATE_ON;
987 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988 goto out;
989
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200990irq_disable:
991 wl1271_disable_interrupts(wl);
992 mutex_unlock(&wl->mutex);
993 /* Unlocking the mutex in the middle of handling is
994 inherently unsafe. In this case we deem it safe to do,
995 because we need to let any possibly pending IRQ out of
996 the system (and while we are WL1271_STATE_OFF the IRQ
997 work function will not do anything.) Also, any other
998 possible concurrent operations will fail due to the
999 current state, hence the wl1271 struct should be safe. */
1000 cancel_work_sync(&wl->irq_work);
1001 mutex_lock(&wl->mutex);
1002power_off:
1003 wl1271_power_off(wl);
1004 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001006 wl1271_error("firmware boot failed despite %d retries",
1007 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001008out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009 mutex_unlock(&wl->mutex);
1010
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001011 if (!ret) {
1012 list_add(&wl->list, &wl_list);
1013 register_inetaddr_notifier(&wl1271_dev_notifier);
1014 }
1015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 return ret;
1017}
1018
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001019static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1020 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001021{
1022 struct wl1271 *wl = hw->priv;
1023 int i;
1024
Juuso Oikarinen2ea9fb32010-03-18 12:26:45 +02001025 unregister_inetaddr_notifier(&wl1271_dev_notifier);
1026
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001027 mutex_lock(&wl->mutex);
1028 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001030 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001032 list_del(&wl->list);
1033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 WARN_ON(wl->state != WL1271_STATE_ON);
1035
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001036 if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 mutex_unlock(&wl->mutex);
1038 ieee80211_scan_completed(wl->hw, true);
1039 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 }
1041
1042 wl->state = WL1271_STATE_OFF;
1043
1044 wl1271_disable_interrupts(wl);
1045
1046 mutex_unlock(&wl->mutex);
1047
1048 cancel_work_sync(&wl->irq_work);
1049 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050
1051 mutex_lock(&wl->mutex);
1052
1053 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001054 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 wl1271_power_off(wl);
1056
1057 memset(wl->bssid, 0, ETH_ALEN);
1058 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1059 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001061 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001062 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063
1064 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001065 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1067 wl->tx_blocks_available = 0;
1068 wl->tx_results_count = 0;
1069 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001070 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001071 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 wl->time_offset = 0;
1073 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001074 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
1075 wl->sta_rate_set = 0;
1076 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001077 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001078 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001079
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 for (i = 0; i < NUM_TX_QUEUES; i++)
1081 wl->tx_blocks_freed[i] = 0;
1082
1083 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001084
1085 kfree(wl->fw_status);
1086 wl->fw_status = NULL;
1087 kfree(wl->tx_res_if);
1088 wl->tx_res_if = NULL;
1089 kfree(wl->target_mem_map);
1090 wl->target_mem_map = NULL;
1091
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 mutex_unlock(&wl->mutex);
1093}
1094
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001095static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1096{
1097 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1098 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1099
1100 /* combine requested filters with current filter config */
1101 filters = wl->filters | filters;
1102
1103 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1104
1105 if (filters & FIF_PROMISC_IN_BSS) {
1106 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1107 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1108 wl->rx_config |= CFG_BSSID_FILTER_EN;
1109 }
1110 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1111 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1112 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1113 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1114 }
1115 if (filters & FIF_OTHER_BSS) {
1116 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1117 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1118 }
1119 if (filters & FIF_CONTROL) {
1120 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1121 wl->rx_filter |= CFG_RX_CTL_EN;
1122 }
1123 if (filters & FIF_FCSFAIL) {
1124 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1125 wl->rx_filter |= CFG_RX_FCS_ERROR;
1126 }
1127}
1128
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001129static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001130{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001131 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001132 /* we need to use a dummy BSSID for now */
1133 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1134 0xad, 0xbe, 0xef };
1135
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001136 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1137
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001138 /* pass through frames from all BSS */
1139 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1140
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001141 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001142 if (ret < 0)
1143 goto out;
1144
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001145 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001146
1147out:
1148 return ret;
1149}
1150
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001151static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001152{
1153 int ret;
1154
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001155 /*
1156 * One of the side effects of the JOIN command is that is clears
1157 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1158 * to a WPA/WPA2 access point will therefore kill the data-path.
1159 * Currently there is no supported scenario for JOIN during
1160 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1161 * must be handled somehow.
1162 *
1163 */
1164 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1165 wl1271_info("JOIN while associated.");
1166
1167 if (set_assoc)
1168 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1169
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001170 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1171 if (ret < 0)
1172 goto out;
1173
1174 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1175
1176 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1177 goto out;
1178
1179 /*
1180 * The join command disable the keep-alive mode, shut down its process,
1181 * and also clear the template config, so we need to reset it all after
1182 * the join. The acx_aid starts the keep-alive process, and the order
1183 * of the commands below is relevant.
1184 */
1185 ret = wl1271_acx_keep_alive_mode(wl, true);
1186 if (ret < 0)
1187 goto out;
1188
1189 ret = wl1271_acx_aid(wl, wl->aid);
1190 if (ret < 0)
1191 goto out;
1192
1193 ret = wl1271_cmd_build_klv_null_data(wl);
1194 if (ret < 0)
1195 goto out;
1196
1197 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1198 ACX_KEEP_ALIVE_TPL_VALID);
1199 if (ret < 0)
1200 goto out;
1201
1202out:
1203 return ret;
1204}
1205
1206static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001207{
1208 int ret;
1209
1210 /* to stop listening to a channel, we disconnect */
1211 ret = wl1271_cmd_disconnect(wl);
1212 if (ret < 0)
1213 goto out;
1214
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001215 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001216 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001217
1218 /* stop filterting packets based on bssid */
1219 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001220
1221out:
1222 return ret;
1223}
1224
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001225static void wl1271_set_band_rate(struct wl1271 *wl)
1226{
1227 if (wl->band == IEEE80211_BAND_2GHZ)
1228 wl->basic_rate_set = wl->conf.tx.basic_rate;
1229 else
1230 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1231}
1232
1233static u32 wl1271_min_rate_get(struct wl1271 *wl)
1234{
1235 int i;
1236 u32 rate = 0;
1237
1238 if (!wl->basic_rate_set) {
1239 WARN_ON(1);
1240 wl->basic_rate_set = wl->conf.tx.basic_rate;
1241 }
1242
1243 for (i = 0; !rate; i++) {
1244 if ((wl->basic_rate_set >> i) & 0x1)
1245 rate = 1 << i;
1246 }
1247
1248 return rate;
1249}
1250
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001251static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1252{
1253 int ret;
1254
1255 if (idle) {
1256 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1257 ret = wl1271_unjoin(wl);
1258 if (ret < 0)
1259 goto out;
1260 }
1261 wl->rate_set = wl1271_min_rate_get(wl);
1262 wl->sta_rate_set = 0;
1263 ret = wl1271_acx_rate_policies(wl);
1264 if (ret < 0)
1265 goto out;
1266 ret = wl1271_acx_keep_alive_config(
1267 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1268 ACX_KEEP_ALIVE_TPL_INVALID);
1269 if (ret < 0)
1270 goto out;
1271 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1272 } else {
1273 /* increment the session counter */
1274 wl->session_counter++;
1275 if (wl->session_counter >= SESSION_COUNTER_MAX)
1276 wl->session_counter = 0;
1277 ret = wl1271_dummy_join(wl);
1278 if (ret < 0)
1279 goto out;
1280 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1281 }
1282
1283out:
1284 return ret;
1285}
1286
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001287static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1288{
1289 struct wl1271 *wl = hw->priv;
1290 struct ieee80211_conf *conf = &hw->conf;
1291 int channel, ret = 0;
1292
1293 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1294
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001295 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001296 channel,
1297 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001298 conf->power_level,
1299 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001301 /*
1302 * mac80211 will go to idle nearly immediately after transmitting some
1303 * frames, such as the deauth. To make sure those frames reach the air,
1304 * wait here until the TX queue is fully flushed.
1305 */
1306 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1307 (conf->flags & IEEE80211_CONF_IDLE))
1308 wl1271_tx_flush(wl);
1309
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 mutex_lock(&wl->mutex);
1311
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001312 if (unlikely(wl->state == WL1271_STATE_OFF))
1313 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001314
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 ret = wl1271_ps_elp_wakeup(wl, false);
1316 if (ret < 0)
1317 goto out;
1318
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001319 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001320 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1321 ((wl->band != conf->channel->band) ||
1322 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001323 wl->band = conf->channel->band;
1324 wl->channel = channel;
1325
1326 /*
1327 * FIXME: the mac80211 should really provide a fixed rate
1328 * to use here. for now, just use the smallest possible rate
1329 * for the band as a fixed rate for association frames and
1330 * other control messages.
1331 */
1332 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1333 wl1271_set_band_rate(wl);
1334
1335 wl->basic_rate = wl1271_min_rate_get(wl);
1336 ret = wl1271_acx_rate_policies(wl);
1337 if (ret < 0)
1338 wl1271_warning("rate policy for update channel "
1339 "failed %d", ret);
1340
1341 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001342 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001343 if (ret < 0)
1344 wl1271_warning("cmd join to update channel "
1345 "failed %d", ret);
1346 }
1347 }
1348
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001349 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001350 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1351 if (ret < 0)
1352 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 }
1354
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001355 if (conf->flags & IEEE80211_CONF_PS &&
1356 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1357 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358
1359 /*
1360 * We enter PSM only if we're already associated.
1361 * If we're not, we'll enter it when joining an SSID,
1362 * through the bss_info_changed() hook.
1363 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001364 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001365 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001366 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1367 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001368 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001370 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001371 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001373 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001375 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001376 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1377 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378 }
1379
1380 if (conf->power_level != wl->power_level) {
1381 ret = wl1271_acx_tx_power(wl, conf->power_level);
1382 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001383 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
1385 wl->power_level = conf->power_level;
1386 }
1387
1388out_sleep:
1389 wl1271_ps_elp_sleep(wl);
1390
1391out:
1392 mutex_unlock(&wl->mutex);
1393
1394 return ret;
1395}
1396
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001397struct wl1271_filter_params {
1398 bool enabled;
1399 int mc_list_length;
1400 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1401};
1402
Jiri Pirko22bedad32010-04-01 21:22:57 +00001403static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1404 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001405{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001406 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001407 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001408 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001409
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001410 if (unlikely(wl->state == WL1271_STATE_OFF))
1411 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001412
Juuso Oikarinen74441132009-10-13 12:47:53 +03001413 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001414 if (!fp) {
1415 wl1271_error("Out of memory setting filters.");
1416 return 0;
1417 }
1418
1419 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001420 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001421 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1422 fp->enabled = false;
1423 } else {
1424 fp->enabled = true;
1425 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001426 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001427 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001428 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001429 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001430 }
1431
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001432 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001433}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001434
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001435#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1436 FIF_ALLMULTI | \
1437 FIF_FCSFAIL | \
1438 FIF_BCN_PRBRESP_PROMISC | \
1439 FIF_CONTROL | \
1440 FIF_OTHER_BSS)
1441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1443 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001444 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001445{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001446 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001447 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001448 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449
1450 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1451
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001452 mutex_lock(&wl->mutex);
1453
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001454 *total &= WL1271_SUPPORTED_FILTERS;
1455 changed &= WL1271_SUPPORTED_FILTERS;
1456
1457 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001458 goto out;
1459
1460 ret = wl1271_ps_elp_wakeup(wl, false);
1461 if (ret < 0)
1462 goto out;
1463
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001465 if (*total & FIF_ALLMULTI)
1466 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1467 else if (fp)
1468 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1469 fp->mc_list,
1470 fp->mc_list_length);
1471 if (ret < 0)
1472 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001474 /* determine, whether supported filter values have changed */
1475 if (changed == 0)
1476 goto out_sleep;
1477
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001478 /* configure filters */
1479 wl->filters = *total;
1480 wl1271_configure_filters(wl, 0);
1481
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001482 /* apply configured filters */
1483 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1484 if (ret < 0)
1485 goto out_sleep;
1486
1487out_sleep:
1488 wl1271_ps_elp_sleep(wl);
1489
1490out:
1491 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001492 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493}
1494
1495static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1496 struct ieee80211_vif *vif,
1497 struct ieee80211_sta *sta,
1498 struct ieee80211_key_conf *key_conf)
1499{
1500 struct wl1271 *wl = hw->priv;
1501 const u8 *addr;
1502 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001503 u32 tx_seq_32 = 0;
1504 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505 u8 key_type;
1506
1507 static const u8 bcast_addr[ETH_ALEN] =
1508 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1509
1510 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1511
1512 addr = sta ? sta->addr : bcast_addr;
1513
1514 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1515 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1516 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1517 key_conf->alg, key_conf->keyidx,
1518 key_conf->keylen, key_conf->flags);
1519 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1520
1521 if (is_zero_ether_addr(addr)) {
1522 /* We dont support TX only encryption */
1523 ret = -EOPNOTSUPP;
1524 goto out;
1525 }
1526
1527 mutex_lock(&wl->mutex);
1528
1529 ret = wl1271_ps_elp_wakeup(wl, false);
1530 if (ret < 0)
1531 goto out_unlock;
1532
1533 switch (key_conf->alg) {
1534 case ALG_WEP:
1535 key_type = KEY_WEP;
1536
1537 key_conf->hw_key_idx = key_conf->keyidx;
1538 break;
1539 case ALG_TKIP:
1540 key_type = KEY_TKIP;
1541
1542 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001543 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1544 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545 break;
1546 case ALG_CCMP:
1547 key_type = KEY_AES;
1548
1549 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001550 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1551 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 break;
1553 default:
1554 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1555
1556 ret = -EOPNOTSUPP;
1557 goto out_sleep;
1558 }
1559
1560 switch (cmd) {
1561 case SET_KEY:
1562 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1563 key_conf->keyidx, key_type,
1564 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001565 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 if (ret < 0) {
1567 wl1271_error("Could not add or replace key");
1568 goto out_sleep;
1569 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001570
1571 /* the default WEP key needs to be configured at least once */
1572 if (key_type == KEY_WEP) {
1573 ret = wl1271_cmd_set_default_wep_key(wl,
1574 wl->default_key);
1575 if (ret < 0)
1576 goto out_sleep;
1577 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 break;
1579
1580 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001581 /* The wl1271 does not allow to remove unicast keys - they
1582 will be cleared automatically on next CMD_JOIN. Ignore the
1583 request silently, as we dont want the mac80211 to emit
1584 an error message. */
1585 if (!is_broadcast_ether_addr(addr))
1586 break;
1587
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1589 key_conf->keyidx, key_type,
1590 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001591 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 if (ret < 0) {
1593 wl1271_error("Could not remove key");
1594 goto out_sleep;
1595 }
1596 break;
1597
1598 default:
1599 wl1271_error("Unsupported key cmd 0x%x", cmd);
1600 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601 break;
1602 }
1603
1604out_sleep:
1605 wl1271_ps_elp_sleep(wl);
1606
1607out_unlock:
1608 mutex_unlock(&wl->mutex);
1609
1610out:
1611 return ret;
1612}
1613
1614static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001615 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001616 struct cfg80211_scan_request *req)
1617{
1618 struct wl1271 *wl = hw->priv;
1619 int ret;
1620 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001621 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001622
1623 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1624
1625 if (req->n_ssids) {
1626 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001627 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001628 }
1629
1630 mutex_lock(&wl->mutex);
1631
1632 ret = wl1271_ps_elp_wakeup(wl, false);
1633 if (ret < 0)
1634 goto out;
1635
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001636 if (wl1271_11a_enabled())
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001637 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1638 1, 0, WL1271_SCAN_BAND_DUAL, 3);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001639 else
Juuso Oikarinen4fb26fa2010-05-24 11:18:20 +03001640 ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
1641 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001642
1643 wl1271_ps_elp_sleep(wl);
1644
1645out:
1646 mutex_unlock(&wl->mutex);
1647
1648 return ret;
1649}
1650
1651static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1652{
1653 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001654 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655
1656 mutex_lock(&wl->mutex);
1657
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001658 if (unlikely(wl->state == WL1271_STATE_OFF))
1659 goto out;
1660
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661 ret = wl1271_ps_elp_wakeup(wl, false);
1662 if (ret < 0)
1663 goto out;
1664
1665 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1666 if (ret < 0)
1667 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1668
1669 wl1271_ps_elp_sleep(wl);
1670
1671out:
1672 mutex_unlock(&wl->mutex);
1673
1674 return ret;
1675}
1676
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001677static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1678{
1679 u8 *ptr = beacon->data +
1680 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1681
1682 /* find the location of the ssid in the beacon */
1683 while (ptr < beacon->data + beacon->len) {
1684 if (ptr[0] == WLAN_EID_SSID) {
1685 wl->ssid_len = ptr[1];
1686 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1687 return;
1688 }
1689 ptr += ptr[1];
1690 }
1691 wl1271_error("ad-hoc beacon template has no SSID!\n");
1692}
1693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001694static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1695 struct ieee80211_vif *vif,
1696 struct ieee80211_bss_conf *bss_conf,
1697 u32 changed)
1698{
1699 enum wl1271_cmd_ps_mode mode;
1700 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001701 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001702 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001703 int ret;
1704
1705 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1706
1707 mutex_lock(&wl->mutex);
1708
1709 ret = wl1271_ps_elp_wakeup(wl, false);
1710 if (ret < 0)
1711 goto out;
1712
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001713 if ((changed && BSS_CHANGED_BEACON_INT) &&
1714 (wl->bss_type == BSS_TYPE_IBSS)) {
1715 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1716 bss_conf->beacon_int);
1717
1718 wl->beacon_int = bss_conf->beacon_int;
1719 do_join = true;
1720 }
1721
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001722 if ((changed && BSS_CHANGED_BEACON) &&
1723 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001724 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1725
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001726 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1727
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001728 if (beacon) {
1729 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001730
1731 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001732 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1733 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001734 beacon->len, 0,
1735 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001736
1737 if (ret < 0) {
1738 dev_kfree_skb(beacon);
1739 goto out_sleep;
1740 }
1741
1742 hdr = (struct ieee80211_hdr *) beacon->data;
1743 hdr->frame_control = cpu_to_le16(
1744 IEEE80211_FTYPE_MGMT |
1745 IEEE80211_STYPE_PROBE_RESP);
1746
1747 ret = wl1271_cmd_template_set(wl,
1748 CMD_TEMPL_PROBE_RESPONSE,
1749 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001750 beacon->len, 0,
1751 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001752 dev_kfree_skb(beacon);
1753 if (ret < 0)
1754 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001755
1756 /* Need to update the SSID (for filtering etc) */
1757 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001758 }
1759 }
1760
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001761 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1762 (wl->bss_type == BSS_TYPE_IBSS)) {
1763 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1764 bss_conf->enable_beacon ? "enabled" : "disabled");
1765
1766 if (bss_conf->enable_beacon)
1767 wl->set_bss_type = BSS_TYPE_IBSS;
1768 else
1769 wl->set_bss_type = BSS_TYPE_STA_BSS;
1770 do_join = true;
1771 }
1772
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001773 if (changed & BSS_CHANGED_CQM) {
1774 bool enable = false;
1775 if (bss_conf->cqm_rssi_thold)
1776 enable = true;
1777 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1778 bss_conf->cqm_rssi_thold,
1779 bss_conf->cqm_rssi_hyst);
1780 if (ret < 0)
1781 goto out;
1782 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1783 }
1784
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001785 if ((changed & BSS_CHANGED_BSSID) &&
1786 /*
1787 * Now we know the correct bssid, so we send a new join command
1788 * and enable the BSSID filter
1789 */
1790 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001791 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001792
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001793 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001794 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001795 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001796
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001797 ret = wl1271_build_qos_null_data(wl);
1798 if (ret < 0)
1799 goto out_sleep;
1800
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001801 /* filter out all packets not from this BSSID */
1802 wl1271_configure_filters(wl, 0);
1803
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001804 /* Need to update the BSSID (for filtering etc) */
1805 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001806 }
1807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 if (changed & BSS_CHANGED_ASSOC) {
1809 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001810 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001812 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001814 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001815 * use basic rates from AP, and determine lowest rate
1816 * to use with control frames.
1817 */
1818 rates = bss_conf->basic_rates;
1819 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1820 rates);
1821 wl->basic_rate = wl1271_min_rate_get(wl);
1822 ret = wl1271_acx_rate_policies(wl);
1823 if (ret < 0)
1824 goto out_sleep;
1825
1826 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001827 * with wl1271, we don't need to update the
1828 * beacon_int and dtim_period, because the firmware
1829 * updates it by itself when the first beacon is
1830 * received after a join.
1831 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1833 if (ret < 0)
1834 goto out_sleep;
1835
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001836 /*
1837 * The SSID is intentionally set to NULL here - the
1838 * firmware will set the probe request with a
1839 * broadcast SSID regardless of what we set in the
1840 * template.
1841 */
1842 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1843 NULL, 0, wl->band);
1844
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001845 /* enable the connection monitoring feature */
1846 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 if (ret < 0)
1848 goto out_sleep;
1849
1850 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001851 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1852 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001854 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855 if (ret < 0)
1856 goto out_sleep;
1857 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001858 } else {
1859 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001860 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001861 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001862
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001863 /* revert back to minimum rates for the current band */
1864 wl1271_set_band_rate(wl);
1865 wl->basic_rate = wl1271_min_rate_get(wl);
1866 ret = wl1271_acx_rate_policies(wl);
1867 if (ret < 0)
1868 goto out_sleep;
1869
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001870 /* disable connection monitor features */
1871 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001872
1873 /* Disable the keep-alive feature */
1874 ret = wl1271_acx_keep_alive_mode(wl, false);
1875
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001876 if (ret < 0)
1877 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001878 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001879
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001882 if (changed & BSS_CHANGED_ERP_SLOT) {
1883 if (bss_conf->use_short_slot)
1884 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1885 else
1886 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1887 if (ret < 0) {
1888 wl1271_warning("Set slot time failed %d", ret);
1889 goto out_sleep;
1890 }
1891 }
1892
1893 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1894 if (bss_conf->use_short_preamble)
1895 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1896 else
1897 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1898 }
1899
1900 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1901 if (bss_conf->use_cts_prot)
1902 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1903 else
1904 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1905 if (ret < 0) {
1906 wl1271_warning("Set ctsprotect failed %d", ret);
1907 goto out_sleep;
1908 }
1909 }
1910
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001911 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001912 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001913 if (ret < 0) {
1914 wl1271_warning("cmd join failed %d", ret);
1915 goto out_sleep;
1916 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001917 }
1918
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001919out_sleep:
1920 wl1271_ps_elp_sleep(wl);
1921
1922out:
1923 mutex_unlock(&wl->mutex);
1924}
1925
Kalle Valoc6999d82010-02-18 13:25:41 +02001926static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1927 const struct ieee80211_tx_queue_params *params)
1928{
1929 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001930 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001931 int ret;
1932
1933 mutex_lock(&wl->mutex);
1934
1935 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1936
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001937 ret = wl1271_ps_elp_wakeup(wl, false);
1938 if (ret < 0)
1939 goto out;
1940
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001941 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001942 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1943 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001944 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001945 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001946 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001947
Kalle Valo4695dc92010-03-18 12:26:38 +02001948 if (params->uapsd)
1949 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1950 else
1951 ps_scheme = CONF_PS_SCHEME_LEGACY;
1952
Kalle Valoc6999d82010-02-18 13:25:41 +02001953 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1954 CONF_CHANNEL_TYPE_EDCF,
1955 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001956 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001957 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001958 goto out_sleep;
1959
1960out_sleep:
1961 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001962
1963out:
1964 mutex_unlock(&wl->mutex);
1965
1966 return ret;
1967}
1968
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001969static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1970{
1971
1972 struct wl1271 *wl = hw->priv;
1973 u64 mactime = ULLONG_MAX;
1974 int ret;
1975
1976 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1977
1978 mutex_lock(&wl->mutex);
1979
1980 ret = wl1271_ps_elp_wakeup(wl, false);
1981 if (ret < 0)
1982 goto out;
1983
1984 ret = wl1271_acx_tsf_info(wl, &mactime);
1985 if (ret < 0)
1986 goto out_sleep;
1987
1988out_sleep:
1989 wl1271_ps_elp_sleep(wl);
1990
1991out:
1992 mutex_unlock(&wl->mutex);
1993 return mactime;
1994}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995
1996/* can't be const, mac80211 writes to this */
1997static struct ieee80211_rate wl1271_rates[] = {
1998 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001999 .hw_value = CONF_HW_BIT_RATE_1MBPS,
2000 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002002 .hw_value = CONF_HW_BIT_RATE_2MBPS,
2003 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002004 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2005 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002006 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
2007 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2009 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002010 .hw_value = CONF_HW_BIT_RATE_11MBPS,
2011 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
2013 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002014 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2015 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002016 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002017 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2018 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002019 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002020 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2021 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002023 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2024 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002026 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2027 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002028 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002029 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2030 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002032 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2033 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002034 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03002035 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2036 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037};
2038
2039/* can't be const, mac80211 writes to this */
2040static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02002041 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
2042 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
2043 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
2044 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
2045 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
2046 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
2047 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
2048 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
2049 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
2050 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
2051 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
2052 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
2053 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054};
2055
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002056/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002057static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002058 /* MCS rates are used only with 11n */
2059 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2060 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2061 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2062 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2063 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2064 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2065 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2066 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2067
2068 11, /* CONF_HW_RXTX_RATE_54 */
2069 10, /* CONF_HW_RXTX_RATE_48 */
2070 9, /* CONF_HW_RXTX_RATE_36 */
2071 8, /* CONF_HW_RXTX_RATE_24 */
2072
2073 /* TI-specific rate */
2074 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2075
2076 7, /* CONF_HW_RXTX_RATE_18 */
2077 6, /* CONF_HW_RXTX_RATE_12 */
2078 3, /* CONF_HW_RXTX_RATE_11 */
2079 5, /* CONF_HW_RXTX_RATE_9 */
2080 4, /* CONF_HW_RXTX_RATE_6 */
2081 2, /* CONF_HW_RXTX_RATE_5_5 */
2082 1, /* CONF_HW_RXTX_RATE_2 */
2083 0 /* CONF_HW_RXTX_RATE_1 */
2084};
2085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086/* can't be const, mac80211 writes to this */
2087static struct ieee80211_supported_band wl1271_band_2ghz = {
2088 .channels = wl1271_channels,
2089 .n_channels = ARRAY_SIZE(wl1271_channels),
2090 .bitrates = wl1271_rates,
2091 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2092};
2093
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002094/* 5 GHz data rates for WL1273 */
2095static struct ieee80211_rate wl1271_rates_5ghz[] = {
2096 { .bitrate = 60,
2097 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2098 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2099 { .bitrate = 90,
2100 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2101 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2102 { .bitrate = 120,
2103 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2104 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2105 { .bitrate = 180,
2106 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2107 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2108 { .bitrate = 240,
2109 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2110 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2111 { .bitrate = 360,
2112 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2113 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2114 { .bitrate = 480,
2115 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2116 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2117 { .bitrate = 540,
2118 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2119 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2120};
2121
2122/* 5 GHz band channels for WL1273 */
2123static struct ieee80211_channel wl1271_channels_5ghz[] = {
2124 { .hw_value = 183, .center_freq = 4915},
2125 { .hw_value = 184, .center_freq = 4920},
2126 { .hw_value = 185, .center_freq = 4925},
2127 { .hw_value = 187, .center_freq = 4935},
2128 { .hw_value = 188, .center_freq = 4940},
2129 { .hw_value = 189, .center_freq = 4945},
2130 { .hw_value = 192, .center_freq = 4960},
2131 { .hw_value = 196, .center_freq = 4980},
2132 { .hw_value = 7, .center_freq = 5035},
2133 { .hw_value = 8, .center_freq = 5040},
2134 { .hw_value = 9, .center_freq = 5045},
2135 { .hw_value = 11, .center_freq = 5055},
2136 { .hw_value = 12, .center_freq = 5060},
2137 { .hw_value = 16, .center_freq = 5080},
2138 { .hw_value = 34, .center_freq = 5170},
2139 { .hw_value = 36, .center_freq = 5180},
2140 { .hw_value = 38, .center_freq = 5190},
2141 { .hw_value = 40, .center_freq = 5200},
2142 { .hw_value = 42, .center_freq = 5210},
2143 { .hw_value = 44, .center_freq = 5220},
2144 { .hw_value = 46, .center_freq = 5230},
2145 { .hw_value = 48, .center_freq = 5240},
2146 { .hw_value = 52, .center_freq = 5260},
2147 { .hw_value = 56, .center_freq = 5280},
2148 { .hw_value = 60, .center_freq = 5300},
2149 { .hw_value = 64, .center_freq = 5320},
2150 { .hw_value = 100, .center_freq = 5500},
2151 { .hw_value = 104, .center_freq = 5520},
2152 { .hw_value = 108, .center_freq = 5540},
2153 { .hw_value = 112, .center_freq = 5560},
2154 { .hw_value = 116, .center_freq = 5580},
2155 { .hw_value = 120, .center_freq = 5600},
2156 { .hw_value = 124, .center_freq = 5620},
2157 { .hw_value = 128, .center_freq = 5640},
2158 { .hw_value = 132, .center_freq = 5660},
2159 { .hw_value = 136, .center_freq = 5680},
2160 { .hw_value = 140, .center_freq = 5700},
2161 { .hw_value = 149, .center_freq = 5745},
2162 { .hw_value = 153, .center_freq = 5765},
2163 { .hw_value = 157, .center_freq = 5785},
2164 { .hw_value = 161, .center_freq = 5805},
2165 { .hw_value = 165, .center_freq = 5825},
2166};
2167
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002168/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002169static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002170 /* MCS rates are used only with 11n */
2171 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2172 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2173 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2174 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2175 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2176 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2177 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2178 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2179
2180 7, /* CONF_HW_RXTX_RATE_54 */
2181 6, /* CONF_HW_RXTX_RATE_48 */
2182 5, /* CONF_HW_RXTX_RATE_36 */
2183 4, /* CONF_HW_RXTX_RATE_24 */
2184
2185 /* TI-specific rate */
2186 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2187
2188 3, /* CONF_HW_RXTX_RATE_18 */
2189 2, /* CONF_HW_RXTX_RATE_12 */
2190 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2191 1, /* CONF_HW_RXTX_RATE_9 */
2192 0, /* CONF_HW_RXTX_RATE_6 */
2193 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2194 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2195 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2196};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002197
2198static struct ieee80211_supported_band wl1271_band_5ghz = {
2199 .channels = wl1271_channels_5ghz,
2200 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2201 .bitrates = wl1271_rates_5ghz,
2202 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2203};
2204
Tobias Klausera0ea9492010-05-20 10:38:11 +02002205static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002206 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2207 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2208};
2209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210static const struct ieee80211_ops wl1271_ops = {
2211 .start = wl1271_op_start,
2212 .stop = wl1271_op_stop,
2213 .add_interface = wl1271_op_add_interface,
2214 .remove_interface = wl1271_op_remove_interface,
2215 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002216 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 .configure_filter = wl1271_op_configure_filter,
2218 .tx = wl1271_op_tx,
2219 .set_key = wl1271_op_set_key,
2220 .hw_scan = wl1271_op_hw_scan,
2221 .bss_info_changed = wl1271_op_bss_info_changed,
2222 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002223 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002224 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002225 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226};
2227
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002228
2229u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2230{
2231 u8 idx;
2232
2233 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2234
2235 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2236 wl1271_error("Illegal RX rate from HW: %d", rate);
2237 return 0;
2238 }
2239
2240 idx = wl1271_band_rate_to_idx[wl->band][rate];
2241 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2242 wl1271_error("Unsupported RX rate from HW: %d", rate);
2243 return 0;
2244 }
2245
2246 return idx;
2247}
2248
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002249static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2250 struct device_attribute *attr,
2251 char *buf)
2252{
2253 struct wl1271 *wl = dev_get_drvdata(dev);
2254 ssize_t len;
2255
2256 /* FIXME: what's the maximum length of buf? page size?*/
2257 len = 500;
2258
2259 mutex_lock(&wl->mutex);
2260 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2261 wl->sg_enabled);
2262 mutex_unlock(&wl->mutex);
2263
2264 return len;
2265
2266}
2267
2268static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2269 struct device_attribute *attr,
2270 const char *buf, size_t count)
2271{
2272 struct wl1271 *wl = dev_get_drvdata(dev);
2273 unsigned long res;
2274 int ret;
2275
2276 ret = strict_strtoul(buf, 10, &res);
2277
2278 if (ret < 0) {
2279 wl1271_warning("incorrect value written to bt_coex_mode");
2280 return count;
2281 }
2282
2283 mutex_lock(&wl->mutex);
2284
2285 res = !!res;
2286
2287 if (res == wl->sg_enabled)
2288 goto out;
2289
2290 wl->sg_enabled = res;
2291
2292 if (wl->state == WL1271_STATE_OFF)
2293 goto out;
2294
2295 ret = wl1271_ps_elp_wakeup(wl, false);
2296 if (ret < 0)
2297 goto out;
2298
2299 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2300 wl1271_ps_elp_sleep(wl);
2301
2302 out:
2303 mutex_unlock(&wl->mutex);
2304 return count;
2305}
2306
2307static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2308 wl1271_sysfs_show_bt_coex_state,
2309 wl1271_sysfs_store_bt_coex_state);
2310
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002311static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2312 struct device_attribute *attr,
2313 char *buf)
2314{
2315 struct wl1271 *wl = dev_get_drvdata(dev);
2316 ssize_t len;
2317
2318 /* FIXME: what's the maximum length of buf? page size?*/
2319 len = 500;
2320
2321 mutex_lock(&wl->mutex);
2322 if (wl->hw_pg_ver >= 0)
2323 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2324 else
2325 len = snprintf(buf, len, "n/a\n");
2326 mutex_unlock(&wl->mutex);
2327
2328 return len;
2329}
2330
2331static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2332 wl1271_sysfs_show_hw_pg_ver, NULL);
2333
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002334int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335{
2336 int ret;
2337
2338 if (wl->mac80211_registered)
2339 return 0;
2340
2341 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2342
2343 ret = ieee80211_register_hw(wl->hw);
2344 if (ret < 0) {
2345 wl1271_error("unable to register mac80211 hw: %d", ret);
2346 return ret;
2347 }
2348
2349 wl->mac80211_registered = true;
2350
2351 wl1271_notice("loaded");
2352
2353 return 0;
2354}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002355EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002357void wl1271_unregister_hw(struct wl1271 *wl)
2358{
2359 ieee80211_unregister_hw(wl->hw);
2360 wl->mac80211_registered = false;
2361
2362}
2363EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2364
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002365int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002367 /* The tx descriptor buffer and the TKIP space. */
2368 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2369 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370
2371 /* unit us */
2372 /* FIXME: find a proper value */
2373 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002374 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375
2376 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002377 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002378 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002379 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002380 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002381 IEEE80211_HW_CONNECTION_MONITOR |
2382 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002383
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002384 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2385 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002386 wl->hw->wiphy->max_scan_ssids = 1;
2387 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2388
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002389 if (wl1271_11a_enabled())
2390 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2391
Kalle Valo12bd8942010-03-18 12:26:33 +02002392 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002393 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002394
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002395 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396
2397 return 0;
2398}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002399EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002401#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002402
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002403struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002404{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002406 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002407 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002408 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409
2410 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2411 if (!hw) {
2412 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002413 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002414 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002415 }
2416
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002417 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2418 if (!plat_dev) {
2419 wl1271_error("could not allocate platform_device");
2420 ret = -ENOMEM;
2421 goto err_plat_alloc;
2422 }
2423
2424 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002426 wl = hw->priv;
2427 memset(wl, 0, sizeof(*wl));
2428
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002429 INIT_LIST_HEAD(&wl->list);
2430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002431 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002432 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002433
2434 skb_queue_head_init(&wl->tx_queue);
2435
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002436 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002438 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440 wl->rx_counter = 0;
2441 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2442 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002443 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002445 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002446 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002447 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2448 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002449 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002450 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002451 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002452 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002453 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002454
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002455 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456 wl->tx_frames[i] = NULL;
2457
2458 spin_lock_init(&wl->wl_lock);
2459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002460 wl->state = WL1271_STATE_OFF;
2461 mutex_init(&wl->mutex);
2462
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002463 /* Apply default driver configuration. */
2464 wl1271_conf_init(wl);
2465
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002466 wl1271_debugfs_init(wl);
2467
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002468 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002469 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002470 if (ret) {
2471 wl1271_error("couldn't register platform device");
2472 goto err_hw;
2473 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002474 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002475
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002476 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002477 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002478 if (ret < 0) {
2479 wl1271_error("failed to create sysfs file bt_coex_state");
2480 goto err_platform;
2481 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002482
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002483 /* Create sysfs file to get HW PG version */
2484 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2485 if (ret < 0) {
2486 wl1271_error("failed to create sysfs file hw_pg_ver");
2487 goto err_bt_coex_state;
2488 }
2489
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002490 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002491
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002492err_bt_coex_state:
2493 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2494
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002495err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002496 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002497
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002498err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002499 wl1271_debugfs_exit(wl);
2500 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002501
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002502err_plat_alloc:
2503 ieee80211_free_hw(hw);
2504
2505err_hw_alloc:
2506
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002507 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002508}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002509EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002510
2511int wl1271_free_hw(struct wl1271 *wl)
2512{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002513 platform_device_unregister(wl->plat_dev);
2514 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002515
2516 wl1271_debugfs_exit(wl);
2517
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002518 vfree(wl->fw);
2519 wl->fw = NULL;
2520 kfree(wl->nvs);
2521 wl->nvs = NULL;
2522
2523 kfree(wl->fw_status);
2524 kfree(wl->tx_res_if);
2525
2526 ieee80211_free_hw(wl->hw);
2527
2528 return 0;
2529}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002530EXPORT_SYMBOL_GPL(wl1271_free_hw);
2531
2532MODULE_LICENSE("GPL");
2533MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2534MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");