blob: d30de58cef9069ad578b7471ba9f9db0e097f878 [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 Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030033
34#include "wl1271.h"
35#include "wl12xx_80211.h"
36#include "wl1271_reg.h"
Teemu Paasikivi7b048c52010-02-18 13:25:55 +020037#include "wl1271_io.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030038#include "wl1271_event.h"
39#include "wl1271_tx.h"
40#include "wl1271_rx.h"
41#include "wl1271_ps.h"
42#include "wl1271_init.h"
43#include "wl1271_debugfs.h"
44#include "wl1271_cmd.h"
45#include "wl1271_boot.h"
Kalle Valoc8c90872010-02-18 13:25:53 +020046#include "wl1271_testmode.h"
Luciano Coelho34dd2aa2010-07-08 17:50:06 +030047#include "wl1271_scan.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,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030058 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020059 [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,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Juuso Oikarinen84502562009-11-23 23:22:12 +0200240 .bet_max_consecutive = 10,
Juuso Oikarinenc1899552010-03-26 12:53:32 +0200241 .psm_entry_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300242 .keep_alive_interval = 55000,
243 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200245 .itrim = {
246 .enable = false,
247 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200248 },
249 .pm_config = {
250 .host_clk_settling_time = 5000,
251 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300252 },
253 .roam_trigger = {
254 /* FIXME: due to firmware bug, must use value 1 for now */
255 .trigger_pacing = 1,
256 .avg_weight_rssi_beacon = 20,
257 .avg_weight_rssi_data = 10,
258 .avg_weight_snr_beacon = 20,
259 .avg_weight_snr_data = 10
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 }
261};
262
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200263static void wl1271_device_release(struct device *dev)
264{
265
266}
267
268static struct platform_device wl1271_device = {
269 .name = "wl1271",
270 .id = -1,
271
272 /* device model insists to have a release function */
273 .dev = {
274 .release = wl1271_device_release,
275 },
276};
277
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300278static LIST_HEAD(wl_list);
279
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300280static void wl1271_conf_init(struct wl1271 *wl)
281{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300282
283 /*
284 * This function applies the default configuration to the driver. This
285 * function is invoked upon driver load (spi probe.)
286 *
287 * The configuration is stored in a run-time structure in order to
288 * facilitate for run-time adjustment of any of the parameters. Making
289 * changes to the configuration structure will apply the new values on
290 * the next interface up (wl1271_op_start.)
291 */
292
293 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300294 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300295}
296
297
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300298static int wl1271_plt_init(struct wl1271 *wl)
299{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200300 struct conf_tx_ac_category *conf_ac;
301 struct conf_tx_tid *conf_tid;
302 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300303
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200304 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200305 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200306 return ret;
307
Luciano Coelho98b5dd52009-11-23 23:22:17 +0200308 ret = wl1271_cmd_radio_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 Coelho12419cc2010-02-18 13:25:44 +0200312 ret = wl1271_init_templates_config(wl);
313 if (ret < 0)
314 return ret;
315
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300316 ret = wl1271_acx_init_mem_config(wl);
317 if (ret < 0)
318 return ret;
319
Luciano Coelho12419cc2010-02-18 13:25:44 +0200320 /* PHY layer config */
321 ret = wl1271_init_phy_config(wl);
322 if (ret < 0)
323 goto out_free_memmap;
324
325 ret = wl1271_acx_dco_itrim_params(wl);
326 if (ret < 0)
327 goto out_free_memmap;
328
329 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200330 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200331 if (ret < 0)
332 goto out_free_memmap;
333
334 /* Bluetooth WLAN coexistence */
335 ret = wl1271_init_pta(wl);
336 if (ret < 0)
337 goto out_free_memmap;
338
339 /* Energy detection */
340 ret = wl1271_init_energy_detection(wl);
341 if (ret < 0)
342 goto out_free_memmap;
343
344 /* Default fragmentation threshold */
345 ret = wl1271_acx_frag_threshold(wl);
346 if (ret < 0)
347 goto out_free_memmap;
348
349 /* Default TID configuration */
350 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
351 conf_tid = &wl->conf.tx.tid_conf[i];
352 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
353 conf_tid->channel_type,
354 conf_tid->tsid,
355 conf_tid->ps_scheme,
356 conf_tid->ack_policy,
357 conf_tid->apsd_conf[0],
358 conf_tid->apsd_conf[1]);
359 if (ret < 0)
360 goto out_free_memmap;
361 }
362
363 /* Default AC configuration */
364 for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
365 conf_ac = &wl->conf.tx.ac_conf[i];
366 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
367 conf_ac->cw_max, conf_ac->aifsn,
368 conf_ac->tx_op_limit);
369 if (ret < 0)
370 goto out_free_memmap;
371 }
372
373 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200374 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300375 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200376 goto out_free_memmap;
377
378 /* Configure for CAM power saving (ie. always active) */
379 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
380 if (ret < 0)
381 goto out_free_memmap;
382
383 /* configure PM */
384 ret = wl1271_acx_pm_config(wl);
385 if (ret < 0)
386 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300387
388 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200389
390 out_free_memmap:
391 kfree(wl->target_mem_map);
392 wl->target_mem_map = NULL;
393
394 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300395}
396
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300397static void wl1271_fw_status(struct wl1271 *wl,
398 struct wl1271_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300399{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200400 struct timespec ts;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300401 u32 total = 0;
402 int i;
403
Teemu Paasikivi09a9c2b2010-02-22 08:38:28 +0200404 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300405
406 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
407 "drv_rx_counter = %d, tx_results_counter = %d)",
408 status->intr,
409 status->fw_rx_counter,
410 status->drv_rx_counter,
411 status->tx_results_counter);
412
413 /* update number of available TX blocks */
414 for (i = 0; i < NUM_TX_QUEUES; i++) {
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300415 u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
416 wl->tx_blocks_freed[i];
417
418 wl->tx_blocks_freed[i] =
419 le32_to_cpu(status->tx_released_blks[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300420 wl->tx_blocks_available += cnt;
421 total += cnt;
422 }
423
424 /* if more blocks are available now, schedule some tx work */
425 if (total && !skb_queue_empty(&wl->tx_queue))
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300426 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300427
428 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200429 getnstimeofday(&ts);
430 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
431 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300432}
433
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200434#define WL1271_IRQ_MAX_LOOPS 10
435
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300436static void wl1271_irq_work(struct work_struct *work)
437{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300438 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300439 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200440 int loopcount = WL1271_IRQ_MAX_LOOPS;
441 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300442 struct wl1271 *wl =
443 container_of(work, struct wl1271, irq_work);
444
445 mutex_lock(&wl->mutex);
446
447 wl1271_debug(DEBUG_IRQ, "IRQ work");
448
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200449 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300450 goto out;
451
452 ret = wl1271_ps_elp_wakeup(wl, true);
453 if (ret < 0)
454 goto out;
455
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200456 spin_lock_irqsave(&wl->wl_lock, flags);
457 while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
458 clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
459 spin_unlock_irqrestore(&wl->wl_lock, flags);
460 loopcount--;
461
462 wl1271_fw_status(wl, wl->fw_status);
463 intr = le32_to_cpu(wl->fw_status->intr);
464 if (!intr) {
465 wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
Dan Carpentercdd08642010-05-08 18:25:17 +0200466 spin_lock_irqsave(&wl->wl_lock, flags);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200467 continue;
468 }
469
470 intr &= WL1271_INTR_MASK;
471
472 if (intr & WL1271_ACX_INTR_DATA) {
473 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
474
475 /* check for tx results */
476 if (wl->fw_status->tx_results_counter !=
477 (wl->tx_results_count & 0xff))
478 wl1271_tx_complete(wl);
479
480 wl1271_rx(wl, wl->fw_status);
481 }
482
483 if (intr & WL1271_ACX_INTR_EVENT_A) {
484 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
485 wl1271_event_handle(wl, 0);
486 }
487
488 if (intr & WL1271_ACX_INTR_EVENT_B) {
489 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
490 wl1271_event_handle(wl, 1);
491 }
492
493 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
494 wl1271_debug(DEBUG_IRQ,
495 "WL1271_ACX_INTR_INIT_COMPLETE");
496
497 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
498 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
499
500 spin_lock_irqsave(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300501 }
502
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200503 if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
504 ieee80211_queue_work(wl->hw, &wl->irq_work);
505 else
506 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
507 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300508
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300509 wl1271_ps_elp_sleep(wl);
510
511out:
512 mutex_unlock(&wl->mutex);
513}
514
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300515static int wl1271_fetch_firmware(struct wl1271 *wl)
516{
517 const struct firmware *fw;
518 int ret;
519
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200520 ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521
522 if (ret < 0) {
523 wl1271_error("could not get firmware: %d", ret);
524 return ret;
525 }
526
527 if (fw->size % 4) {
528 wl1271_error("firmware size is not multiple of 32 bits: %zu",
529 fw->size);
530 ret = -EILSEQ;
531 goto out;
532 }
533
534 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300535 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300536
537 if (!wl->fw) {
538 wl1271_error("could not allocate memory for the firmware");
539 ret = -ENOMEM;
540 goto out;
541 }
542
543 memcpy(wl->fw, fw->data, wl->fw_len);
544
545 ret = 0;
546
547out:
548 release_firmware(fw);
549
550 return ret;
551}
552
553static int wl1271_fetch_nvs(struct wl1271 *wl)
554{
555 const struct firmware *fw;
556 int ret;
557
Teemu Paasikivi8197b712010-02-22 08:38:23 +0200558 ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300559
560 if (ret < 0) {
561 wl1271_error("could not get nvs file: %d", ret);
562 return ret;
563 }
564
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300565 /*
566 * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
567 * configurations) can be removed when those NVS files stop floating
568 * around.
569 */
570 if (fw->size != sizeof(struct wl1271_nvs_file) &&
571 (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
572 wl1271_11a_enabled())) {
Juuso Oikarinen152ee6e2010-02-18 13:25:42 +0200573 wl1271_error("nvs size is not as expected: %zu != %zu",
574 fw->size, sizeof(struct wl1271_nvs_file));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300575 ret = -EILSEQ;
576 goto out;
577 }
578
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300579 wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300580
581 if (!wl->nvs) {
582 wl1271_error("could not allocate memory for the nvs file");
583 ret = -ENOMEM;
584 goto out;
585 }
586
Juuso Oikarinena7da74f2010-05-14 10:46:23 +0300587 memcpy(wl->nvs, fw->data, fw->size);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300588
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300589out:
590 release_firmware(fw);
591
592 return ret;
593}
594
595static void wl1271_fw_wakeup(struct wl1271 *wl)
596{
597 u32 elp_reg;
598
599 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300600 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300601}
602
603static int wl1271_setup(struct wl1271 *wl)
604{
605 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
606 if (!wl->fw_status)
607 return -ENOMEM;
608
609 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
610 if (!wl->tx_res_if) {
611 kfree(wl->fw_status);
612 return -ENOMEM;
613 }
614
615 INIT_WORK(&wl->irq_work, wl1271_irq_work);
616 INIT_WORK(&wl->tx_work, wl1271_tx_work);
617 return 0;
618}
619
620static int wl1271_chip_wakeup(struct wl1271 *wl)
621{
Juuso Oikarinen451de972009-10-12 15:08:46 +0300622 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623 int ret = 0;
624
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +0200625 msleep(WL1271_PRE_POWER_ON_SLEEP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300626 wl1271_power_on(wl);
627 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +0200628 wl1271_io_reset(wl);
629 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300630
631 /* We don't need a real memory partition here, because we only want
632 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +0300633 memset(&partition, 0, sizeof(partition));
634 partition.reg.start = REGISTERS_BASE;
635 partition.reg.size = REGISTERS_DOWN_SIZE;
636 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300637
638 /* ELP module wake up */
639 wl1271_fw_wakeup(wl);
640
641 /* whal_FwCtrl_BootSm() */
642
643 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +0200644 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300645
646 /* 1. check if chip id is valid */
647
648 switch (wl->chip.id) {
649 case CHIP_ID_1271_PG10:
650 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
651 wl->chip.id);
652
653 ret = wl1271_setup(wl);
654 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200655 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656 break;
657 case CHIP_ID_1271_PG20:
658 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
659 wl->chip.id);
660
661 ret = wl1271_setup(wl);
662 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200663 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 break;
665 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200666 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200668 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300669 }
670
671 if (wl->fw == NULL) {
672 ret = wl1271_fetch_firmware(wl);
673 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200674 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300675 }
676
677 /* No NVS from netlink, try to get it from the filesystem */
678 if (wl->nvs == NULL) {
679 ret = wl1271_fetch_nvs(wl);
680 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200681 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 }
683
684out:
685 return ret;
686}
687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688int wl1271_plt_start(struct wl1271 *wl)
689{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200690 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 int ret;
692
693 mutex_lock(&wl->mutex);
694
695 wl1271_notice("power up");
696
697 if (wl->state != WL1271_STATE_OFF) {
698 wl1271_error("cannot go into PLT state because not "
699 "in off state: %d", wl->state);
700 ret = -EBUSY;
701 goto out;
702 }
703
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200704 while (retries) {
705 retries--;
706 ret = wl1271_chip_wakeup(wl);
707 if (ret < 0)
708 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200710 ret = wl1271_boot(wl);
711 if (ret < 0)
712 goto power_off;
713
714 ret = wl1271_plt_init(wl);
715 if (ret < 0)
716 goto irq_disable;
717
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200718 wl->state = WL1271_STATE_PLT;
719 wl1271_notice("firmware booted in PLT mode (%s)",
720 wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 goto out;
722
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200723irq_disable:
724 wl1271_disable_interrupts(wl);
725 mutex_unlock(&wl->mutex);
726 /* Unlocking the mutex in the middle of handling is
727 inherently unsafe. In this case we deem it safe to do,
728 because we need to let any possibly pending IRQ out of
729 the system (and while we are WL1271_STATE_OFF the IRQ
730 work function will not do anything.) Also, any other
731 possible concurrent operations will fail due to the
732 current state, hence the wl1271 struct should be safe. */
733 cancel_work_sync(&wl->irq_work);
734 mutex_lock(&wl->mutex);
735power_off:
736 wl1271_power_off(wl);
737 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200739 wl1271_error("firmware boot in PLT mode failed despite %d retries",
740 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300741out:
742 mutex_unlock(&wl->mutex);
743
744 return ret;
745}
746
747int wl1271_plt_stop(struct wl1271 *wl)
748{
749 int ret = 0;
750
751 mutex_lock(&wl->mutex);
752
753 wl1271_notice("power down");
754
755 if (wl->state != WL1271_STATE_PLT) {
756 wl1271_error("cannot power down because not in PLT "
757 "state: %d", wl->state);
758 ret = -EBUSY;
759 goto out;
760 }
761
762 wl1271_disable_interrupts(wl);
763 wl1271_power_off(wl);
764
765 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +0300766 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767
768out:
769 mutex_unlock(&wl->mutex);
770
771 return ret;
772}
773
774
775static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
776{
777 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200778 struct ieee80211_conf *conf = &hw->conf;
779 struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
780 struct ieee80211_sta *sta = txinfo->control.sta;
781 unsigned long flags;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200783 /* peek into the rates configured in the STA entry */
784 spin_lock_irqsave(&wl->wl_lock, flags);
785 if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) {
786 wl->sta_rate_set = sta->supp_rates[conf->channel->band];
787 set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags);
788 }
789 spin_unlock_irqrestore(&wl->wl_lock, flags);
790
791 /* queue the packet */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300792 skb_queue_tail(&wl->tx_queue, skb);
793
794 /*
795 * The chip specific setup must run before the first TX packet -
796 * before that, the tx_work will not be initialized!
797 */
798
Juuso Oikarinena64b07e2009-10-08 21:56:29 +0300799 ieee80211_queue_work(wl->hw, &wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300800
801 /*
802 * The workqueue is slow to process the tx_queue and we need stop
803 * the queue here, otherwise the queue will get too long.
804 */
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200805 if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
806 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300807
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200808 spin_lock_irqsave(&wl->wl_lock, flags);
809 ieee80211_stop_queues(wl->hw);
Juuso Oikarinen71449f82009-12-11 15:41:07 +0200810 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
Juuso Oikarinen06f7bc72010-02-22 08:38:33 +0200811 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812 }
813
814 return NETDEV_TX_OK;
815}
816
817static int wl1271_op_start(struct ieee80211_hw *hw)
818{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200819 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
820
821 /*
822 * We have to delay the booting of the hardware because
823 * we need to know the local MAC address before downloading and
824 * initializing the firmware. The MAC address cannot be changed
825 * after boot, and without the proper MAC address, the firmware
826 * will not function properly.
827 *
828 * The MAC address is first known when the corresponding interface
829 * is added. That is where we will initialize the hardware.
830 */
831
832 return 0;
833}
834
835static void wl1271_op_stop(struct ieee80211_hw *hw)
836{
837 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
838}
839
840static int wl1271_op_add_interface(struct ieee80211_hw *hw,
841 struct ieee80211_vif *vif)
842{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300843 struct wl1271 *wl = hw->priv;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200844 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845 int ret = 0;
846
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200847 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
848 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849
850 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200851 if (wl->vif) {
852 ret = -EBUSY;
853 goto out;
854 }
855
856 wl->vif = vif;
857
858 switch (vif->type) {
859 case NL80211_IFTYPE_STATION:
860 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200861 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200862 break;
863 case NL80211_IFTYPE_ADHOC:
864 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200865 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200866 break;
867 default:
868 ret = -EOPNOTSUPP;
869 goto out;
870 }
871
872 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873
874 if (wl->state != WL1271_STATE_OFF) {
875 wl1271_error("cannot start because not in off state: %d",
876 wl->state);
877 ret = -EBUSY;
878 goto out;
879 }
880
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200881 while (retries) {
882 retries--;
883 ret = wl1271_chip_wakeup(wl);
884 if (ret < 0)
885 goto power_off;
886
887 ret = wl1271_boot(wl);
888 if (ret < 0)
889 goto power_off;
890
891 ret = wl1271_hw_init(wl);
892 if (ret < 0)
893 goto irq_disable;
894
895 wl->state = WL1271_STATE_ON;
896 wl1271_info("firmware booted (%s)", wl->chip.fw_ver);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 goto out;
898
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200899irq_disable:
900 wl1271_disable_interrupts(wl);
901 mutex_unlock(&wl->mutex);
902 /* Unlocking the mutex in the middle of handling is
903 inherently unsafe. In this case we deem it safe to do,
904 because we need to let any possibly pending IRQ out of
905 the system (and while we are WL1271_STATE_OFF the IRQ
906 work function will not do anything.) Also, any other
907 possible concurrent operations will fail due to the
908 current state, hence the wl1271 struct should be safe. */
909 cancel_work_sync(&wl->irq_work);
910 mutex_lock(&wl->mutex);
911power_off:
912 wl1271_power_off(wl);
913 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +0200915 wl1271_error("firmware boot failed despite %d retries",
916 WL1271_BOOT_RETRIES);
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +0300917out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918 mutex_unlock(&wl->mutex);
919
Juuso Oikarineneb887df2010-07-08 17:49:58 +0300920 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300921 list_add(&wl->list, &wl_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300922
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300923 return ret;
924}
925
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200926static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
927 struct ieee80211_vif *vif)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928{
929 struct wl1271 *wl = hw->priv;
930 int i;
931
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200932 mutex_lock(&wl->mutex);
933 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300934
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200935 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300937 list_del(&wl->list);
938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300939 WARN_ON(wl->state != WL1271_STATE_ON);
940
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300941 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +0300942 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +0300943 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +0300944
Luciano Coelho08688d62010-07-08 17:50:07 +0300945 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 mutex_unlock(&wl->mutex);
947 ieee80211_scan_completed(wl->hw, true);
948 mutex_lock(&wl->mutex);
Luciano Coelho08688d62010-07-08 17:50:07 +0300949 wl->scan.state = WL1271_SCAN_STATE_IDLE;
950 kfree(wl->scan.scanned_ch);
951 wl->scan.scanned_ch = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952 }
953
954 wl->state = WL1271_STATE_OFF;
955
956 wl1271_disable_interrupts(wl);
957
958 mutex_unlock(&wl->mutex);
959
960 cancel_work_sync(&wl->irq_work);
961 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300962 cancel_delayed_work_sync(&wl->pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963
964 mutex_lock(&wl->mutex);
965
966 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +0300967 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300968 wl1271_power_off(wl);
969
970 memset(wl->bssid, 0, ETH_ALEN);
971 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
972 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300973 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +0200974 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +0300975 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976
977 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +0200978 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
980 wl->tx_blocks_available = 0;
981 wl->tx_results_count = 0;
982 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +0300983 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +0200984 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300985 wl->time_offset = 0;
986 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +0200987 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
988 wl->sta_rate_set = 0;
989 wl->flags = 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +0200990 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +0200991 wl->filters = 0;
Luciano Coelhod6e19d132009-10-12 15:08:43 +0300992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 for (i = 0; i < NUM_TX_QUEUES; i++)
994 wl->tx_blocks_freed[i] = 0;
995
996 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +0300997
998 kfree(wl->fw_status);
999 wl->fw_status = NULL;
1000 kfree(wl->tx_res_if);
1001 wl->tx_res_if = NULL;
1002 kfree(wl->target_mem_map);
1003 wl->target_mem_map = NULL;
1004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 mutex_unlock(&wl->mutex);
1006}
1007
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001008static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
1009{
1010 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
1011 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
1012
1013 /* combine requested filters with current filter config */
1014 filters = wl->filters | filters;
1015
1016 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1017
1018 if (filters & FIF_PROMISC_IN_BSS) {
1019 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1020 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1021 wl->rx_config |= CFG_BSSID_FILTER_EN;
1022 }
1023 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1024 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1025 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1026 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1027 }
1028 if (filters & FIF_OTHER_BSS) {
1029 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1030 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1031 }
1032 if (filters & FIF_CONTROL) {
1033 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1034 wl->rx_filter |= CFG_RX_CTL_EN;
1035 }
1036 if (filters & FIF_FCSFAIL) {
1037 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1038 wl->rx_filter |= CFG_RX_FCS_ERROR;
1039 }
1040}
1041
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001042static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001043{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001044 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001045 /* we need to use a dummy BSSID for now */
1046 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1047 0xad, 0xbe, 0xef };
1048
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001049 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1050
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001051 /* pass through frames from all BSS */
1052 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1053
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001054 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001055 if (ret < 0)
1056 goto out;
1057
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001058 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001059
1060out:
1061 return ret;
1062}
1063
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001064static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001065{
1066 int ret;
1067
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001068 /*
1069 * One of the side effects of the JOIN command is that is clears
1070 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1071 * to a WPA/WPA2 access point will therefore kill the data-path.
1072 * Currently there is no supported scenario for JOIN during
1073 * association - if it becomes a supported scenario, the WPA/WPA2 keys
1074 * must be handled somehow.
1075 *
1076 */
1077 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1078 wl1271_info("JOIN while associated.");
1079
1080 if (set_assoc)
1081 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1082
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001083 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1084 if (ret < 0)
1085 goto out;
1086
1087 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1088
1089 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1090 goto out;
1091
1092 /*
1093 * The join command disable the keep-alive mode, shut down its process,
1094 * and also clear the template config, so we need to reset it all after
1095 * the join. The acx_aid starts the keep-alive process, and the order
1096 * of the commands below is relevant.
1097 */
1098 ret = wl1271_acx_keep_alive_mode(wl, true);
1099 if (ret < 0)
1100 goto out;
1101
1102 ret = wl1271_acx_aid(wl, wl->aid);
1103 if (ret < 0)
1104 goto out;
1105
1106 ret = wl1271_cmd_build_klv_null_data(wl);
1107 if (ret < 0)
1108 goto out;
1109
1110 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1111 ACX_KEEP_ALIVE_TPL_VALID);
1112 if (ret < 0)
1113 goto out;
1114
1115out:
1116 return ret;
1117}
1118
1119static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001120{
1121 int ret;
1122
1123 /* to stop listening to a channel, we disconnect */
1124 ret = wl1271_cmd_disconnect(wl);
1125 if (ret < 0)
1126 goto out;
1127
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001128 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001129 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001130
1131 /* stop filterting packets based on bssid */
1132 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001133
1134out:
1135 return ret;
1136}
1137
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001138static void wl1271_set_band_rate(struct wl1271 *wl)
1139{
1140 if (wl->band == IEEE80211_BAND_2GHZ)
1141 wl->basic_rate_set = wl->conf.tx.basic_rate;
1142 else
1143 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1144}
1145
1146static u32 wl1271_min_rate_get(struct wl1271 *wl)
1147{
1148 int i;
1149 u32 rate = 0;
1150
1151 if (!wl->basic_rate_set) {
1152 WARN_ON(1);
1153 wl->basic_rate_set = wl->conf.tx.basic_rate;
1154 }
1155
1156 for (i = 0; !rate; i++) {
1157 if ((wl->basic_rate_set >> i) & 0x1)
1158 rate = 1 << i;
1159 }
1160
1161 return rate;
1162}
1163
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001164static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
1165{
1166 int ret;
1167
1168 if (idle) {
1169 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1170 ret = wl1271_unjoin(wl);
1171 if (ret < 0)
1172 goto out;
1173 }
1174 wl->rate_set = wl1271_min_rate_get(wl);
1175 wl->sta_rate_set = 0;
1176 ret = wl1271_acx_rate_policies(wl);
1177 if (ret < 0)
1178 goto out;
1179 ret = wl1271_acx_keep_alive_config(
1180 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1181 ACX_KEEP_ALIVE_TPL_INVALID);
1182 if (ret < 0)
1183 goto out;
1184 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1185 } else {
1186 /* increment the session counter */
1187 wl->session_counter++;
1188 if (wl->session_counter >= SESSION_COUNTER_MAX)
1189 wl->session_counter = 0;
1190 ret = wl1271_dummy_join(wl);
1191 if (ret < 0)
1192 goto out;
1193 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1194 }
1195
1196out:
1197 return ret;
1198}
1199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001200static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1201{
1202 struct wl1271 *wl = hw->priv;
1203 struct ieee80211_conf *conf = &hw->conf;
1204 int channel, ret = 0;
1205
1206 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1207
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001208 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209 channel,
1210 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001211 conf->power_level,
1212 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001214 /*
1215 * mac80211 will go to idle nearly immediately after transmitting some
1216 * frames, such as the deauth. To make sure those frames reach the air,
1217 * wait here until the TX queue is fully flushed.
1218 */
1219 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1220 (conf->flags & IEEE80211_CONF_IDLE))
1221 wl1271_tx_flush(wl);
1222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 mutex_lock(&wl->mutex);
1224
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001225 if (unlikely(wl->state == WL1271_STATE_OFF))
1226 goto out;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001227
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001228 ret = wl1271_ps_elp_wakeup(wl, false);
1229 if (ret < 0)
1230 goto out;
1231
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001232 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001233 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1234 ((wl->band != conf->channel->band) ||
1235 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001236 wl->band = conf->channel->band;
1237 wl->channel = channel;
1238
1239 /*
1240 * FIXME: the mac80211 should really provide a fixed rate
1241 * to use here. for now, just use the smallest possible rate
1242 * for the band as a fixed rate for association frames and
1243 * other control messages.
1244 */
1245 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1246 wl1271_set_band_rate(wl);
1247
1248 wl->basic_rate = wl1271_min_rate_get(wl);
1249 ret = wl1271_acx_rate_policies(wl);
1250 if (ret < 0)
1251 wl1271_warning("rate policy for update channel "
1252 "failed %d", ret);
1253
1254 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001255 ret = wl1271_join(wl, false);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001256 if (ret < 0)
1257 wl1271_warning("cmd join to update channel "
1258 "failed %d", ret);
1259 }
1260 }
1261
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001262 if (changed & IEEE80211_CONF_CHANGE_IDLE) {
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001263 ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
1264 if (ret < 0)
1265 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266 }
1267
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001268 /*
1269 * if mac80211 changes the PSM mode, make sure the mode is not
1270 * incorrectly changed after the pspoll failure active window.
1271 */
1272 if (changed & IEEE80211_CONF_CHANGE_PS)
1273 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1274
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001275 if (conf->flags & IEEE80211_CONF_PS &&
1276 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1277 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001278
1279 /*
1280 * We enter PSM only if we're already associated.
1281 * If we're not, we'll enter it when joining an SSID,
1282 * through the bss_info_changed() hook.
1283 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001284 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001285 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001286 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1287 true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001288 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001290 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001291 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001293 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001295 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001296 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1297 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 }
1299
1300 if (conf->power_level != wl->power_level) {
1301 ret = wl1271_acx_tx_power(wl, conf->power_level);
1302 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001303 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001304
1305 wl->power_level = conf->power_level;
1306 }
1307
1308out_sleep:
1309 wl1271_ps_elp_sleep(wl);
1310
1311out:
1312 mutex_unlock(&wl->mutex);
1313
1314 return ret;
1315}
1316
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001317struct wl1271_filter_params {
1318 bool enabled;
1319 int mc_list_length;
1320 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1321};
1322
Jiri Pirko22bedad32010-04-01 21:22:57 +00001323static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1324 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001325{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001326 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001327 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001328 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001329
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001330 if (unlikely(wl->state == WL1271_STATE_OFF))
1331 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001332
Juuso Oikarinen74441132009-10-13 12:47:53 +03001333 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001334 if (!fp) {
1335 wl1271_error("Out of memory setting filters.");
1336 return 0;
1337 }
1338
1339 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001340 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001341 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1342 fp->enabled = false;
1343 } else {
1344 fp->enabled = true;
1345 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001346 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001347 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001348 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001349 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001350 }
1351
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001352 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001353}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001355#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1356 FIF_ALLMULTI | \
1357 FIF_FCSFAIL | \
1358 FIF_BCN_PRBRESP_PROMISC | \
1359 FIF_CONTROL | \
1360 FIF_OTHER_BSS)
1361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1363 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001364 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001366 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001367 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001368 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369
1370 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter");
1371
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001372 mutex_lock(&wl->mutex);
1373
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001374 *total &= WL1271_SUPPORTED_FILTERS;
1375 changed &= WL1271_SUPPORTED_FILTERS;
1376
1377 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001378 goto out;
1379
1380 ret = wl1271_ps_elp_wakeup(wl, false);
1381 if (ret < 0)
1382 goto out;
1383
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001384
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001385 if (*total & FIF_ALLMULTI)
1386 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1387 else if (fp)
1388 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1389 fp->mc_list,
1390 fp->mc_list_length);
1391 if (ret < 0)
1392 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001394 /* determine, whether supported filter values have changed */
1395 if (changed == 0)
1396 goto out_sleep;
1397
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001398 /* configure filters */
1399 wl->filters = *total;
1400 wl1271_configure_filters(wl, 0);
1401
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001402 /* apply configured filters */
1403 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
1404 if (ret < 0)
1405 goto out_sleep;
1406
1407out_sleep:
1408 wl1271_ps_elp_sleep(wl);
1409
1410out:
1411 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001412 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413}
1414
1415static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
1416 struct ieee80211_vif *vif,
1417 struct ieee80211_sta *sta,
1418 struct ieee80211_key_conf *key_conf)
1419{
1420 struct wl1271 *wl = hw->priv;
1421 const u8 *addr;
1422 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001423 u32 tx_seq_32 = 0;
1424 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 u8 key_type;
1426
1427 static const u8 bcast_addr[ETH_ALEN] =
1428 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1429
1430 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
1431
1432 addr = sta ? sta->addr : bcast_addr;
1433
1434 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
1435 wl1271_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
1436 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
1437 key_conf->alg, key_conf->keyidx,
1438 key_conf->keylen, key_conf->flags);
1439 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
1440
1441 if (is_zero_ether_addr(addr)) {
1442 /* We dont support TX only encryption */
1443 ret = -EOPNOTSUPP;
1444 goto out;
1445 }
1446
1447 mutex_lock(&wl->mutex);
1448
1449 ret = wl1271_ps_elp_wakeup(wl, false);
1450 if (ret < 0)
1451 goto out_unlock;
1452
1453 switch (key_conf->alg) {
1454 case ALG_WEP:
1455 key_type = KEY_WEP;
1456
1457 key_conf->hw_key_idx = key_conf->keyidx;
1458 break;
1459 case ALG_TKIP:
1460 key_type = KEY_TKIP;
1461
1462 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001463 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1464 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 break;
1466 case ALG_CCMP:
1467 key_type = KEY_AES;
1468
1469 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001470 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
1471 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001472 break;
1473 default:
1474 wl1271_error("Unknown key algo 0x%x", key_conf->alg);
1475
1476 ret = -EOPNOTSUPP;
1477 goto out_sleep;
1478 }
1479
1480 switch (cmd) {
1481 case SET_KEY:
1482 ret = wl1271_cmd_set_key(wl, KEY_ADD_OR_REPLACE,
1483 key_conf->keyidx, key_type,
1484 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001485 addr, tx_seq_32, tx_seq_16);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 if (ret < 0) {
1487 wl1271_error("Could not add or replace key");
1488 goto out_sleep;
1489 }
Juuso Oikarinenee444cf2010-02-18 13:25:50 +02001490
1491 /* the default WEP key needs to be configured at least once */
1492 if (key_type == KEY_WEP) {
1493 ret = wl1271_cmd_set_default_wep_key(wl,
1494 wl->default_key);
1495 if (ret < 0)
1496 goto out_sleep;
1497 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 break;
1499
1500 case DISABLE_KEY:
Juuso Oikarinenfddc7dd2010-02-18 13:25:49 +02001501 /* The wl1271 does not allow to remove unicast keys - they
1502 will be cleared automatically on next CMD_JOIN. Ignore the
1503 request silently, as we dont want the mac80211 to emit
1504 an error message. */
1505 if (!is_broadcast_ether_addr(addr))
1506 break;
1507
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001508 ret = wl1271_cmd_set_key(wl, KEY_REMOVE,
1509 key_conf->keyidx, key_type,
1510 key_conf->keylen, key_conf->key,
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001511 addr, 0, 0);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001512 if (ret < 0) {
1513 wl1271_error("Could not remove key");
1514 goto out_sleep;
1515 }
1516 break;
1517
1518 default:
1519 wl1271_error("Unsupported key cmd 0x%x", cmd);
1520 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521 break;
1522 }
1523
1524out_sleep:
1525 wl1271_ps_elp_sleep(wl);
1526
1527out_unlock:
1528 mutex_unlock(&wl->mutex);
1529
1530out:
1531 return ret;
1532}
1533
1534static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02001535 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 struct cfg80211_scan_request *req)
1537{
1538 struct wl1271 *wl = hw->priv;
1539 int ret;
1540 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001541 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542
1543 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
1544
1545 if (req->n_ssids) {
1546 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001547 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548 }
1549
1550 mutex_lock(&wl->mutex);
1551
1552 ret = wl1271_ps_elp_wakeup(wl, false);
1553 if (ret < 0)
1554 goto out;
1555
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001556 if (wl1271_11a_enabled())
Luciano Coelho08688d62010-07-08 17:50:07 +03001557 ret = wl1271_scan(hw->priv, ssid, len, req);
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03001558 else
Luciano Coelho08688d62010-07-08 17:50:07 +03001559 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560
1561 wl1271_ps_elp_sleep(wl);
1562
1563out:
1564 mutex_unlock(&wl->mutex);
1565
1566 return ret;
1567}
1568
1569static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
1570{
1571 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001572 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573
1574 mutex_lock(&wl->mutex);
1575
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03001576 if (unlikely(wl->state == WL1271_STATE_OFF))
1577 goto out;
1578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 ret = wl1271_ps_elp_wakeup(wl, false);
1580 if (ret < 0)
1581 goto out;
1582
1583 ret = wl1271_acx_rts_threshold(wl, (u16) value);
1584 if (ret < 0)
1585 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
1586
1587 wl1271_ps_elp_sleep(wl);
1588
1589out:
1590 mutex_unlock(&wl->mutex);
1591
1592 return ret;
1593}
1594
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001595static void wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *beacon)
1596{
1597 u8 *ptr = beacon->data +
1598 offsetof(struct ieee80211_mgmt, u.beacon.variable);
1599
1600 /* find the location of the ssid in the beacon */
1601 while (ptr < beacon->data + beacon->len) {
1602 if (ptr[0] == WLAN_EID_SSID) {
1603 wl->ssid_len = ptr[1];
1604 memcpy(wl->ssid, ptr+2, wl->ssid_len);
1605 return;
1606 }
1607 ptr += ptr[1];
1608 }
1609 wl1271_error("ad-hoc beacon template has no SSID!\n");
1610}
1611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001612static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
1613 struct ieee80211_vif *vif,
1614 struct ieee80211_bss_conf *bss_conf,
1615 u32 changed)
1616{
1617 enum wl1271_cmd_ps_mode mode;
1618 struct wl1271 *wl = hw->priv;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001619 bool do_join = false;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001620 bool set_assoc = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001621 int ret;
1622
1623 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
1624
1625 mutex_lock(&wl->mutex);
1626
1627 ret = wl1271_ps_elp_wakeup(wl, false);
1628 if (ret < 0)
1629 goto out;
1630
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02001631 if ((changed && BSS_CHANGED_BEACON_INT) &&
1632 (wl->bss_type == BSS_TYPE_IBSS)) {
1633 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
1634 bss_conf->beacon_int);
1635
1636 wl->beacon_int = bss_conf->beacon_int;
1637 do_join = true;
1638 }
1639
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001640 if ((changed && BSS_CHANGED_BEACON) &&
1641 (wl->bss_type == BSS_TYPE_IBSS)) {
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001642 struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
1643
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001644 wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
1645
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001646 if (beacon) {
1647 struct ieee80211_hdr *hdr;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001648
1649 wl1271_ssid_set(wl, beacon);
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001650 ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
1651 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001652 beacon->len, 0,
1653 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001654
1655 if (ret < 0) {
1656 dev_kfree_skb(beacon);
1657 goto out_sleep;
1658 }
1659
1660 hdr = (struct ieee80211_hdr *) beacon->data;
1661 hdr->frame_control = cpu_to_le16(
1662 IEEE80211_FTYPE_MGMT |
1663 IEEE80211_STYPE_PROBE_RESP);
1664
1665 ret = wl1271_cmd_template_set(wl,
1666 CMD_TEMPL_PROBE_RESPONSE,
1667 beacon->data,
Juuso Oikarinen606c1482010-04-01 11:38:21 +03001668 beacon->len, 0,
1669 wl1271_min_rate_get(wl));
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001670 dev_kfree_skb(beacon);
1671 if (ret < 0)
1672 goto out_sleep;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001673
1674 /* Need to update the SSID (for filtering etc) */
1675 do_join = true;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001676 }
1677 }
1678
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001679 if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
1680 (wl->bss_type == BSS_TYPE_IBSS)) {
1681 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
1682 bss_conf->enable_beacon ? "enabled" : "disabled");
1683
1684 if (bss_conf->enable_beacon)
1685 wl->set_bss_type = BSS_TYPE_IBSS;
1686 else
1687 wl->set_bss_type = BSS_TYPE_STA_BSS;
1688 do_join = true;
1689 }
1690
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03001691 if (changed & BSS_CHANGED_CQM) {
1692 bool enable = false;
1693 if (bss_conf->cqm_rssi_thold)
1694 enable = true;
1695 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
1696 bss_conf->cqm_rssi_thold,
1697 bss_conf->cqm_rssi_hyst);
1698 if (ret < 0)
1699 goto out;
1700 wl->rssi_thold = bss_conf->cqm_rssi_thold;
1701 }
1702
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001703 if ((changed & BSS_CHANGED_BSSID) &&
1704 /*
1705 * Now we know the correct bssid, so we send a new join command
1706 * and enable the BSSID filter
1707 */
1708 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001709 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001710
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001711 ret = wl1271_cmd_build_null_data(wl);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02001712 if (ret < 0)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001713 goto out_sleep;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001714
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03001715 ret = wl1271_build_qos_null_data(wl);
1716 if (ret < 0)
1717 goto out_sleep;
1718
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001719 /* filter out all packets not from this BSSID */
1720 wl1271_configure_filters(wl, 0);
1721
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001722 /* Need to update the BSSID (for filtering etc) */
1723 do_join = true;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02001724 }
1725
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001726 if (changed & BSS_CHANGED_ASSOC) {
1727 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001728 u32 rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001729 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001730 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001732 wl->ps_poll_failures = 0;
1733
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001734 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001735 * use basic rates from AP, and determine lowest rate
1736 * to use with control frames.
1737 */
1738 rates = bss_conf->basic_rates;
1739 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
1740 rates);
1741 wl->basic_rate = wl1271_min_rate_get(wl);
1742 ret = wl1271_acx_rate_policies(wl);
1743 if (ret < 0)
1744 goto out_sleep;
1745
1746 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03001747 * with wl1271, we don't need to update the
1748 * beacon_int and dtim_period, because the firmware
1749 * updates it by itself when the first beacon is
1750 * received after a join.
1751 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
1753 if (ret < 0)
1754 goto out_sleep;
1755
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02001756 /*
1757 * The SSID is intentionally set to NULL here - the
1758 * firmware will set the probe request with a
1759 * broadcast SSID regardless of what we set in the
1760 * template.
1761 */
1762 ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
1763 NULL, 0, wl->band);
1764
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001765 /* enable the connection monitoring feature */
1766 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767 if (ret < 0)
1768 goto out_sleep;
1769
1770 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001771 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
1772 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001774 ret = wl1271_ps_set_mode(wl, mode, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775 if (ret < 0)
1776 goto out_sleep;
1777 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001778 } else {
1779 /* use defaults when not associated */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001780 clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001781 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001782
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001783 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001784 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001785
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001786 /* revert back to minimum rates for the current band */
1787 wl1271_set_band_rate(wl);
1788 wl->basic_rate = wl1271_min_rate_get(wl);
1789 ret = wl1271_acx_rate_policies(wl);
1790 if (ret < 0)
1791 goto out_sleep;
1792
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001793 /* disable connection monitor features */
1794 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001795
1796 /* Disable the keep-alive feature */
1797 ret = wl1271_acx_keep_alive_mode(wl, false);
1798
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02001799 if (ret < 0)
1800 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001801 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03001802
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001803 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001804
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 if (changed & BSS_CHANGED_ERP_SLOT) {
1806 if (bss_conf->use_short_slot)
1807 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
1808 else
1809 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
1810 if (ret < 0) {
1811 wl1271_warning("Set slot time failed %d", ret);
1812 goto out_sleep;
1813 }
1814 }
1815
1816 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
1817 if (bss_conf->use_short_preamble)
1818 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
1819 else
1820 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
1821 }
1822
1823 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
1824 if (bss_conf->use_cts_prot)
1825 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
1826 else
1827 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
1828 if (ret < 0) {
1829 wl1271_warning("Set ctsprotect failed %d", ret);
1830 goto out_sleep;
1831 }
1832 }
1833
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03001834 if (changed & BSS_CHANGED_ARP_FILTER) {
1835 __be32 addr = bss_conf->arp_addr_list[0];
1836 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
1837
1838 if (bss_conf->arp_addr_cnt == 1 && bss_conf->arp_filter_enabled)
1839 ret = wl1271_acx_arp_ip_filter(wl, true, addr);
1840 else
1841 ret = wl1271_acx_arp_ip_filter(wl, false, addr);
1842
1843 if (ret < 0)
1844 goto out_sleep;
1845 }
1846
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001847 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001848 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02001849 if (ret < 0) {
1850 wl1271_warning("cmd join failed %d", ret);
1851 goto out_sleep;
1852 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02001853 }
1854
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855out_sleep:
1856 wl1271_ps_elp_sleep(wl);
1857
1858out:
1859 mutex_unlock(&wl->mutex);
1860}
1861
Kalle Valoc6999d82010-02-18 13:25:41 +02001862static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
1863 const struct ieee80211_tx_queue_params *params)
1864{
1865 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02001866 u8 ps_scheme;
Kalle Valoc6999d82010-02-18 13:25:41 +02001867 int ret;
1868
1869 mutex_lock(&wl->mutex);
1870
1871 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
1872
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001873 ret = wl1271_ps_elp_wakeup(wl, false);
1874 if (ret < 0)
1875 goto out;
1876
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001877 /* the txop is confed in units of 32us by the mac80211, we need us */
Kalle Valoc6999d82010-02-18 13:25:41 +02001878 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
1879 params->cw_min, params->cw_max,
Juuso Oikarinenb43316d2010-03-18 12:26:26 +02001880 params->aifs, params->txop << 5);
Kalle Valoc6999d82010-02-18 13:25:41 +02001881 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001882 goto out_sleep;
Kalle Valoc6999d82010-02-18 13:25:41 +02001883
Kalle Valo4695dc92010-03-18 12:26:38 +02001884 if (params->uapsd)
1885 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
1886 else
1887 ps_scheme = CONF_PS_SCHEME_LEGACY;
1888
Kalle Valoc6999d82010-02-18 13:25:41 +02001889 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
1890 CONF_CHANNEL_TYPE_EDCF,
1891 wl1271_tx_get_queue(queue),
Kalle Valo4695dc92010-03-18 12:26:38 +02001892 ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
Kalle Valoc6999d82010-02-18 13:25:41 +02001893 if (ret < 0)
Kalle Valoc82c1dd2010-02-18 13:25:47 +02001894 goto out_sleep;
1895
1896out_sleep:
1897 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02001898
1899out:
1900 mutex_unlock(&wl->mutex);
1901
1902 return ret;
1903}
1904
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03001905static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
1906{
1907
1908 struct wl1271 *wl = hw->priv;
1909 u64 mactime = ULLONG_MAX;
1910 int ret;
1911
1912 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
1913
1914 mutex_lock(&wl->mutex);
1915
1916 ret = wl1271_ps_elp_wakeup(wl, false);
1917 if (ret < 0)
1918 goto out;
1919
1920 ret = wl1271_acx_tsf_info(wl, &mactime);
1921 if (ret < 0)
1922 goto out_sleep;
1923
1924out_sleep:
1925 wl1271_ps_elp_sleep(wl);
1926
1927out:
1928 mutex_unlock(&wl->mutex);
1929 return mactime;
1930}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931
1932/* can't be const, mac80211 writes to this */
1933static struct ieee80211_rate wl1271_rates[] = {
1934 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001935 .hw_value = CONF_HW_BIT_RATE_1MBPS,
1936 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001937 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001938 .hw_value = CONF_HW_BIT_RATE_2MBPS,
1939 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1941 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001942 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
1943 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001944 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1945 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001946 .hw_value = CONF_HW_BIT_RATE_11MBPS,
1947 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1949 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001950 .hw_value = CONF_HW_BIT_RATE_6MBPS,
1951 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001952 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001953 .hw_value = CONF_HW_BIT_RATE_9MBPS,
1954 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001956 .hw_value = CONF_HW_BIT_RATE_12MBPS,
1957 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001958 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001959 .hw_value = CONF_HW_BIT_RATE_18MBPS,
1960 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001962 .hw_value = CONF_HW_BIT_RATE_24MBPS,
1963 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001965 .hw_value = CONF_HW_BIT_RATE_36MBPS,
1966 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001968 .hw_value = CONF_HW_BIT_RATE_48MBPS,
1969 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001970 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03001971 .hw_value = CONF_HW_BIT_RATE_54MBPS,
1972 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973};
1974
1975/* can't be const, mac80211 writes to this */
1976static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02001977 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
1978 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
1979 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
1980 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
1981 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
1982 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
1983 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
1984 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
1985 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
1986 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
1987 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
1988 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
1989 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990};
1991
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001992/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02001993static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02001994 /* MCS rates are used only with 11n */
1995 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
1996 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
1997 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
1998 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
1999 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2000 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2001 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2002 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2003
2004 11, /* CONF_HW_RXTX_RATE_54 */
2005 10, /* CONF_HW_RXTX_RATE_48 */
2006 9, /* CONF_HW_RXTX_RATE_36 */
2007 8, /* CONF_HW_RXTX_RATE_24 */
2008
2009 /* TI-specific rate */
2010 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2011
2012 7, /* CONF_HW_RXTX_RATE_18 */
2013 6, /* CONF_HW_RXTX_RATE_12 */
2014 3, /* CONF_HW_RXTX_RATE_11 */
2015 5, /* CONF_HW_RXTX_RATE_9 */
2016 4, /* CONF_HW_RXTX_RATE_6 */
2017 2, /* CONF_HW_RXTX_RATE_5_5 */
2018 1, /* CONF_HW_RXTX_RATE_2 */
2019 0 /* CONF_HW_RXTX_RATE_1 */
2020};
2021
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002022/* can't be const, mac80211 writes to this */
2023static struct ieee80211_supported_band wl1271_band_2ghz = {
2024 .channels = wl1271_channels,
2025 .n_channels = ARRAY_SIZE(wl1271_channels),
2026 .bitrates = wl1271_rates,
2027 .n_bitrates = ARRAY_SIZE(wl1271_rates),
2028};
2029
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002030/* 5 GHz data rates for WL1273 */
2031static struct ieee80211_rate wl1271_rates_5ghz[] = {
2032 { .bitrate = 60,
2033 .hw_value = CONF_HW_BIT_RATE_6MBPS,
2034 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
2035 { .bitrate = 90,
2036 .hw_value = CONF_HW_BIT_RATE_9MBPS,
2037 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
2038 { .bitrate = 120,
2039 .hw_value = CONF_HW_BIT_RATE_12MBPS,
2040 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
2041 { .bitrate = 180,
2042 .hw_value = CONF_HW_BIT_RATE_18MBPS,
2043 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
2044 { .bitrate = 240,
2045 .hw_value = CONF_HW_BIT_RATE_24MBPS,
2046 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
2047 { .bitrate = 360,
2048 .hw_value = CONF_HW_BIT_RATE_36MBPS,
2049 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
2050 { .bitrate = 480,
2051 .hw_value = CONF_HW_BIT_RATE_48MBPS,
2052 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
2053 { .bitrate = 540,
2054 .hw_value = CONF_HW_BIT_RATE_54MBPS,
2055 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
2056};
2057
2058/* 5 GHz band channels for WL1273 */
2059static struct ieee80211_channel wl1271_channels_5ghz[] = {
2060 { .hw_value = 183, .center_freq = 4915},
2061 { .hw_value = 184, .center_freq = 4920},
2062 { .hw_value = 185, .center_freq = 4925},
2063 { .hw_value = 187, .center_freq = 4935},
2064 { .hw_value = 188, .center_freq = 4940},
2065 { .hw_value = 189, .center_freq = 4945},
2066 { .hw_value = 192, .center_freq = 4960},
2067 { .hw_value = 196, .center_freq = 4980},
2068 { .hw_value = 7, .center_freq = 5035},
2069 { .hw_value = 8, .center_freq = 5040},
2070 { .hw_value = 9, .center_freq = 5045},
2071 { .hw_value = 11, .center_freq = 5055},
2072 { .hw_value = 12, .center_freq = 5060},
2073 { .hw_value = 16, .center_freq = 5080},
2074 { .hw_value = 34, .center_freq = 5170},
2075 { .hw_value = 36, .center_freq = 5180},
2076 { .hw_value = 38, .center_freq = 5190},
2077 { .hw_value = 40, .center_freq = 5200},
2078 { .hw_value = 42, .center_freq = 5210},
2079 { .hw_value = 44, .center_freq = 5220},
2080 { .hw_value = 46, .center_freq = 5230},
2081 { .hw_value = 48, .center_freq = 5240},
2082 { .hw_value = 52, .center_freq = 5260},
2083 { .hw_value = 56, .center_freq = 5280},
2084 { .hw_value = 60, .center_freq = 5300},
2085 { .hw_value = 64, .center_freq = 5320},
2086 { .hw_value = 100, .center_freq = 5500},
2087 { .hw_value = 104, .center_freq = 5520},
2088 { .hw_value = 108, .center_freq = 5540},
2089 { .hw_value = 112, .center_freq = 5560},
2090 { .hw_value = 116, .center_freq = 5580},
2091 { .hw_value = 120, .center_freq = 5600},
2092 { .hw_value = 124, .center_freq = 5620},
2093 { .hw_value = 128, .center_freq = 5640},
2094 { .hw_value = 132, .center_freq = 5660},
2095 { .hw_value = 136, .center_freq = 5680},
2096 { .hw_value = 140, .center_freq = 5700},
2097 { .hw_value = 149, .center_freq = 5745},
2098 { .hw_value = 153, .center_freq = 5765},
2099 { .hw_value = 157, .center_freq = 5785},
2100 { .hw_value = 161, .center_freq = 5805},
2101 { .hw_value = 165, .center_freq = 5825},
2102};
2103
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002104/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02002105static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002106 /* MCS rates are used only with 11n */
2107 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
2108 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
2109 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
2110 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
2111 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
2112 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
2113 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
2114 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
2115
2116 7, /* CONF_HW_RXTX_RATE_54 */
2117 6, /* CONF_HW_RXTX_RATE_48 */
2118 5, /* CONF_HW_RXTX_RATE_36 */
2119 4, /* CONF_HW_RXTX_RATE_24 */
2120
2121 /* TI-specific rate */
2122 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
2123
2124 3, /* CONF_HW_RXTX_RATE_18 */
2125 2, /* CONF_HW_RXTX_RATE_12 */
2126 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
2127 1, /* CONF_HW_RXTX_RATE_9 */
2128 0, /* CONF_HW_RXTX_RATE_6 */
2129 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
2130 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
2131 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
2132};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002133
2134static struct ieee80211_supported_band wl1271_band_5ghz = {
2135 .channels = wl1271_channels_5ghz,
2136 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
2137 .bitrates = wl1271_rates_5ghz,
2138 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
2139};
2140
Tobias Klausera0ea9492010-05-20 10:38:11 +02002141static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002142 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
2143 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
2144};
2145
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002146static const struct ieee80211_ops wl1271_ops = {
2147 .start = wl1271_op_start,
2148 .stop = wl1271_op_stop,
2149 .add_interface = wl1271_op_add_interface,
2150 .remove_interface = wl1271_op_remove_interface,
2151 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002152 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002153 .configure_filter = wl1271_op_configure_filter,
2154 .tx = wl1271_op_tx,
2155 .set_key = wl1271_op_set_key,
2156 .hw_scan = wl1271_op_hw_scan,
2157 .bss_info_changed = wl1271_op_bss_info_changed,
2158 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02002159 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002160 .get_tsf = wl1271_op_get_tsf,
Kalle Valoc8c90872010-02-18 13:25:53 +02002161 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002162};
2163
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02002164
2165u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
2166{
2167 u8 idx;
2168
2169 BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
2170
2171 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
2172 wl1271_error("Illegal RX rate from HW: %d", rate);
2173 return 0;
2174 }
2175
2176 idx = wl1271_band_rate_to_idx[wl->band][rate];
2177 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
2178 wl1271_error("Unsupported RX rate from HW: %d", rate);
2179 return 0;
2180 }
2181
2182 return idx;
2183}
2184
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002185static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
2186 struct device_attribute *attr,
2187 char *buf)
2188{
2189 struct wl1271 *wl = dev_get_drvdata(dev);
2190 ssize_t len;
2191
2192 /* FIXME: what's the maximum length of buf? page size?*/
2193 len = 500;
2194
2195 mutex_lock(&wl->mutex);
2196 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
2197 wl->sg_enabled);
2198 mutex_unlock(&wl->mutex);
2199
2200 return len;
2201
2202}
2203
2204static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
2205 struct device_attribute *attr,
2206 const char *buf, size_t count)
2207{
2208 struct wl1271 *wl = dev_get_drvdata(dev);
2209 unsigned long res;
2210 int ret;
2211
2212 ret = strict_strtoul(buf, 10, &res);
2213
2214 if (ret < 0) {
2215 wl1271_warning("incorrect value written to bt_coex_mode");
2216 return count;
2217 }
2218
2219 mutex_lock(&wl->mutex);
2220
2221 res = !!res;
2222
2223 if (res == wl->sg_enabled)
2224 goto out;
2225
2226 wl->sg_enabled = res;
2227
2228 if (wl->state == WL1271_STATE_OFF)
2229 goto out;
2230
2231 ret = wl1271_ps_elp_wakeup(wl, false);
2232 if (ret < 0)
2233 goto out;
2234
2235 wl1271_acx_sg_enable(wl, wl->sg_enabled);
2236 wl1271_ps_elp_sleep(wl);
2237
2238 out:
2239 mutex_unlock(&wl->mutex);
2240 return count;
2241}
2242
2243static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
2244 wl1271_sysfs_show_bt_coex_state,
2245 wl1271_sysfs_store_bt_coex_state);
2246
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002247static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
2248 struct device_attribute *attr,
2249 char *buf)
2250{
2251 struct wl1271 *wl = dev_get_drvdata(dev);
2252 ssize_t len;
2253
2254 /* FIXME: what's the maximum length of buf? page size?*/
2255 len = 500;
2256
2257 mutex_lock(&wl->mutex);
2258 if (wl->hw_pg_ver >= 0)
2259 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
2260 else
2261 len = snprintf(buf, len, "n/a\n");
2262 mutex_unlock(&wl->mutex);
2263
2264 return len;
2265}
2266
2267static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
2268 wl1271_sysfs_show_hw_pg_ver, NULL);
2269
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002270int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002271{
2272 int ret;
2273
2274 if (wl->mac80211_registered)
2275 return 0;
2276
2277 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
2278
2279 ret = ieee80211_register_hw(wl->hw);
2280 if (ret < 0) {
2281 wl1271_error("unable to register mac80211 hw: %d", ret);
2282 return ret;
2283 }
2284
2285 wl->mac80211_registered = true;
2286
2287 wl1271_notice("loaded");
2288
2289 return 0;
2290}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002291EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002293void wl1271_unregister_hw(struct wl1271 *wl)
2294{
2295 ieee80211_unregister_hw(wl->hw);
2296 wl->mac80211_registered = false;
2297
2298}
2299EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
2300
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002301int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302{
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03002303 /* The tx descriptor buffer and the TKIP space. */
2304 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
2305 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306
2307 /* unit us */
2308 /* FIXME: find a proper value */
2309 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03002310 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311
2312 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02002313 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02002314 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02002315 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02002316 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002317 IEEE80211_HW_CONNECTION_MONITOR |
2318 IEEE80211_HW_SUPPORTS_CQM_RSSI;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002320 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
2321 BIT(NL80211_IFTYPE_ADHOC);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002322 wl->hw->wiphy->max_scan_ssids = 1;
2323 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz;
2324
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03002325 if (wl1271_11a_enabled())
2326 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
2327
Kalle Valo12bd8942010-03-18 12:26:33 +02002328 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02002329 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02002330
Teemu Paasikivi8197b712010-02-22 08:38:23 +02002331 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002332
2333 return 0;
2334}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002335EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002336
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002338
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002339struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002340{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002342 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002343 struct wl1271 *wl;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002344 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002345
2346 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
2347 if (!hw) {
2348 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002349 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002350 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002351 }
2352
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002353 plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
2354 if (!plat_dev) {
2355 wl1271_error("could not allocate platform_device");
2356 ret = -ENOMEM;
2357 goto err_plat_alloc;
2358 }
2359
2360 memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
2361
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362 wl = hw->priv;
2363 memset(wl, 0, sizeof(*wl));
2364
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002365 INIT_LIST_HEAD(&wl->list);
2366
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002368 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369
2370 skb_queue_head_init(&wl->tx_queue);
2371
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03002372 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002373 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02002375 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377 wl->rx_counter = 0;
2378 wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
2379 wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002380 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002381 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02002382 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002383 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002384 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
2385 wl->sta_rate_set = 0;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002386 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03002387 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002388 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002389 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002390 wl->hw_pg_ver = -1;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03002392 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393 wl->tx_frames[i] = NULL;
2394
2395 spin_lock_init(&wl->wl_lock);
2396
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002397 wl->state = WL1271_STATE_OFF;
2398 mutex_init(&wl->mutex);
2399
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002400 /* Apply default driver configuration. */
2401 wl1271_conf_init(wl);
2402
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02002403 wl1271_debugfs_init(wl);
2404
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002405 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002406 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002407 if (ret) {
2408 wl1271_error("couldn't register platform device");
2409 goto err_hw;
2410 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002411 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002412
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002413 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002414 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002415 if (ret < 0) {
2416 wl1271_error("failed to create sysfs file bt_coex_state");
2417 goto err_platform;
2418 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002419
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002420 /* Create sysfs file to get HW PG version */
2421 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
2422 if (ret < 0) {
2423 wl1271_error("failed to create sysfs file hw_pg_ver");
2424 goto err_bt_coex_state;
2425 }
2426
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002427 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002428
Juuso Oikarinend717fd62010-05-07 11:38:58 +03002429err_bt_coex_state:
2430 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
2431
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002432err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002433 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02002434
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002435err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002436 wl1271_debugfs_exit(wl);
2437 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002438
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002439err_plat_alloc:
2440 ieee80211_free_hw(hw);
2441
2442err_hw_alloc:
2443
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02002444 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002445}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002446EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002447
2448int wl1271_free_hw(struct wl1271 *wl)
2449{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02002450 platform_device_unregister(wl->plat_dev);
2451 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002452
2453 wl1271_debugfs_exit(wl);
2454
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02002455 vfree(wl->fw);
2456 wl->fw = NULL;
2457 kfree(wl->nvs);
2458 wl->nvs = NULL;
2459
2460 kfree(wl->fw_status);
2461 kfree(wl->tx_res_if);
2462
2463 ieee80211_free_hw(wl->hw);
2464
2465 return 0;
2466}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02002467EXPORT_SYMBOL_GPL(wl1271_free_hw);
2468
2469MODULE_LICENSE("GPL");
2470MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
2471MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");