blob: 6a21c13761ba9a3459cc844e401023a1c3f78e14 [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>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300314 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300315 .num_probe_reqs = 2,
316 .rssi_threshold = -90,
317 .snr_threshold = 0,
318 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200319 .rf = {
320 .tx_per_channel_power_compensation_2 = {
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 },
323 .tx_per_channel_power_compensation_5 = {
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 },
328 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100329 .ht = {
330 .tx_ba_win_size = 64,
331 .inactivity_timeout = 10000,
332 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200333 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200334 .num_stations = 1,
335 .ssid_profiles = 1,
336 .rx_block_num = 70,
337 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300338 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200339 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200340 .min_req_rx_blocks = 22,
341 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200342 },
343 .mem_wl128x = {
344 .num_stations = 1,
345 .ssid_profiles = 1,
346 .rx_block_num = 40,
347 .tx_min_block_num = 40,
348 .dynamic_memory = 1,
349 .min_req_tx_blocks = 45,
350 .min_req_rx_blocks = 22,
351 .tx_min = 27,
352 },
Shahar Leviff868432011-04-11 15:41:46 +0300353 .fm_coex = {
354 .enable = true,
355 .swallow_period = 5,
356 .n_divider_fref_set_1 = 0xff, /* default */
357 .n_divider_fref_set_2 = 12,
358 .m_divider_fref_set_1 = 148,
359 .m_divider_fref_set_2 = 0xffff, /* default */
360 .coex_pll_stabilization_time = 0xffffffff, /* default */
361 .ldo_stabilization_time = 0xffff, /* default */
362 .fm_disturbed_band_margin = 0xff, /* default */
363 .swallow_clk_diff = 0xff, /* default */
364 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300365 .rx_streaming = {
366 .duration = 150,
367 .queues = 0x1,
368 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300369 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300370 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300371 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300372};
373
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300374static void __wl1271_op_remove_interface(struct wl1271 *wl,
375 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200376static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200377
378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200379static void wl1271_device_release(struct device *dev)
380{
381
382}
383
384static struct platform_device wl1271_device = {
385 .name = "wl1271",
386 .id = -1,
387
388 /* device model insists to have a release function */
389 .dev = {
390 .release = wl1271_device_release,
391 },
392};
393
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200394static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300395static LIST_HEAD(wl_list);
396
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300397static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
398 void *arg)
399{
400 struct net_device *dev = arg;
401 struct wireless_dev *wdev;
402 struct wiphy *wiphy;
403 struct ieee80211_hw *hw;
404 struct wl1271 *wl;
405 struct wl1271 *wl_temp;
406 int ret = 0;
407
408 /* Check that this notification is for us. */
409 if (what != NETDEV_CHANGE)
410 return NOTIFY_DONE;
411
412 wdev = dev->ieee80211_ptr;
413 if (wdev == NULL)
414 return NOTIFY_DONE;
415
416 wiphy = wdev->wiphy;
417 if (wiphy == NULL)
418 return NOTIFY_DONE;
419
420 hw = wiphy_priv(wiphy);
421 if (hw == NULL)
422 return NOTIFY_DONE;
423
424 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200425 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300426 list_for_each_entry(wl, &wl_list, list) {
427 if (wl == wl_temp)
428 break;
429 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200430 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300431 if (wl != wl_temp)
432 return NOTIFY_DONE;
433
434 mutex_lock(&wl->mutex);
435
436 if (wl->state == WL1271_STATE_OFF)
437 goto out;
438
439 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
440 goto out;
441
Ido Yariva6208652011-03-01 15:14:41 +0200442 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300443 if (ret < 0)
444 goto out;
445
446 if ((dev->operstate == IF_OPER_UP) &&
447 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
448 wl1271_cmd_set_sta_state(wl);
449 wl1271_info("Association completed.");
450 }
451
452 wl1271_ps_elp_sleep(wl);
453
454out:
455 mutex_unlock(&wl->mutex);
456
457 return NOTIFY_OK;
458}
459
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100460static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200461 struct regulatory_request *request)
462{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100463 struct ieee80211_supported_band *band;
464 struct ieee80211_channel *ch;
465 int i;
466
467 band = wiphy->bands[IEEE80211_BAND_5GHZ];
468 for (i = 0; i < band->n_channels; i++) {
469 ch = &band->channels[i];
470 if (ch->flags & IEEE80211_CHAN_DISABLED)
471 continue;
472
473 if (ch->flags & IEEE80211_CHAN_RADAR)
474 ch->flags |= IEEE80211_CHAN_NO_IBSS |
475 IEEE80211_CHAN_PASSIVE_SCAN;
476
477 }
478
479 return 0;
480}
481
Eliad Peller77ddaa12011-05-15 11:10:29 +0300482static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
483{
484 int ret = 0;
485
486 /* we should hold wl->mutex */
487 ret = wl1271_acx_ps_rx_streaming(wl, enable);
488 if (ret < 0)
489 goto out;
490
491 if (enable)
492 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
493 else
494 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
495out:
496 return ret;
497}
498
499/*
500 * this function is being called when the rx_streaming interval
501 * has beed changed or rx_streaming should be disabled
502 */
503int wl1271_recalc_rx_streaming(struct wl1271 *wl)
504{
505 int ret = 0;
506 int period = wl->conf.rx_streaming.interval;
507
508 /* don't reconfigure if rx_streaming is disabled */
509 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
510 goto out;
511
512 /* reconfigure/disable according to new streaming_period */
513 if (period &&
514 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
515 (wl->conf.rx_streaming.always ||
516 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
517 ret = wl1271_set_rx_streaming(wl, true);
518 else {
519 ret = wl1271_set_rx_streaming(wl, false);
520 /* don't cancel_work_sync since we might deadlock */
521 del_timer_sync(&wl->rx_streaming_timer);
522 }
523out:
524 return ret;
525}
526
527static void wl1271_rx_streaming_enable_work(struct work_struct *work)
528{
529 int ret;
530 struct wl1271 *wl =
531 container_of(work, struct wl1271, rx_streaming_enable_work);
532
533 mutex_lock(&wl->mutex);
534
535 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
536 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
537 (!wl->conf.rx_streaming.always &&
538 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
539 goto out;
540
541 if (!wl->conf.rx_streaming.interval)
542 goto out;
543
544 ret = wl1271_ps_elp_wakeup(wl);
545 if (ret < 0)
546 goto out;
547
548 ret = wl1271_set_rx_streaming(wl, true);
549 if (ret < 0)
550 goto out_sleep;
551
552 /* stop it after some time of inactivity */
553 mod_timer(&wl->rx_streaming_timer,
554 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
555
556out_sleep:
557 wl1271_ps_elp_sleep(wl);
558out:
559 mutex_unlock(&wl->mutex);
560}
561
562static void wl1271_rx_streaming_disable_work(struct work_struct *work)
563{
564 int ret;
565 struct wl1271 *wl =
566 container_of(work, struct wl1271, rx_streaming_disable_work);
567
568 mutex_lock(&wl->mutex);
569
570 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
571 goto out;
572
573 ret = wl1271_ps_elp_wakeup(wl);
574 if (ret < 0)
575 goto out;
576
577 ret = wl1271_set_rx_streaming(wl, false);
578 if (ret)
579 goto out_sleep;
580
581out_sleep:
582 wl1271_ps_elp_sleep(wl);
583out:
584 mutex_unlock(&wl->mutex);
585}
586
587static void wl1271_rx_streaming_timer(unsigned long data)
588{
589 struct wl1271 *wl = (struct wl1271 *)data;
590 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
591}
592
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300593static void wl1271_conf_init(struct wl1271 *wl)
594{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300595
596 /*
597 * This function applies the default configuration to the driver. This
598 * function is invoked upon driver load (spi probe.)
599 *
600 * The configuration is stored in a run-time structure in order to
601 * facilitate for run-time adjustment of any of the parameters. Making
602 * changes to the configuration structure will apply the new values on
603 * the next interface up (wl1271_op_start.)
604 */
605
606 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300607 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608}
609
610
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611static int wl1271_plt_init(struct wl1271 *wl)
612{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200613 struct conf_tx_ac_category *conf_ac;
614 struct conf_tx_tid *conf_tid;
615 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300616
Shahar Levi49d750ca2011-03-06 16:32:09 +0200617 if (wl->chip.id == CHIP_ID_1283_PG20)
618 ret = wl128x_cmd_general_parms(wl);
619 else
620 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200621 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200622 return ret;
623
Shahar Levi49d750ca2011-03-06 16:32:09 +0200624 if (wl->chip.id == CHIP_ID_1283_PG20)
625 ret = wl128x_cmd_radio_parms(wl);
626 else
627 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200628 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200629 return ret;
630
Shahar Levi49d750ca2011-03-06 16:32:09 +0200631 if (wl->chip.id != CHIP_ID_1283_PG20) {
632 ret = wl1271_cmd_ext_radio_parms(wl);
633 if (ret < 0)
634 return ret;
635 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200636 if (ret < 0)
637 return ret;
638
Shahar Levi48a61472011-03-06 16:32:08 +0200639 /* Chip-specific initializations */
640 ret = wl1271_chip_specific_init(wl);
641 if (ret < 0)
642 return ret;
643
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200644 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200645 if (ret < 0)
646 return ret;
647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648 ret = wl1271_acx_init_mem_config(wl);
649 if (ret < 0)
650 return ret;
651
Luciano Coelho12419cc2010-02-18 13:25:44 +0200652 /* PHY layer config */
653 ret = wl1271_init_phy_config(wl);
654 if (ret < 0)
655 goto out_free_memmap;
656
657 ret = wl1271_acx_dco_itrim_params(wl);
658 if (ret < 0)
659 goto out_free_memmap;
660
661 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200662 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200663 if (ret < 0)
664 goto out_free_memmap;
665
666 /* Bluetooth WLAN coexistence */
667 ret = wl1271_init_pta(wl);
668 if (ret < 0)
669 goto out_free_memmap;
670
Shahar Leviff868432011-04-11 15:41:46 +0300671 /* FM WLAN coexistence */
672 ret = wl1271_acx_fm_coex(wl);
673 if (ret < 0)
674 goto out_free_memmap;
675
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 /* Energy detection */
677 ret = wl1271_init_energy_detection(wl);
678 if (ret < 0)
679 goto out_free_memmap;
680
Gery Kahn1ec610e2011-02-01 03:03:08 -0600681 ret = wl1271_acx_sta_mem_cfg(wl);
682 if (ret < 0)
683 goto out_free_memmap;
684
Luciano Coelho12419cc2010-02-18 13:25:44 +0200685 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100686 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 if (ret < 0)
688 goto out_free_memmap;
689
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200690 /* Default TID/AC configuration */
691 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200692 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200693 conf_ac = &wl->conf.tx.ac_conf[i];
694 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
695 conf_ac->cw_max, conf_ac->aifsn,
696 conf_ac->tx_op_limit);
697 if (ret < 0)
698 goto out_free_memmap;
699
Luciano Coelho12419cc2010-02-18 13:25:44 +0200700 conf_tid = &wl->conf.tx.tid_conf[i];
701 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
702 conf_tid->channel_type,
703 conf_tid->tsid,
704 conf_tid->ps_scheme,
705 conf_tid->ack_policy,
706 conf_tid->apsd_conf[0],
707 conf_tid->apsd_conf[1]);
708 if (ret < 0)
709 goto out_free_memmap;
710 }
711
Luciano Coelho12419cc2010-02-18 13:25:44 +0200712 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200713 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715 goto out_free_memmap;
716
717 /* Configure for CAM power saving (ie. always active) */
718 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
719 if (ret < 0)
720 goto out_free_memmap;
721
722 /* configure PM */
723 ret = wl1271_acx_pm_config(wl);
724 if (ret < 0)
725 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726
727 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200728
729 out_free_memmap:
730 kfree(wl->target_mem_map);
731 wl->target_mem_map = NULL;
732
733 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734}
735
Arik Nemtsovb622d992011-02-23 00:22:31 +0200736static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
737{
738 bool fw_ps;
739
740 /* only regulate station links */
741 if (hlid < WL1271_AP_STA_HLID_START)
742 return;
743
744 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
745
746 /*
747 * Wake up from high level PS if the STA is asleep with too little
748 * blocks in FW or if the STA is awake.
749 */
750 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
751 wl1271_ps_link_end(wl, hlid);
752
753 /* Start high-level PS if the STA is asleep with enough blocks in FW */
754 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
755 wl1271_ps_link_start(wl, hlid, true);
756}
757
758static void wl1271_irq_update_links_status(struct wl1271 *wl,
759 struct wl1271_fw_ap_status *status)
760{
761 u32 cur_fw_ps_map;
762 u8 hlid;
763
764 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
765 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
766 wl1271_debug(DEBUG_PSM,
767 "link ps prev 0x%x cur 0x%x changed 0x%x",
768 wl->ap_fw_ps_map, cur_fw_ps_map,
769 wl->ap_fw_ps_map ^ cur_fw_ps_map);
770
771 wl->ap_fw_ps_map = cur_fw_ps_map;
772 }
773
774 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
775 u8 cnt = status->tx_lnk_free_blks[hlid] -
776 wl->links[hlid].prev_freed_blks;
777
778 wl->links[hlid].prev_freed_blks =
779 status->tx_lnk_free_blks[hlid];
780 wl->links[hlid].allocated_blks -= cnt;
781
782 wl1271_irq_ps_regulate_link(wl, hlid,
783 wl->links[hlid].allocated_blks);
784 }
785}
786
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300787static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200788 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200790 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200791 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200792 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200793 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300794 int i;
795
Shahar Levi13b107d2011-03-06 16:32:12 +0200796 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200797 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
798 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200799 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200800 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
801 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200802 }
803
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
805 "drv_rx_counter = %d, tx_results_counter = %d)",
806 status->intr,
807 status->fw_rx_counter,
808 status->drv_rx_counter,
809 status->tx_results_counter);
810
811 /* update number of available TX blocks */
812 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
814 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300815
816 wl->tx_blocks_freed[i] =
817 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200818 }
819
Ido Yarivd2f4d472011-03-31 10:07:00 +0200820 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200821
Ido Yarivd2f4d472011-03-31 10:07:00 +0200822 if (wl->bss_type == BSS_TYPE_AP_BSS) {
823 /* Update num of allocated TX blocks per link and ps status */
824 wl1271_irq_update_links_status(wl, &full_status->ap);
825 wl->tx_blocks_available += freed_blocks;
826 } else {
827 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
828
829 /*
830 * The FW might change the total number of TX memblocks before
831 * we get a notification about blocks being released. Thus, the
832 * available blocks calculation might yield a temporary result
833 * which is lower than the actual available blocks. Keeping in
834 * mind that only blocks that were allocated can be moved from
835 * TX to RX, tx_blocks_available should never decrease here.
836 */
837 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
838 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 }
840
Ido Yariva5225502010-10-12 14:49:10 +0200841 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200842 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200843 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844
845 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200846 getnstimeofday(&ts);
847 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
848 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849}
850
Ido Yariva6208652011-03-01 15:14:41 +0200851static void wl1271_flush_deferred_work(struct wl1271 *wl)
852{
853 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200854
Ido Yariva6208652011-03-01 15:14:41 +0200855 /* Pass all received frames to the network stack */
856 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
857 ieee80211_rx_ni(wl->hw, skb);
858
859 /* Return sent skbs to the network stack */
860 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
861 ieee80211_tx_status(wl->hw, skb);
862}
863
864static void wl1271_netstack_work(struct work_struct *work)
865{
866 struct wl1271 *wl =
867 container_of(work, struct wl1271, netstack_work);
868
869 do {
870 wl1271_flush_deferred_work(wl);
871 } while (skb_queue_len(&wl->deferred_rx_queue));
872}
873
874#define WL1271_IRQ_MAX_LOOPS 256
875
876irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300879 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200880 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200881 struct wl1271 *wl = (struct wl1271 *)cookie;
882 bool done = false;
883 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200884 unsigned long flags;
885
886 /* TX might be handled here, avoid redundant work */
887 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
888 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889
Ido Yariv341b7cd2011-03-31 10:07:01 +0200890 /*
891 * In case edge triggered interrupt must be used, we cannot iterate
892 * more than once without introducing race conditions with the hardirq.
893 */
894 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
895 loopcount = 1;
896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 mutex_lock(&wl->mutex);
898
899 wl1271_debug(DEBUG_IRQ, "IRQ work");
900
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200901 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 goto out;
903
Ido Yariva6208652011-03-01 15:14:41 +0200904 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905 if (ret < 0)
906 goto out;
907
Ido Yariva6208652011-03-01 15:14:41 +0200908 while (!done && loopcount--) {
909 /*
910 * In order to avoid a race with the hardirq, clear the flag
911 * before acknowledging the chip. Since the mutex is held,
912 * wl1271_ps_elp_wakeup cannot be called concurrently.
913 */
914 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
915 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200916
917 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200918 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200919 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200920 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200921 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200922 continue;
923 }
924
Eliad Pellerccc83b02010-10-27 14:09:57 +0200925 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
926 wl1271_error("watchdog interrupt received! "
927 "starting recovery.");
928 ieee80211_queue_work(wl->hw, &wl->recovery_work);
929
930 /* restarting the chip. ignore any other interrupt. */
931 goto out;
932 }
933
Ido Yariva6208652011-03-01 15:14:41 +0200934 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200935 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
936
Ido Yariv8aad2462011-03-01 15:14:38 +0200937 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200938
Ido Yariva5225502010-10-12 14:49:10 +0200939 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200941 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200942 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200943 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200944 /*
945 * In order to avoid starvation of the TX path,
946 * call the work function directly.
947 */
948 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200949 } else {
950 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200951 }
952
Ido Yariv8aad2462011-03-01 15:14:38 +0200953 /* check for tx results */
954 if (wl->fw_status->common.tx_results_counter !=
955 (wl->tx_results_count & 0xff))
956 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200957
958 /* Make sure the deferred queues don't get too long */
959 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
960 skb_queue_len(&wl->deferred_rx_queue);
961 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
962 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 }
964
965 if (intr & WL1271_ACX_INTR_EVENT_A) {
966 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
967 wl1271_event_handle(wl, 0);
968 }
969
970 if (intr & WL1271_ACX_INTR_EVENT_B) {
971 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
972 wl1271_event_handle(wl, 1);
973 }
974
975 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
976 wl1271_debug(DEBUG_IRQ,
977 "WL1271_ACX_INTR_INIT_COMPLETE");
978
979 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
980 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981 }
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 wl1271_ps_elp_sleep(wl);
984
985out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 spin_lock_irqsave(&wl->wl_lock, flags);
987 /* In case TX was not handled here, queue TX work */
988 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
989 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
990 wl->tx_queue_count)
991 ieee80211_queue_work(wl->hw, &wl->tx_work);
992 spin_unlock_irqrestore(&wl->wl_lock, flags);
993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200995
996 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997}
Ido Yariva6208652011-03-01 15:14:41 +0200998EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000static int wl1271_fetch_firmware(struct wl1271 *wl)
1001{
1002 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001003 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 int ret;
1005
Arik Nemtsov166d5042010-10-16 21:44:57 +02001006 switch (wl->bss_type) {
1007 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +02001008 if (wl->chip.id == CHIP_ID_1283_PG20)
1009 fw_name = WL128X_AP_FW_NAME;
1010 else
1011 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001012 break;
1013 case BSS_TYPE_IBSS:
1014 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +02001015 if (wl->chip.id == CHIP_ID_1283_PG20)
1016 fw_name = WL128X_FW_NAME;
1017 else
1018 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001019 break;
1020 default:
1021 wl1271_error("no compatible firmware for bss_type %d",
1022 wl->bss_type);
1023 return -EINVAL;
1024 }
1025
1026 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1027
1028 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029
1030 if (ret < 0) {
1031 wl1271_error("could not get firmware: %d", ret);
1032 return ret;
1033 }
1034
1035 if (fw->size % 4) {
1036 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1037 fw->size);
1038 ret = -EILSEQ;
1039 goto out;
1040 }
1041
Arik Nemtsov166d5042010-10-16 21:44:57 +02001042 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001044 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 if (!wl->fw) {
1047 wl1271_error("could not allocate memory for the firmware");
1048 ret = -ENOMEM;
1049 goto out;
1050 }
1051
1052 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +02001053 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 ret = 0;
1055
1056out:
1057 release_firmware(fw);
1058
1059 return ret;
1060}
1061
1062static int wl1271_fetch_nvs(struct wl1271 *wl)
1063{
1064 const struct firmware *fw;
1065 int ret;
1066
Shahar Levi5aa42342011-03-06 16:32:07 +02001067 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 if (ret < 0) {
1070 wl1271_error("could not get nvs file: %d", ret);
1071 return ret;
1072 }
1073
Shahar Levibc765bf2011-03-06 16:32:10 +02001074 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075
1076 if (!wl->nvs) {
1077 wl1271_error("could not allocate memory for the nvs file");
1078 ret = -ENOMEM;
1079 goto out;
1080 }
1081
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001082 wl->nvs_len = fw->size;
1083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084out:
1085 release_firmware(fw);
1086
1087 return ret;
1088}
1089
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001090static void wl1271_recovery_work(struct work_struct *work)
1091{
1092 struct wl1271 *wl =
1093 container_of(work, struct wl1271, recovery_work);
1094
1095 mutex_lock(&wl->mutex);
1096
1097 if (wl->state != WL1271_STATE_ON)
1098 goto out;
1099
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001100 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1101 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001102
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001103 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1104 ieee80211_connection_loss(wl->vif);
1105
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001106 /* Prevent spurious TX during FW restart */
1107 ieee80211_stop_queues(wl->hw);
1108
Luciano Coelho33c2c062011-05-10 14:46:02 +03001109 if (wl->sched_scanning) {
1110 ieee80211_sched_scan_stopped(wl->hw);
1111 wl->sched_scanning = false;
1112 }
1113
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001114 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001115 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001116 ieee80211_restart_hw(wl->hw);
1117
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001118 /*
1119 * Its safe to enable TX now - the queues are stopped after a request
1120 * to restart the HW.
1121 */
1122 ieee80211_wake_queues(wl->hw);
1123
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001124out:
1125 mutex_unlock(&wl->mutex);
1126}
1127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128static void wl1271_fw_wakeup(struct wl1271 *wl)
1129{
1130 u32 elp_reg;
1131
1132 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001133 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134}
1135
1136static int wl1271_setup(struct wl1271 *wl)
1137{
1138 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1139 if (!wl->fw_status)
1140 return -ENOMEM;
1141
1142 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1143 if (!wl->tx_res_if) {
1144 kfree(wl->fw_status);
1145 return -ENOMEM;
1146 }
1147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001148 return 0;
1149}
1150
1151static int wl1271_chip_wakeup(struct wl1271 *wl)
1152{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001153 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 int ret = 0;
1155
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001156 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001157 ret = wl1271_power_on(wl);
1158 if (ret < 0)
1159 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001161 wl1271_io_reset(wl);
1162 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163
1164 /* We don't need a real memory partition here, because we only want
1165 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001166 memset(&partition, 0, sizeof(partition));
1167 partition.reg.start = REGISTERS_BASE;
1168 partition.reg.size = REGISTERS_DOWN_SIZE;
1169 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
1171 /* ELP module wake up */
1172 wl1271_fw_wakeup(wl);
1173
1174 /* whal_FwCtrl_BootSm() */
1175
1176 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001177 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
1179 /* 1. check if chip id is valid */
1180
1181 switch (wl->chip.id) {
1182 case CHIP_ID_1271_PG10:
1183 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1184 wl->chip.id);
1185
1186 ret = wl1271_setup(wl);
1187 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001188 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 break;
1190 case CHIP_ID_1271_PG20:
1191 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1192 wl->chip.id);
1193
Shahar Levi0c005042011-06-12 10:34:43 +03001194 /*
1195 * 'end-of-transaction flag' and 'LPD mode flag'
1196 * should be set in wl127x AP mode only
1197 */
Shahar Levi564f5952011-04-04 10:20:39 +03001198 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001199 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1200 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202 ret = wl1271_setup(wl);
1203 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001204 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001206 case CHIP_ID_1283_PG20:
1207 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1208 wl->chip.id);
1209
1210 ret = wl1271_setup(wl);
1211 if (ret < 0)
1212 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001213
Ido Yariv0da13da2011-03-31 10:06:58 +02001214 if (wl1271_set_block_size(wl))
1215 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001216 break;
1217 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001219 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001221 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222 }
1223
Arik Nemtsov166d5042010-10-16 21:44:57 +02001224 /* Make sure the firmware type matches the BSS type */
1225 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 ret = wl1271_fetch_firmware(wl);
1227 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001228 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 }
1230
1231 /* No NVS from netlink, try to get it from the filesystem */
1232 if (wl->nvs == NULL) {
1233 ret = wl1271_fetch_nvs(wl);
1234 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001235 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236 }
1237
1238out:
1239 return ret;
1240}
1241
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001242static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1243{
1244 unsigned int quirks = 0;
1245 unsigned int *fw_ver = wl->chip.fw_ver;
1246
1247 /* Only for wl127x */
1248 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1249 /* Check STA version */
1250 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1251 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1252 /* Check AP version */
1253 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1254 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1255 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1256
1257 return quirks;
1258}
1259
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260int wl1271_plt_start(struct wl1271 *wl)
1261{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001262 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 int ret;
1264
1265 mutex_lock(&wl->mutex);
1266
1267 wl1271_notice("power up");
1268
1269 if (wl->state != WL1271_STATE_OFF) {
1270 wl1271_error("cannot go into PLT state because not "
1271 "in off state: %d", wl->state);
1272 ret = -EBUSY;
1273 goto out;
1274 }
1275
Arik Nemtsov166d5042010-10-16 21:44:57 +02001276 wl->bss_type = BSS_TYPE_STA_BSS;
1277
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001278 while (retries) {
1279 retries--;
1280 ret = wl1271_chip_wakeup(wl);
1281 if (ret < 0)
1282 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001284 ret = wl1271_boot(wl);
1285 if (ret < 0)
1286 goto power_off;
1287
1288 ret = wl1271_plt_init(wl);
1289 if (ret < 0)
1290 goto irq_disable;
1291
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001292 wl->state = WL1271_STATE_PLT;
1293 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001294 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001295
1296 /* Check if any quirks are needed with older fw versions */
1297 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 goto out;
1299
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001300irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001301 mutex_unlock(&wl->mutex);
1302 /* Unlocking the mutex in the middle of handling is
1303 inherently unsafe. In this case we deem it safe to do,
1304 because we need to let any possibly pending IRQ out of
1305 the system (and while we are WL1271_STATE_OFF the IRQ
1306 work function will not do anything.) Also, any other
1307 possible concurrent operations will fail due to the
1308 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001309 wl1271_disable_interrupts(wl);
1310 wl1271_flush_deferred_work(wl);
1311 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001312 mutex_lock(&wl->mutex);
1313power_off:
1314 wl1271_power_off(wl);
1315 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001317 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1318 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319out:
1320 mutex_unlock(&wl->mutex);
1321
1322 return ret;
1323}
1324
Luciano Coelho4623ec72011-03-21 19:26:41 +02001325static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326{
1327 int ret = 0;
1328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 wl1271_notice("power down");
1330
1331 if (wl->state != WL1271_STATE_PLT) {
1332 wl1271_error("cannot power down because not in PLT "
1333 "state: %d", wl->state);
1334 ret = -EBUSY;
1335 goto out;
1336 }
1337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 wl1271_power_off(wl);
1339
1340 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001341 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001344 wl1271_disable_interrupts(wl);
1345 wl1271_flush_deferred_work(wl);
1346 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001347 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001348 mutex_lock(&wl->mutex);
1349out:
1350 return ret;
1351}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001352
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001353int wl1271_plt_stop(struct wl1271 *wl)
1354{
1355 int ret;
1356
1357 mutex_lock(&wl->mutex);
1358 ret = __wl1271_plt_stop(wl);
1359 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 return ret;
1361}
1362
Johannes Berg7bb45682011-02-24 14:42:06 +01001363static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364{
1365 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001366 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001367 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001368 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369
Ido Yarivb07d4032011-03-01 15:14:43 +02001370 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1371
1372 if (wl->bss_type == BSS_TYPE_AP_BSS)
1373 hlid = wl1271_tx_get_hlid(skb);
1374
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001375 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001376
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001377 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001378
1379 /*
1380 * The workqueue is slow to process the tx_queue and we need stop
1381 * the queue here, otherwise the queue will get too long.
1382 */
1383 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1384 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1385 ieee80211_stop_queues(wl->hw);
1386 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1387 }
1388
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001389 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001390 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001391 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1392 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1393 } else {
1394 skb_queue_tail(&wl->tx_queue[q], skb);
1395 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396
1397 /*
1398 * The chip specific setup must run before the first TX packet -
1399 * before that, the tx_work will not be initialized!
1400 */
1401
Ido Yarivb07d4032011-03-01 15:14:43 +02001402 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1403 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001404 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001405
1406 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407}
1408
Shahar Leviae47c452011-03-06 16:32:14 +02001409int wl1271_tx_dummy_packet(struct wl1271 *wl)
1410{
Ido Yariv990f5de2011-03-31 10:06:59 +02001411 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001412
Ido Yariv990f5de2011-03-31 10:06:59 +02001413 spin_lock_irqsave(&wl->wl_lock, flags);
1414 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1415 wl->tx_queue_count++;
1416 spin_unlock_irqrestore(&wl->wl_lock, flags);
1417
1418 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1419 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1420 wl1271_tx_work_locked(wl);
1421
1422 /*
1423 * If the FW TX is busy, TX work will be scheduled by the threaded
1424 * interrupt handler function
1425 */
1426 return 0;
1427}
1428
1429/*
1430 * The size of the dummy packet should be at least 1400 bytes. However, in
1431 * order to minimize the number of bus transactions, aligning it to 512 bytes
1432 * boundaries could be beneficial, performance wise
1433 */
1434#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1435
Luciano Coelhocf27d862011-04-01 21:08:23 +03001436static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001437{
1438 struct sk_buff *skb;
1439 struct ieee80211_hdr_3addr *hdr;
1440 unsigned int dummy_packet_size;
1441
1442 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1443 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1444
1445 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001446 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001447 wl1271_warning("Failed to allocate a dummy packet skb");
1448 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001449 }
1450
1451 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1452
1453 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1454 memset(hdr, 0, sizeof(*hdr));
1455 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001456 IEEE80211_STYPE_NULLFUNC |
1457 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001458
Ido Yariv990f5de2011-03-31 10:06:59 +02001459 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001460
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001461 /* Dummy packets require the TID to be management */
1462 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001463
1464 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001465 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001466 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001467
Ido Yariv990f5de2011-03-31 10:06:59 +02001468 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001469}
1470
Ido Yariv990f5de2011-03-31 10:06:59 +02001471
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001472static struct notifier_block wl1271_dev_notifier = {
1473 .notifier_call = wl1271_dev_notify,
1474};
1475
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001476#ifdef CONFIG_PM
Eliad Peller94390642011-05-13 11:57:13 +03001477static int wl1271_configure_suspend(struct wl1271 *wl)
1478{
1479 int ret;
1480
1481 if (wl->bss_type != BSS_TYPE_STA_BSS)
1482 return 0;
1483
1484 mutex_lock(&wl->mutex);
1485
1486 ret = wl1271_ps_elp_wakeup(wl);
1487 if (ret < 0)
1488 goto out_unlock;
1489
1490 /* enter psm if needed*/
1491 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1492 DECLARE_COMPLETION_ONSTACK(compl);
1493
1494 wl->ps_compl = &compl;
1495 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1496 wl->basic_rate, true);
1497 if (ret < 0)
1498 goto out_sleep;
1499
1500 /* we must unlock here so we will be able to get events */
1501 wl1271_ps_elp_sleep(wl);
1502 mutex_unlock(&wl->mutex);
1503
1504 ret = wait_for_completion_timeout(
1505 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1506 if (ret <= 0) {
1507 wl1271_warning("couldn't enter ps mode!");
1508 ret = -EBUSY;
1509 goto out;
1510 }
1511
1512 /* take mutex again, and wakeup */
1513 mutex_lock(&wl->mutex);
1514
1515 ret = wl1271_ps_elp_wakeup(wl);
1516 if (ret < 0)
1517 goto out_unlock;
1518 }
1519out_sleep:
1520 wl1271_ps_elp_sleep(wl);
1521out_unlock:
1522 mutex_unlock(&wl->mutex);
1523out:
1524 return ret;
1525
1526}
1527
1528static void wl1271_configure_resume(struct wl1271 *wl)
1529{
1530 int ret;
1531
1532 if (wl->bss_type != BSS_TYPE_STA_BSS)
1533 return;
1534
1535 mutex_lock(&wl->mutex);
1536 ret = wl1271_ps_elp_wakeup(wl);
1537 if (ret < 0)
1538 goto out;
1539
1540 /* exit psm if it wasn't configured */
1541 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1542 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1543 wl->basic_rate, true);
1544
1545 wl1271_ps_elp_sleep(wl);
1546out:
1547 mutex_unlock(&wl->mutex);
1548}
1549
Eliad Peller402e48612011-05-13 11:57:09 +03001550static int wl1271_op_suspend(struct ieee80211_hw *hw,
1551 struct cfg80211_wowlan *wow)
1552{
1553 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001554 int ret;
1555
Eliad Peller402e48612011-05-13 11:57:09 +03001556 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001557 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001558
Eliad Peller4a859df2011-06-06 12:21:52 +03001559 wl->wow_enabled = true;
1560 ret = wl1271_configure_suspend(wl);
1561 if (ret < 0) {
1562 wl1271_warning("couldn't prepare device to suspend");
1563 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001564 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001565 /* flush any remaining work */
1566 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1567 flush_delayed_work(&wl->scan_complete_work);
1568
1569 /*
1570 * disable and re-enable interrupts in order to flush
1571 * the threaded_irq
1572 */
1573 wl1271_disable_interrupts(wl);
1574
1575 /*
1576 * set suspended flag to avoid triggering a new threaded_irq
1577 * work. no need for spinlock as interrupts are disabled.
1578 */
1579 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1580
1581 wl1271_enable_interrupts(wl);
1582 flush_work(&wl->tx_work);
1583 flush_delayed_work(&wl->pspoll_work);
1584 flush_delayed_work(&wl->elp_work);
1585
Eliad Peller402e48612011-05-13 11:57:09 +03001586 return 0;
1587}
1588
1589static int wl1271_op_resume(struct ieee80211_hw *hw)
1590{
1591 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001592 unsigned long flags;
1593 bool run_irq_work = false;
1594
Eliad Peller402e48612011-05-13 11:57:09 +03001595 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1596 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001597 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001598
1599 /*
1600 * re-enable irq_work enqueuing, and call irq_work directly if
1601 * there is a pending work.
1602 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001603 spin_lock_irqsave(&wl->wl_lock, flags);
1604 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1605 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1606 run_irq_work = true;
1607 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001608
Eliad Peller4a859df2011-06-06 12:21:52 +03001609 if (run_irq_work) {
1610 wl1271_debug(DEBUG_MAC80211,
1611 "run postponed irq_work directly");
1612 wl1271_irq(0, wl);
1613 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001614 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001615 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001616 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001617
Eliad Peller402e48612011-05-13 11:57:09 +03001618 return 0;
1619}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001620#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001621
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001622static int wl1271_op_start(struct ieee80211_hw *hw)
1623{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001624 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1625
1626 /*
1627 * We have to delay the booting of the hardware because
1628 * we need to know the local MAC address before downloading and
1629 * initializing the firmware. The MAC address cannot be changed
1630 * after boot, and without the proper MAC address, the firmware
1631 * will not function properly.
1632 *
1633 * The MAC address is first known when the corresponding interface
1634 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001635 *
1636 * In addition, we currently have different firmwares for AP and managed
1637 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001638 */
1639
1640 return 0;
1641}
1642
1643static void wl1271_op_stop(struct ieee80211_hw *hw)
1644{
1645 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1646}
1647
1648static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1649 struct ieee80211_vif *vif)
1650{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001651 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001652 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001653 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001654 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001655 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001657 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1658 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659
1660 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001661 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001662 wl1271_debug(DEBUG_MAC80211,
1663 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001664 ret = -EBUSY;
1665 goto out;
1666 }
1667
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001668 /*
1669 * in some very corner case HW recovery scenarios its possible to
1670 * get here before __wl1271_op_remove_interface is complete, so
1671 * opt out if that is the case.
1672 */
1673 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1674 ret = -EBUSY;
1675 goto out;
1676 }
1677
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001678 switch (vif->type) {
1679 case NL80211_IFTYPE_STATION:
1680 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001681 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001682 break;
1683 case NL80211_IFTYPE_ADHOC:
1684 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001685 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001686 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001687 case NL80211_IFTYPE_AP:
1688 wl->bss_type = BSS_TYPE_AP_BSS;
1689 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001690 default:
1691 ret = -EOPNOTSUPP;
1692 goto out;
1693 }
1694
1695 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696
1697 if (wl->state != WL1271_STATE_OFF) {
1698 wl1271_error("cannot start because not in off state: %d",
1699 wl->state);
1700 ret = -EBUSY;
1701 goto out;
1702 }
1703
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001704 while (retries) {
1705 retries--;
1706 ret = wl1271_chip_wakeup(wl);
1707 if (ret < 0)
1708 goto power_off;
1709
1710 ret = wl1271_boot(wl);
1711 if (ret < 0)
1712 goto power_off;
1713
1714 ret = wl1271_hw_init(wl);
1715 if (ret < 0)
1716 goto irq_disable;
1717
Eliad Peller71125ab2010-10-28 21:46:43 +02001718 booted = true;
1719 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001721irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001722 mutex_unlock(&wl->mutex);
1723 /* Unlocking the mutex in the middle of handling is
1724 inherently unsafe. In this case we deem it safe to do,
1725 because we need to let any possibly pending IRQ out of
1726 the system (and while we are WL1271_STATE_OFF the IRQ
1727 work function will not do anything.) Also, any other
1728 possible concurrent operations will fail due to the
1729 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001730 wl1271_disable_interrupts(wl);
1731 wl1271_flush_deferred_work(wl);
1732 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001733 mutex_lock(&wl->mutex);
1734power_off:
1735 wl1271_power_off(wl);
1736 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001737
Eliad Peller71125ab2010-10-28 21:46:43 +02001738 if (!booted) {
1739 wl1271_error("firmware boot failed despite %d retries",
1740 WL1271_BOOT_RETRIES);
1741 goto out;
1742 }
1743
1744 wl->vif = vif;
1745 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001746 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001747 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001748
1749 /* update hw/fw version info in wiphy struct */
1750 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001751 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001752 sizeof(wiphy->fw_version));
1753
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001754 /* Check if any quirks are needed with older fw versions */
1755 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1756
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001757 /*
1758 * Now we know if 11a is supported (info from the NVS), so disable
1759 * 11a channels if not supported
1760 */
1761 if (!wl->enable_11a)
1762 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1763
1764 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1765 wl->enable_11a ? "" : "not ");
1766
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001767out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768 mutex_unlock(&wl->mutex);
1769
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001770 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001771 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001772 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001773 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001774
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775 return ret;
1776}
1777
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001778static void __wl1271_op_remove_interface(struct wl1271 *wl,
1779 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001781 int i;
1782
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001783 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001784
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001785 /* because of hardware recovery, we may get here twice */
1786 if (wl->state != WL1271_STATE_ON)
1787 return;
1788
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001789 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001790
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001791 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001792 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001793 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001794
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001795 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001796 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001797 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001798
Luciano Coelho08688d62010-07-08 17:50:07 +03001799 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001800 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001801 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001802 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001803 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804 }
1805
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001806 /*
1807 * this must be before the cancel_work calls below, so that the work
1808 * functions don't perform further work.
1809 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001810 wl->state = WL1271_STATE_OFF;
1811
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812 mutex_unlock(&wl->mutex);
1813
Ido Yariva6208652011-03-01 15:14:41 +02001814 wl1271_disable_interrupts(wl);
1815 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001816 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001817 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03001819 del_timer_sync(&wl->rx_streaming_timer);
1820 cancel_work_sync(&wl->rx_streaming_enable_work);
1821 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001822 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001823 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824
1825 mutex_lock(&wl->mutex);
1826
1827 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001828 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829 wl1271_power_off(wl);
1830
1831 memset(wl->bssid, 0, ETH_ALEN);
1832 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1833 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001834 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001835 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001836 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837
1838 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001839 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001840 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1841 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001842 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 wl->tx_results_count = 0;
1844 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001845 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001846 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 wl->time_offset = 0;
1848 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001849 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001850 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001851 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001852 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001853 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001854 wl->ap_fw_ps_map = 0;
1855 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001856 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001857
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001858 /*
1859 * this is performed after the cancel_work calls and the associated
1860 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1861 * get executed before all these vars have been reset.
1862 */
1863 wl->flags = 0;
1864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 for (i = 0; i < NUM_TX_QUEUES; i++)
1866 wl->tx_blocks_freed[i] = 0;
1867
1868 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001869
1870 kfree(wl->fw_status);
1871 wl->fw_status = NULL;
1872 kfree(wl->tx_res_if);
1873 wl->tx_res_if = NULL;
1874 kfree(wl->target_mem_map);
1875 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001876}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001877
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001878static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1879 struct ieee80211_vif *vif)
1880{
1881 struct wl1271 *wl = hw->priv;
1882
1883 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001884 /*
1885 * wl->vif can be null here if someone shuts down the interface
1886 * just when hardware recovery has been started.
1887 */
1888 if (wl->vif) {
1889 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001890 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001891 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001892
Juuso Oikarinen67353292010-11-18 15:19:02 +02001893 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001894 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895}
1896
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001897void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001898{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001899 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001900
1901 /* combine requested filters with current filter config */
1902 filters = wl->filters | filters;
1903
1904 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1905
1906 if (filters & FIF_PROMISC_IN_BSS) {
1907 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1908 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1909 wl->rx_config |= CFG_BSSID_FILTER_EN;
1910 }
1911 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1912 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1913 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1914 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1915 }
1916 if (filters & FIF_OTHER_BSS) {
1917 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1918 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1919 }
1920 if (filters & FIF_CONTROL) {
1921 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1922 wl->rx_filter |= CFG_RX_CTL_EN;
1923 }
1924 if (filters & FIF_FCSFAIL) {
1925 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1926 wl->rx_filter |= CFG_RX_FCS_ERROR;
1927 }
1928}
1929
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001930static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001931{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001932 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001933 /* we need to use a dummy BSSID for now */
1934 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1935 0xad, 0xbe, 0xef };
1936
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001937 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1938
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001939 /* pass through frames from all BSS */
1940 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1941
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001942 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001943 if (ret < 0)
1944 goto out;
1945
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001946 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001947
1948out:
1949 return ret;
1950}
1951
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001952static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001953{
1954 int ret;
1955
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001956 /*
1957 * One of the side effects of the JOIN command is that is clears
1958 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1959 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001960 * Currently the only valid scenario for JOIN during association
1961 * is on roaming, in which case we will also be given new keys.
1962 * Keep the below message for now, unless it starts bothering
1963 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001964 */
1965 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1966 wl1271_info("JOIN while associated.");
1967
1968 if (set_assoc)
1969 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1970
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001971 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1972 if (ret < 0)
1973 goto out;
1974
1975 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1976
1977 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1978 goto out;
1979
1980 /*
1981 * The join command disable the keep-alive mode, shut down its process,
1982 * and also clear the template config, so we need to reset it all after
1983 * the join. The acx_aid starts the keep-alive process, and the order
1984 * of the commands below is relevant.
1985 */
1986 ret = wl1271_acx_keep_alive_mode(wl, true);
1987 if (ret < 0)
1988 goto out;
1989
1990 ret = wl1271_acx_aid(wl, wl->aid);
1991 if (ret < 0)
1992 goto out;
1993
1994 ret = wl1271_cmd_build_klv_null_data(wl);
1995 if (ret < 0)
1996 goto out;
1997
1998 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1999 ACX_KEEP_ALIVE_TPL_VALID);
2000 if (ret < 0)
2001 goto out;
2002
2003out:
2004 return ret;
2005}
2006
2007static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002008{
2009 int ret;
2010
2011 /* to stop listening to a channel, we disconnect */
2012 ret = wl1271_cmd_disconnect(wl);
2013 if (ret < 0)
2014 goto out;
2015
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002016 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002017 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002018
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02002019 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002020 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002021
2022out:
2023 return ret;
2024}
2025
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002026static void wl1271_set_band_rate(struct wl1271 *wl)
2027{
2028 if (wl->band == IEEE80211_BAND_2GHZ)
2029 wl->basic_rate_set = wl->conf.tx.basic_rate;
2030 else
2031 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2032}
2033
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002034static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002035{
2036 int ret;
2037
2038 if (idle) {
2039 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2040 ret = wl1271_unjoin(wl);
2041 if (ret < 0)
2042 goto out;
2043 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002044 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002045 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002046 if (ret < 0)
2047 goto out;
2048 ret = wl1271_acx_keep_alive_config(
2049 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2050 ACX_KEEP_ALIVE_TPL_INVALID);
2051 if (ret < 0)
2052 goto out;
2053 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2054 } else {
2055 /* increment the session counter */
2056 wl->session_counter++;
2057 if (wl->session_counter >= SESSION_COUNTER_MAX)
2058 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002059
2060 /* The current firmware only supports sched_scan in idle */
2061 if (wl->sched_scanning) {
2062 wl1271_scan_sched_scan_stop(wl);
2063 ieee80211_sched_scan_stopped(wl->hw);
2064 }
2065
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002066 ret = wl1271_dummy_join(wl);
2067 if (ret < 0)
2068 goto out;
2069 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2070 }
2071
2072out:
2073 return ret;
2074}
2075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2077{
2078 struct wl1271 *wl = hw->priv;
2079 struct ieee80211_conf *conf = &hw->conf;
2080 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002081 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082
2083 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2084
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002085 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2086 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087 channel,
2088 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002089 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002090 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2091 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002092
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002093 /*
2094 * mac80211 will go to idle nearly immediately after transmitting some
2095 * frames, such as the deauth. To make sure those frames reach the air,
2096 * wait here until the TX queue is fully flushed.
2097 */
2098 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2099 (conf->flags & IEEE80211_CONF_IDLE))
2100 wl1271_tx_flush(wl);
2101
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002102 mutex_lock(&wl->mutex);
2103
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002104 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002105 /* we support configuring the channel and band while off */
2106 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2107 wl->band = conf->channel->band;
2108 wl->channel = channel;
2109 }
2110
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002111 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002112 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002113
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002114 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2115
Ido Yariva6208652011-03-01 15:14:41 +02002116 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117 if (ret < 0)
2118 goto out;
2119
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002120 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002121 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2122 ((wl->band != conf->channel->band) ||
2123 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002124 wl->band = conf->channel->band;
2125 wl->channel = channel;
2126
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002127 if (!is_ap) {
2128 /*
2129 * FIXME: the mac80211 should really provide a fixed
2130 * rate to use here. for now, just use the smallest
2131 * possible rate for the band as a fixed rate for
2132 * association frames and other control messages.
2133 */
2134 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2135 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002136
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002137 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2138 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002139 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002140 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002141 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002142
2143 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2144 ret = wl1271_join(wl, false);
2145 if (ret < 0)
2146 wl1271_warning("cmd join on channel "
2147 "failed %d", ret);
2148 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002149 }
2150 }
2151
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002152 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2153 ret = wl1271_sta_handle_idle(wl,
2154 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002155 if (ret < 0)
2156 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002157 }
2158
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002159 /*
2160 * if mac80211 changes the PSM mode, make sure the mode is not
2161 * incorrectly changed after the pspoll failure active window.
2162 */
2163 if (changed & IEEE80211_CONF_CHANGE_PS)
2164 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2165
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002166 if (conf->flags & IEEE80211_CONF_PS &&
2167 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2168 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169
2170 /*
2171 * We enter PSM only if we're already associated.
2172 * If we're not, we'll enter it when joining an SSID,
2173 * through the bss_info_changed() hook.
2174 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002175 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002176 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002177 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002178 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002179 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002181 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002182 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002184 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002185
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002186 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002187 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002188 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189 }
2190
2191 if (conf->power_level != wl->power_level) {
2192 ret = wl1271_acx_tx_power(wl, conf->power_level);
2193 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002194 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195
2196 wl->power_level = conf->power_level;
2197 }
2198
2199out_sleep:
2200 wl1271_ps_elp_sleep(wl);
2201
2202out:
2203 mutex_unlock(&wl->mutex);
2204
2205 return ret;
2206}
2207
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002208struct wl1271_filter_params {
2209 bool enabled;
2210 int mc_list_length;
2211 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2212};
2213
Jiri Pirko22bedad2010-04-01 21:22:57 +00002214static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2215 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002216{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002217 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002218 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002219 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002220
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002221 if (unlikely(wl->state == WL1271_STATE_OFF))
2222 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002223
Juuso Oikarinen74441132009-10-13 12:47:53 +03002224 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002225 if (!fp) {
2226 wl1271_error("Out of memory setting filters.");
2227 return 0;
2228 }
2229
2230 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002231 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002232 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2233 fp->enabled = false;
2234 } else {
2235 fp->enabled = true;
2236 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002237 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002238 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002239 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002240 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002241 }
2242
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002243 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002244}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002245
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002246#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2247 FIF_ALLMULTI | \
2248 FIF_FCSFAIL | \
2249 FIF_BCN_PRBRESP_PROMISC | \
2250 FIF_CONTROL | \
2251 FIF_OTHER_BSS)
2252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002253static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2254 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002255 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002256{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002257 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002259 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002260
Arik Nemtsov7d057862010-10-16 19:25:35 +02002261 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2262 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002263
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002264 mutex_lock(&wl->mutex);
2265
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002266 *total &= WL1271_SUPPORTED_FILTERS;
2267 changed &= WL1271_SUPPORTED_FILTERS;
2268
2269 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002270 goto out;
2271
Ido Yariva6208652011-03-01 15:14:41 +02002272 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002273 if (ret < 0)
2274 goto out;
2275
Arik Nemtsov7d057862010-10-16 19:25:35 +02002276 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2277 if (*total & FIF_ALLMULTI)
2278 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2279 else if (fp)
2280 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2281 fp->mc_list,
2282 fp->mc_list_length);
2283 if (ret < 0)
2284 goto out_sleep;
2285 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002286
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002287 /* determine, whether supported filter values have changed */
2288 if (changed == 0)
2289 goto out_sleep;
2290
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002291 /* configure filters */
2292 wl->filters = *total;
2293 wl1271_configure_filters(wl, 0);
2294
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002295 /* apply configured filters */
2296 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2297 if (ret < 0)
2298 goto out_sleep;
2299
2300out_sleep:
2301 wl1271_ps_elp_sleep(wl);
2302
2303out:
2304 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002305 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306}
2307
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002308static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2309 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2310 u16 tx_seq_16)
2311{
2312 struct wl1271_ap_key *ap_key;
2313 int i;
2314
2315 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2316
2317 if (key_size > MAX_KEY_SIZE)
2318 return -EINVAL;
2319
2320 /*
2321 * Find next free entry in ap_keys. Also check we are not replacing
2322 * an existing key.
2323 */
2324 for (i = 0; i < MAX_NUM_KEYS; i++) {
2325 if (wl->recorded_ap_keys[i] == NULL)
2326 break;
2327
2328 if (wl->recorded_ap_keys[i]->id == id) {
2329 wl1271_warning("trying to record key replacement");
2330 return -EINVAL;
2331 }
2332 }
2333
2334 if (i == MAX_NUM_KEYS)
2335 return -EBUSY;
2336
2337 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2338 if (!ap_key)
2339 return -ENOMEM;
2340
2341 ap_key->id = id;
2342 ap_key->key_type = key_type;
2343 ap_key->key_size = key_size;
2344 memcpy(ap_key->key, key, key_size);
2345 ap_key->hlid = hlid;
2346 ap_key->tx_seq_32 = tx_seq_32;
2347 ap_key->tx_seq_16 = tx_seq_16;
2348
2349 wl->recorded_ap_keys[i] = ap_key;
2350 return 0;
2351}
2352
2353static void wl1271_free_ap_keys(struct wl1271 *wl)
2354{
2355 int i;
2356
2357 for (i = 0; i < MAX_NUM_KEYS; i++) {
2358 kfree(wl->recorded_ap_keys[i]);
2359 wl->recorded_ap_keys[i] = NULL;
2360 }
2361}
2362
2363static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2364{
2365 int i, ret = 0;
2366 struct wl1271_ap_key *key;
2367 bool wep_key_added = false;
2368
2369 for (i = 0; i < MAX_NUM_KEYS; i++) {
2370 if (wl->recorded_ap_keys[i] == NULL)
2371 break;
2372
2373 key = wl->recorded_ap_keys[i];
2374 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2375 key->id, key->key_type,
2376 key->key_size, key->key,
2377 key->hlid, key->tx_seq_32,
2378 key->tx_seq_16);
2379 if (ret < 0)
2380 goto out;
2381
2382 if (key->key_type == KEY_WEP)
2383 wep_key_added = true;
2384 }
2385
2386 if (wep_key_added) {
2387 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2388 if (ret < 0)
2389 goto out;
2390 }
2391
2392out:
2393 wl1271_free_ap_keys(wl);
2394 return ret;
2395}
2396
2397static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2398 u8 key_size, const u8 *key, u32 tx_seq_32,
2399 u16 tx_seq_16, struct ieee80211_sta *sta)
2400{
2401 int ret;
2402 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2403
2404 if (is_ap) {
2405 struct wl1271_station *wl_sta;
2406 u8 hlid;
2407
2408 if (sta) {
2409 wl_sta = (struct wl1271_station *)sta->drv_priv;
2410 hlid = wl_sta->hlid;
2411 } else {
2412 hlid = WL1271_AP_BROADCAST_HLID;
2413 }
2414
2415 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2416 /*
2417 * We do not support removing keys after AP shutdown.
2418 * Pretend we do to make mac80211 happy.
2419 */
2420 if (action != KEY_ADD_OR_REPLACE)
2421 return 0;
2422
2423 ret = wl1271_record_ap_key(wl, id,
2424 key_type, key_size,
2425 key, hlid, tx_seq_32,
2426 tx_seq_16);
2427 } else {
2428 ret = wl1271_cmd_set_ap_key(wl, action,
2429 id, key_type, key_size,
2430 key, hlid, tx_seq_32,
2431 tx_seq_16);
2432 }
2433
2434 if (ret < 0)
2435 return ret;
2436 } else {
2437 const u8 *addr;
2438 static const u8 bcast_addr[ETH_ALEN] = {
2439 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2440 };
2441
2442 addr = sta ? sta->addr : bcast_addr;
2443
2444 if (is_zero_ether_addr(addr)) {
2445 /* We dont support TX only encryption */
2446 return -EOPNOTSUPP;
2447 }
2448
2449 /* The wl1271 does not allow to remove unicast keys - they
2450 will be cleared automatically on next CMD_JOIN. Ignore the
2451 request silently, as we dont want the mac80211 to emit
2452 an error message. */
2453 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2454 return 0;
2455
2456 ret = wl1271_cmd_set_sta_key(wl, action,
2457 id, key_type, key_size,
2458 key, addr, tx_seq_32,
2459 tx_seq_16);
2460 if (ret < 0)
2461 return ret;
2462
2463 /* the default WEP key needs to be configured at least once */
2464 if (key_type == KEY_WEP) {
2465 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2466 wl->default_key);
2467 if (ret < 0)
2468 return ret;
2469 }
2470 }
2471
2472 return 0;
2473}
2474
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002475static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2476 struct ieee80211_vif *vif,
2477 struct ieee80211_sta *sta,
2478 struct ieee80211_key_conf *key_conf)
2479{
2480 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002482 u32 tx_seq_32 = 0;
2483 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002484 u8 key_type;
2485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002486 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2487
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002488 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002489 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002490 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002491 key_conf->keylen, key_conf->flags);
2492 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2493
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002494 mutex_lock(&wl->mutex);
2495
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002496 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2497 ret = -EAGAIN;
2498 goto out_unlock;
2499 }
2500
Ido Yariva6208652011-03-01 15:14:41 +02002501 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002502 if (ret < 0)
2503 goto out_unlock;
2504
Johannes Berg97359d12010-08-10 09:46:38 +02002505 switch (key_conf->cipher) {
2506 case WLAN_CIPHER_SUITE_WEP40:
2507 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508 key_type = KEY_WEP;
2509
2510 key_conf->hw_key_idx = key_conf->keyidx;
2511 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002512 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 key_type = KEY_TKIP;
2514
2515 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002516 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2517 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002519 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520 key_type = KEY_AES;
2521
2522 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002523 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2524 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002526 case WL1271_CIPHER_SUITE_GEM:
2527 key_type = KEY_GEM;
2528 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2529 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2530 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002532 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533
2534 ret = -EOPNOTSUPP;
2535 goto out_sleep;
2536 }
2537
2538 switch (cmd) {
2539 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002540 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2541 key_conf->keyidx, key_type,
2542 key_conf->keylen, key_conf->key,
2543 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 if (ret < 0) {
2545 wl1271_error("Could not add or replace key");
2546 goto out_sleep;
2547 }
2548 break;
2549
2550 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002551 ret = wl1271_set_key(wl, KEY_REMOVE,
2552 key_conf->keyidx, key_type,
2553 key_conf->keylen, key_conf->key,
2554 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002555 if (ret < 0) {
2556 wl1271_error("Could not remove key");
2557 goto out_sleep;
2558 }
2559 break;
2560
2561 default:
2562 wl1271_error("Unsupported key cmd 0x%x", cmd);
2563 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002564 break;
2565 }
2566
2567out_sleep:
2568 wl1271_ps_elp_sleep(wl);
2569
2570out_unlock:
2571 mutex_unlock(&wl->mutex);
2572
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002573 return ret;
2574}
2575
2576static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002577 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578 struct cfg80211_scan_request *req)
2579{
2580 struct wl1271 *wl = hw->priv;
2581 int ret;
2582 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002583 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584
2585 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2586
2587 if (req->n_ssids) {
2588 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002589 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002590 }
2591
2592 mutex_lock(&wl->mutex);
2593
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002594 if (wl->state == WL1271_STATE_OFF) {
2595 /*
2596 * We cannot return -EBUSY here because cfg80211 will expect
2597 * a call to ieee80211_scan_completed if we do - in this case
2598 * there won't be any call.
2599 */
2600 ret = -EAGAIN;
2601 goto out;
2602 }
2603
Ido Yariva6208652011-03-01 15:14:41 +02002604 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 if (ret < 0)
2606 goto out;
2607
Luciano Coelho5924f892010-08-04 03:46:22 +03002608 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002609
2610 wl1271_ps_elp_sleep(wl);
2611
2612out:
2613 mutex_unlock(&wl->mutex);
2614
2615 return ret;
2616}
2617
Luciano Coelho33c2c062011-05-10 14:46:02 +03002618static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2619 struct ieee80211_vif *vif,
2620 struct cfg80211_sched_scan_request *req,
2621 struct ieee80211_sched_scan_ies *ies)
2622{
2623 struct wl1271 *wl = hw->priv;
2624 int ret;
2625
2626 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2627
2628 mutex_lock(&wl->mutex);
2629
2630 ret = wl1271_ps_elp_wakeup(wl);
2631 if (ret < 0)
2632 goto out;
2633
2634 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2635 if (ret < 0)
2636 goto out_sleep;
2637
2638 ret = wl1271_scan_sched_scan_start(wl);
2639 if (ret < 0)
2640 goto out_sleep;
2641
2642 wl->sched_scanning = true;
2643
2644out_sleep:
2645 wl1271_ps_elp_sleep(wl);
2646out:
2647 mutex_unlock(&wl->mutex);
2648 return ret;
2649}
2650
2651static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2652 struct ieee80211_vif *vif)
2653{
2654 struct wl1271 *wl = hw->priv;
2655 int ret;
2656
2657 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2658
2659 mutex_lock(&wl->mutex);
2660
2661 ret = wl1271_ps_elp_wakeup(wl);
2662 if (ret < 0)
2663 goto out;
2664
2665 wl1271_scan_sched_scan_stop(wl);
2666
2667 wl1271_ps_elp_sleep(wl);
2668out:
2669 mutex_unlock(&wl->mutex);
2670}
2671
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002672static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2673{
2674 struct wl1271 *wl = hw->priv;
2675 int ret = 0;
2676
2677 mutex_lock(&wl->mutex);
2678
2679 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2680 ret = -EAGAIN;
2681 goto out;
2682 }
2683
Ido Yariva6208652011-03-01 15:14:41 +02002684 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002685 if (ret < 0)
2686 goto out;
2687
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002688 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002689 if (ret < 0)
2690 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2691
2692 wl1271_ps_elp_sleep(wl);
2693
2694out:
2695 mutex_unlock(&wl->mutex);
2696
2697 return ret;
2698}
2699
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002700static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2701{
2702 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002703 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704
2705 mutex_lock(&wl->mutex);
2706
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002707 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2708 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002709 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002710 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002711
Ido Yariva6208652011-03-01 15:14:41 +02002712 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002713 if (ret < 0)
2714 goto out;
2715
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002716 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002717 if (ret < 0)
2718 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2719
2720 wl1271_ps_elp_sleep(wl);
2721
2722out:
2723 mutex_unlock(&wl->mutex);
2724
2725 return ret;
2726}
2727
Arik Nemtsove78a2872010-10-16 19:07:21 +02002728static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002729 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002730{
Eliad Peller889cb362011-05-01 09:56:45 +03002731 u8 ssid_len;
2732 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2733 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002734
Eliad Peller889cb362011-05-01 09:56:45 +03002735 if (!ptr) {
2736 wl1271_error("No SSID in IEs!");
2737 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002738 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002739
Eliad Peller889cb362011-05-01 09:56:45 +03002740 ssid_len = ptr[1];
2741 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2742 wl1271_error("SSID is too long!");
2743 return -EINVAL;
2744 }
2745
2746 wl->ssid_len = ssid_len;
2747 memcpy(wl->ssid, ptr+2, ssid_len);
2748 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002749}
2750
Arik Nemtsove78a2872010-10-16 19:07:21 +02002751static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2752 struct ieee80211_bss_conf *bss_conf,
2753 u32 changed)
2754{
2755 int ret = 0;
2756
2757 if (changed & BSS_CHANGED_ERP_SLOT) {
2758 if (bss_conf->use_short_slot)
2759 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2760 else
2761 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2762 if (ret < 0) {
2763 wl1271_warning("Set slot time failed %d", ret);
2764 goto out;
2765 }
2766 }
2767
2768 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2769 if (bss_conf->use_short_preamble)
2770 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2771 else
2772 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2773 }
2774
2775 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2776 if (bss_conf->use_cts_prot)
2777 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2778 else
2779 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2780 if (ret < 0) {
2781 wl1271_warning("Set ctsprotect failed %d", ret);
2782 goto out;
2783 }
2784 }
2785
2786out:
2787 return ret;
2788}
2789
2790static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2791 struct ieee80211_vif *vif,
2792 struct ieee80211_bss_conf *bss_conf,
2793 u32 changed)
2794{
2795 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2796 int ret = 0;
2797
2798 if ((changed & BSS_CHANGED_BEACON_INT)) {
2799 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2800 bss_conf->beacon_int);
2801
2802 wl->beacon_int = bss_conf->beacon_int;
2803 }
2804
2805 if ((changed & BSS_CHANGED_BEACON)) {
2806 struct ieee80211_hdr *hdr;
2807 int ieoffset = offsetof(struct ieee80211_mgmt,
2808 u.beacon.variable);
2809 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2810 u16 tmpl_id;
2811
2812 if (!beacon)
2813 goto out;
2814
2815 wl1271_debug(DEBUG_MASTER, "beacon updated");
2816
2817 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2818 if (ret < 0) {
2819 dev_kfree_skb(beacon);
2820 goto out;
2821 }
2822 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2823 CMD_TEMPL_BEACON;
2824 ret = wl1271_cmd_template_set(wl, tmpl_id,
2825 beacon->data,
2826 beacon->len, 0,
2827 wl1271_tx_min_rate_get(wl));
2828 if (ret < 0) {
2829 dev_kfree_skb(beacon);
2830 goto out;
2831 }
2832
2833 hdr = (struct ieee80211_hdr *) beacon->data;
2834 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2835 IEEE80211_STYPE_PROBE_RESP);
2836
2837 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2838 CMD_TEMPL_PROBE_RESPONSE;
2839 ret = wl1271_cmd_template_set(wl,
2840 tmpl_id,
2841 beacon->data,
2842 beacon->len, 0,
2843 wl1271_tx_min_rate_get(wl));
2844 dev_kfree_skb(beacon);
2845 if (ret < 0)
2846 goto out;
2847 }
2848
2849out:
2850 return ret;
2851}
2852
2853/* AP mode changes */
2854static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855 struct ieee80211_vif *vif,
2856 struct ieee80211_bss_conf *bss_conf,
2857 u32 changed)
2858{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002859 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002860
Arik Nemtsove78a2872010-10-16 19:07:21 +02002861 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2862 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002863
Arik Nemtsove78a2872010-10-16 19:07:21 +02002864 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2865 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002866
Arik Nemtsov70f47422011-04-18 14:15:25 +03002867 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002868 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002869 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002870 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002871 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002872
2873 ret = wl1271_ap_init_templates(wl);
2874 if (ret < 0)
2875 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002876 }
2877
Arik Nemtsove78a2872010-10-16 19:07:21 +02002878 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2879 if (ret < 0)
2880 goto out;
2881
2882 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2883 if (bss_conf->enable_beacon) {
2884 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2885 ret = wl1271_cmd_start_bss(wl);
2886 if (ret < 0)
2887 goto out;
2888
2889 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2890 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002891
2892 ret = wl1271_ap_init_hwenc(wl);
2893 if (ret < 0)
2894 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002895 }
2896 } else {
2897 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2898 ret = wl1271_cmd_stop_bss(wl);
2899 if (ret < 0)
2900 goto out;
2901
2902 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2903 wl1271_debug(DEBUG_AP, "stopped AP");
2904 }
2905 }
2906 }
2907
2908 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2909 if (ret < 0)
2910 goto out;
2911out:
2912 return;
2913}
2914
2915/* STA/IBSS mode changes */
2916static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2917 struct ieee80211_vif *vif,
2918 struct ieee80211_bss_conf *bss_conf,
2919 u32 changed)
2920{
2921 bool do_join = false, set_assoc = false;
2922 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002923 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002924 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002925 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002926 bool sta_exists = false;
2927 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002928
2929 if (is_ibss) {
2930 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2931 changed);
2932 if (ret < 0)
2933 goto out;
2934 }
2935
2936 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2937 do_join = true;
2938
2939 /* Need to update the SSID (for filtering etc) */
2940 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2941 do_join = true;
2942
2943 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002944 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2945 bss_conf->enable_beacon ? "enabled" : "disabled");
2946
2947 if (bss_conf->enable_beacon)
2948 wl->set_bss_type = BSS_TYPE_IBSS;
2949 else
2950 wl->set_bss_type = BSS_TYPE_STA_BSS;
2951 do_join = true;
2952 }
2953
Arik Nemtsove78a2872010-10-16 19:07:21 +02002954 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002955 bool enable = false;
2956 if (bss_conf->cqm_rssi_thold)
2957 enable = true;
2958 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2959 bss_conf->cqm_rssi_thold,
2960 bss_conf->cqm_rssi_hyst);
2961 if (ret < 0)
2962 goto out;
2963 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2964 }
2965
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002966 if ((changed & BSS_CHANGED_BSSID) &&
2967 /*
2968 * Now we know the correct bssid, so we send a new join command
2969 * and enable the BSSID filter
2970 */
2971 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002972 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002973
Eliad Pellerfa287b82010-12-26 09:27:50 +01002974 if (!is_zero_ether_addr(wl->bssid)) {
2975 ret = wl1271_cmd_build_null_data(wl);
2976 if (ret < 0)
2977 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002978
Eliad Pellerfa287b82010-12-26 09:27:50 +01002979 ret = wl1271_build_qos_null_data(wl);
2980 if (ret < 0)
2981 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002982
Eliad Pellerfa287b82010-12-26 09:27:50 +01002983 /* filter out all packets not from this BSSID */
2984 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002985
Eliad Pellerfa287b82010-12-26 09:27:50 +01002986 /* Need to update the BSSID (for filtering etc) */
2987 do_join = true;
2988 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002989 }
2990
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002991 rcu_read_lock();
2992 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2993 if (sta) {
2994 /* save the supp_rates of the ap */
2995 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2996 if (sta->ht_cap.ht_supported)
2997 sta_rate_set |=
2998 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002999 sta_ht_cap = sta->ht_cap;
3000 sta_exists = true;
3001 }
3002 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003003
Arik Nemtsova1008852011-02-12 23:24:20 +02003004 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003005 /* handle new association with HT and HT information change */
3006 if ((changed & BSS_CHANGED_HT) &&
3007 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003008 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003009 true);
3010 if (ret < 0) {
3011 wl1271_warning("Set ht cap true failed %d",
3012 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003013 goto out;
3014 }
3015 ret = wl1271_acx_set_ht_information(wl,
3016 bss_conf->ht_operation_mode);
3017 if (ret < 0) {
3018 wl1271_warning("Set ht information failed %d",
3019 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003020 goto out;
3021 }
3022 }
3023 /* handle new association without HT and disassociation */
3024 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003025 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003026 false);
3027 if (ret < 0) {
3028 wl1271_warning("Set ht cap false failed %d",
3029 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003030 goto out;
3031 }
3032 }
3033 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003034
Arik Nemtsove78a2872010-10-16 19:07:21 +02003035 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003036 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003037 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003038 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003039 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003040 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003042 wl->ps_poll_failures = 0;
3043
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003044 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003045 * use basic rates from AP, and determine lowest rate
3046 * to use with control frames.
3047 */
3048 rates = bss_conf->basic_rates;
3049 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3050 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003051 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003052 if (sta_rate_set)
3053 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3054 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003055 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003056 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003057 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003058
3059 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003060 * with wl1271, we don't need to update the
3061 * beacon_int and dtim_period, because the firmware
3062 * updates it by itself when the first beacon is
3063 * received after a join.
3064 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003065 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3066 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003067 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003068
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003069 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003070 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003071 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003072 dev_kfree_skb(wl->probereq);
3073 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3074 ieoffset = offsetof(struct ieee80211_mgmt,
3075 u.probe_req.variable);
3076 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003077
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003078 /* enable the connection monitoring feature */
3079 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003081 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003082
3083 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003084 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3085 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003086 enum wl1271_cmd_ps_mode mode;
3087
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003088 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003089 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003090 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03003091 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003092 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003093 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003094 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003095 } else {
3096 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003097 bool was_assoc =
3098 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3099 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003100 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003101 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003102
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003103 /* free probe-request template */
3104 dev_kfree_skb(wl->probereq);
3105 wl->probereq = NULL;
3106
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003107 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003108 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003109
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003110 /* revert back to minimum rates for the current band */
3111 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003112 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003113 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003114 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003115 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003116
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003117 /* disable connection monitor features */
3118 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003119
3120 /* Disable the keep-alive feature */
3121 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003122 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003123 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003124
3125 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003126 if (was_assoc) {
3127 wl1271_unjoin(wl);
3128 wl1271_dummy_join(wl);
3129 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003130 }
3131 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003132
Eliad Pellerd192d262011-05-24 14:33:08 +03003133 if (changed & BSS_CHANGED_IBSS) {
3134 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3135 bss_conf->ibss_joined);
3136
3137 if (bss_conf->ibss_joined) {
3138 u32 rates = bss_conf->basic_rates;
3139 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3140 rates);
3141 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3142
3143 /* by default, use 11b rates */
3144 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3145 ret = wl1271_acx_sta_rate_policies(wl);
3146 if (ret < 0)
3147 goto out;
3148 }
3149 }
3150
Arik Nemtsove78a2872010-10-16 19:07:21 +02003151 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3152 if (ret < 0)
3153 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003154
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003155 if (changed & BSS_CHANGED_ARP_FILTER) {
3156 __be32 addr = bss_conf->arp_addr_list[0];
3157 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3158
Eliad Pellerc5312772010-12-09 11:31:27 +02003159 if (bss_conf->arp_addr_cnt == 1 &&
3160 bss_conf->arp_filter_enabled) {
3161 /*
3162 * The template should have been configured only upon
3163 * association. however, it seems that the correct ip
3164 * isn't being set (when sending), so we have to
3165 * reconfigure the template upon every ip change.
3166 */
3167 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3168 if (ret < 0) {
3169 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003170 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003171 }
3172
3173 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003174 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003175 addr);
3176 } else
3177 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003178
3179 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003180 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003181 }
3182
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003183 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003184 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003185 if (ret < 0) {
3186 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003187 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003188 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003189 }
3190
Arik Nemtsove78a2872010-10-16 19:07:21 +02003191out:
3192 return;
3193}
3194
3195static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3196 struct ieee80211_vif *vif,
3197 struct ieee80211_bss_conf *bss_conf,
3198 u32 changed)
3199{
3200 struct wl1271 *wl = hw->priv;
3201 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3202 int ret;
3203
3204 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3205 (int)changed);
3206
3207 mutex_lock(&wl->mutex);
3208
3209 if (unlikely(wl->state == WL1271_STATE_OFF))
3210 goto out;
3211
Ido Yariva6208652011-03-01 15:14:41 +02003212 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003213 if (ret < 0)
3214 goto out;
3215
3216 if (is_ap)
3217 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3218 else
3219 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003221 wl1271_ps_elp_sleep(wl);
3222
3223out:
3224 mutex_unlock(&wl->mutex);
3225}
3226
Kalle Valoc6999d82010-02-18 13:25:41 +02003227static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3228 const struct ieee80211_tx_queue_params *params)
3229{
3230 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003231 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003232 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003233
3234 mutex_lock(&wl->mutex);
3235
3236 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3237
Kalle Valo4695dc92010-03-18 12:26:38 +02003238 if (params->uapsd)
3239 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3240 else
3241 ps_scheme = CONF_PS_SCHEME_LEGACY;
3242
Arik Nemtsov488fc542010-10-16 20:33:45 +02003243 if (wl->state == WL1271_STATE_OFF) {
3244 /*
3245 * If the state is off, the parameters will be recorded and
3246 * configured on init. This happens in AP-mode.
3247 */
3248 struct conf_tx_ac_category *conf_ac =
3249 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3250 struct conf_tx_tid *conf_tid =
3251 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3252
3253 conf_ac->ac = wl1271_tx_get_queue(queue);
3254 conf_ac->cw_min = (u8)params->cw_min;
3255 conf_ac->cw_max = params->cw_max;
3256 conf_ac->aifsn = params->aifs;
3257 conf_ac->tx_op_limit = params->txop << 5;
3258
3259 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3260 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3261 conf_tid->tsid = wl1271_tx_get_queue(queue);
3262 conf_tid->ps_scheme = ps_scheme;
3263 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3264 conf_tid->apsd_conf[0] = 0;
3265 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003266 goto out;
3267 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003268
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003269 ret = wl1271_ps_elp_wakeup(wl);
3270 if (ret < 0)
3271 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003272
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003273 /*
3274 * the txop is confed in units of 32us by the mac80211,
3275 * we need us
3276 */
3277 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3278 params->cw_min, params->cw_max,
3279 params->aifs, params->txop << 5);
3280 if (ret < 0)
3281 goto out_sleep;
3282
3283 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3284 CONF_CHANNEL_TYPE_EDCF,
3285 wl1271_tx_get_queue(queue),
3286 ps_scheme, CONF_ACK_POLICY_LEGACY,
3287 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003288
3289out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003290 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003291
3292out:
3293 mutex_unlock(&wl->mutex);
3294
3295 return ret;
3296}
3297
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003298static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3299{
3300
3301 struct wl1271 *wl = hw->priv;
3302 u64 mactime = ULLONG_MAX;
3303 int ret;
3304
3305 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3306
3307 mutex_lock(&wl->mutex);
3308
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003309 if (unlikely(wl->state == WL1271_STATE_OFF))
3310 goto out;
3311
Ido Yariva6208652011-03-01 15:14:41 +02003312 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003313 if (ret < 0)
3314 goto out;
3315
3316 ret = wl1271_acx_tsf_info(wl, &mactime);
3317 if (ret < 0)
3318 goto out_sleep;
3319
3320out_sleep:
3321 wl1271_ps_elp_sleep(wl);
3322
3323out:
3324 mutex_unlock(&wl->mutex);
3325 return mactime;
3326}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003327
John W. Linvilleece550d2010-07-28 16:41:06 -04003328static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3329 struct survey_info *survey)
3330{
3331 struct wl1271 *wl = hw->priv;
3332 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003333
John W. Linvilleece550d2010-07-28 16:41:06 -04003334 if (idx != 0)
3335 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003336
John W. Linvilleece550d2010-07-28 16:41:06 -04003337 survey->channel = conf->channel;
3338 survey->filled = SURVEY_INFO_NOISE_DBM;
3339 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003340
John W. Linvilleece550d2010-07-28 16:41:06 -04003341 return 0;
3342}
3343
Arik Nemtsov409622e2011-02-23 00:22:29 +02003344static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003345 struct ieee80211_sta *sta,
3346 u8 *hlid)
3347{
3348 struct wl1271_station *wl_sta;
3349 int id;
3350
3351 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3352 if (id >= AP_MAX_STATIONS) {
3353 wl1271_warning("could not allocate HLID - too much stations");
3354 return -EBUSY;
3355 }
3356
3357 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003358 __set_bit(id, wl->ap_hlid_map);
3359 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3360 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003361 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003362 return 0;
3363}
3364
Arik Nemtsov409622e2011-02-23 00:22:29 +02003365static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003366{
3367 int id = hlid - WL1271_AP_STA_HLID_START;
3368
Arik Nemtsov409622e2011-02-23 00:22:29 +02003369 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3370 return;
3371
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003372 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003373 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003374 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003375 __clear_bit(hlid, &wl->ap_ps_map);
3376 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003377}
3378
3379static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3380 struct ieee80211_vif *vif,
3381 struct ieee80211_sta *sta)
3382{
3383 struct wl1271 *wl = hw->priv;
3384 int ret = 0;
3385 u8 hlid;
3386
3387 mutex_lock(&wl->mutex);
3388
3389 if (unlikely(wl->state == WL1271_STATE_OFF))
3390 goto out;
3391
3392 if (wl->bss_type != BSS_TYPE_AP_BSS)
3393 goto out;
3394
3395 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3396
Arik Nemtsov409622e2011-02-23 00:22:29 +02003397 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003398 if (ret < 0)
3399 goto out;
3400
Ido Yariva6208652011-03-01 15:14:41 +02003401 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003402 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003403 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003404
3405 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3406 if (ret < 0)
3407 goto out_sleep;
3408
3409out_sleep:
3410 wl1271_ps_elp_sleep(wl);
3411
Arik Nemtsov409622e2011-02-23 00:22:29 +02003412out_free_sta:
3413 if (ret < 0)
3414 wl1271_free_sta(wl, hlid);
3415
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003416out:
3417 mutex_unlock(&wl->mutex);
3418 return ret;
3419}
3420
3421static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3422 struct ieee80211_vif *vif,
3423 struct ieee80211_sta *sta)
3424{
3425 struct wl1271 *wl = hw->priv;
3426 struct wl1271_station *wl_sta;
3427 int ret = 0, id;
3428
3429 mutex_lock(&wl->mutex);
3430
3431 if (unlikely(wl->state == WL1271_STATE_OFF))
3432 goto out;
3433
3434 if (wl->bss_type != BSS_TYPE_AP_BSS)
3435 goto out;
3436
3437 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3438
3439 wl_sta = (struct wl1271_station *)sta->drv_priv;
3440 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3441 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3442 goto out;
3443
Ido Yariva6208652011-03-01 15:14:41 +02003444 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003445 if (ret < 0)
3446 goto out;
3447
3448 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3449 if (ret < 0)
3450 goto out_sleep;
3451
Arik Nemtsov409622e2011-02-23 00:22:29 +02003452 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003453
3454out_sleep:
3455 wl1271_ps_elp_sleep(wl);
3456
3457out:
3458 mutex_unlock(&wl->mutex);
3459 return ret;
3460}
3461
Luciano Coelho4623ec72011-03-21 19:26:41 +02003462static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3463 struct ieee80211_vif *vif,
3464 enum ieee80211_ampdu_mlme_action action,
3465 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3466 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003467{
3468 struct wl1271 *wl = hw->priv;
3469 int ret;
3470
3471 mutex_lock(&wl->mutex);
3472
3473 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3474 ret = -EAGAIN;
3475 goto out;
3476 }
3477
Ido Yariva6208652011-03-01 15:14:41 +02003478 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003479 if (ret < 0)
3480 goto out;
3481
Shahar Levi70559a02011-05-22 16:10:22 +03003482 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3483 tid, action);
3484
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003485 switch (action) {
3486 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003487 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003488 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3489 true);
3490 if (!ret)
3491 wl->ba_rx_bitmap |= BIT(tid);
3492 } else {
3493 ret = -ENOTSUPP;
3494 }
3495 break;
3496
3497 case IEEE80211_AMPDU_RX_STOP:
3498 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3499 if (!ret)
3500 wl->ba_rx_bitmap &= ~BIT(tid);
3501 break;
3502
3503 /*
3504 * The BA initiator session management in FW independently.
3505 * Falling break here on purpose for all TX APDU commands.
3506 */
3507 case IEEE80211_AMPDU_TX_START:
3508 case IEEE80211_AMPDU_TX_STOP:
3509 case IEEE80211_AMPDU_TX_OPERATIONAL:
3510 ret = -EINVAL;
3511 break;
3512
3513 default:
3514 wl1271_error("Incorrect ampdu action id=%x\n", action);
3515 ret = -EINVAL;
3516 }
3517
3518 wl1271_ps_elp_sleep(wl);
3519
3520out:
3521 mutex_unlock(&wl->mutex);
3522
3523 return ret;
3524}
3525
Arik Nemtsov33437892011-04-26 23:35:39 +03003526static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3527{
3528 struct wl1271 *wl = hw->priv;
3529 bool ret = false;
3530
3531 mutex_lock(&wl->mutex);
3532
3533 if (unlikely(wl->state == WL1271_STATE_OFF))
3534 goto out;
3535
3536 /* packets are considered pending if in the TX queue or the FW */
3537 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3538
3539 /* the above is appropriate for STA mode for PS purposes */
3540 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3541
3542out:
3543 mutex_unlock(&wl->mutex);
3544
3545 return ret;
3546}
3547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003548/* can't be const, mac80211 writes to this */
3549static struct ieee80211_rate wl1271_rates[] = {
3550 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003551 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3552 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003553 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003554 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3555 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003556 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3557 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003558 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3559 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003560 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3561 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003562 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3563 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003564 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3565 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003566 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3567 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003568 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003569 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3570 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003571 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003572 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3573 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003574 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003575 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3576 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003577 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003578 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3579 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003580 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003581 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3582 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003583 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003584 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3585 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003586 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003587 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3588 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003589};
3590
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003591/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003593 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003594 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003595 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3596 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3597 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003598 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003599 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3600 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3601 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003602 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003603 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3604 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3605 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003606 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003607};
3608
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003609/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003610static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003611 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003612 7, /* CONF_HW_RXTX_RATE_MCS7 */
3613 6, /* CONF_HW_RXTX_RATE_MCS6 */
3614 5, /* CONF_HW_RXTX_RATE_MCS5 */
3615 4, /* CONF_HW_RXTX_RATE_MCS4 */
3616 3, /* CONF_HW_RXTX_RATE_MCS3 */
3617 2, /* CONF_HW_RXTX_RATE_MCS2 */
3618 1, /* CONF_HW_RXTX_RATE_MCS1 */
3619 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003620
3621 11, /* CONF_HW_RXTX_RATE_54 */
3622 10, /* CONF_HW_RXTX_RATE_48 */
3623 9, /* CONF_HW_RXTX_RATE_36 */
3624 8, /* CONF_HW_RXTX_RATE_24 */
3625
3626 /* TI-specific rate */
3627 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3628
3629 7, /* CONF_HW_RXTX_RATE_18 */
3630 6, /* CONF_HW_RXTX_RATE_12 */
3631 3, /* CONF_HW_RXTX_RATE_11 */
3632 5, /* CONF_HW_RXTX_RATE_9 */
3633 4, /* CONF_HW_RXTX_RATE_6 */
3634 2, /* CONF_HW_RXTX_RATE_5_5 */
3635 1, /* CONF_HW_RXTX_RATE_2 */
3636 0 /* CONF_HW_RXTX_RATE_1 */
3637};
3638
Shahar Levie8b03a22010-10-13 16:09:39 +02003639/* 11n STA capabilities */
3640#define HW_RX_HIGHEST_RATE 72
3641
Shahar Levi00d20102010-11-08 11:20:10 +00003642#ifdef CONFIG_WL12XX_HT
3643#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003644 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3645 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003646 .ht_supported = true, \
3647 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3648 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3649 .mcs = { \
3650 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3651 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3652 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3653 }, \
3654}
Shahar Levi18357852010-10-13 16:09:41 +02003655#else
Shahar Levi00d20102010-11-08 11:20:10 +00003656#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003657 .ht_supported = false, \
3658}
3659#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003660
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003661/* can't be const, mac80211 writes to this */
3662static struct ieee80211_supported_band wl1271_band_2ghz = {
3663 .channels = wl1271_channels,
3664 .n_channels = ARRAY_SIZE(wl1271_channels),
3665 .bitrates = wl1271_rates,
3666 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003667 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003668};
3669
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003670/* 5 GHz data rates for WL1273 */
3671static struct ieee80211_rate wl1271_rates_5ghz[] = {
3672 { .bitrate = 60,
3673 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3674 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3675 { .bitrate = 90,
3676 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3677 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3678 { .bitrate = 120,
3679 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3680 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3681 { .bitrate = 180,
3682 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3683 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3684 { .bitrate = 240,
3685 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3686 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3687 { .bitrate = 360,
3688 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3689 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3690 { .bitrate = 480,
3691 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3692 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3693 { .bitrate = 540,
3694 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3695 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3696};
3697
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003698/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003699static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003700 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003701 { .hw_value = 8, .center_freq = 5040},
3702 { .hw_value = 9, .center_freq = 5045},
3703 { .hw_value = 11, .center_freq = 5055},
3704 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003705 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003706 { .hw_value = 34, .center_freq = 5170},
3707 { .hw_value = 36, .center_freq = 5180},
3708 { .hw_value = 38, .center_freq = 5190},
3709 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003710 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003711 { .hw_value = 44, .center_freq = 5220},
3712 { .hw_value = 46, .center_freq = 5230},
3713 { .hw_value = 48, .center_freq = 5240},
3714 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003715 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003716 { .hw_value = 60, .center_freq = 5300},
3717 { .hw_value = 64, .center_freq = 5320},
3718 { .hw_value = 100, .center_freq = 5500},
3719 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003720 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003721 { .hw_value = 112, .center_freq = 5560},
3722 { .hw_value = 116, .center_freq = 5580},
3723 { .hw_value = 120, .center_freq = 5600},
3724 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003725 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003726 { .hw_value = 132, .center_freq = 5660},
3727 { .hw_value = 136, .center_freq = 5680},
3728 { .hw_value = 140, .center_freq = 5700},
3729 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003730 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003731 { .hw_value = 157, .center_freq = 5785},
3732 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003733 { .hw_value = 165, .center_freq = 5825},
3734};
3735
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003736/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003737static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003738 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003739 7, /* CONF_HW_RXTX_RATE_MCS7 */
3740 6, /* CONF_HW_RXTX_RATE_MCS6 */
3741 5, /* CONF_HW_RXTX_RATE_MCS5 */
3742 4, /* CONF_HW_RXTX_RATE_MCS4 */
3743 3, /* CONF_HW_RXTX_RATE_MCS3 */
3744 2, /* CONF_HW_RXTX_RATE_MCS2 */
3745 1, /* CONF_HW_RXTX_RATE_MCS1 */
3746 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003747
3748 7, /* CONF_HW_RXTX_RATE_54 */
3749 6, /* CONF_HW_RXTX_RATE_48 */
3750 5, /* CONF_HW_RXTX_RATE_36 */
3751 4, /* CONF_HW_RXTX_RATE_24 */
3752
3753 /* TI-specific rate */
3754 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3755
3756 3, /* CONF_HW_RXTX_RATE_18 */
3757 2, /* CONF_HW_RXTX_RATE_12 */
3758 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3759 1, /* CONF_HW_RXTX_RATE_9 */
3760 0, /* CONF_HW_RXTX_RATE_6 */
3761 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3762 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3763 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3764};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003765
3766static struct ieee80211_supported_band wl1271_band_5ghz = {
3767 .channels = wl1271_channels_5ghz,
3768 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3769 .bitrates = wl1271_rates_5ghz,
3770 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003771 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003772};
3773
Tobias Klausera0ea9492010-05-20 10:38:11 +02003774static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003775 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3776 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3777};
3778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003779static const struct ieee80211_ops wl1271_ops = {
3780 .start = wl1271_op_start,
3781 .stop = wl1271_op_stop,
3782 .add_interface = wl1271_op_add_interface,
3783 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003784#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003785 .suspend = wl1271_op_suspend,
3786 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003787#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003788 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003789 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003790 .configure_filter = wl1271_op_configure_filter,
3791 .tx = wl1271_op_tx,
3792 .set_key = wl1271_op_set_key,
3793 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003794 .sched_scan_start = wl1271_op_sched_scan_start,
3795 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003796 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003797 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003798 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003799 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003800 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003801 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003802 .sta_add = wl1271_op_sta_add,
3803 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003804 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003805 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003806 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003807};
3808
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003809
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003810u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003811{
3812 u8 idx;
3813
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003814 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003815
3816 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3817 wl1271_error("Illegal RX rate from HW: %d", rate);
3818 return 0;
3819 }
3820
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003821 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003822 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3823 wl1271_error("Unsupported RX rate from HW: %d", rate);
3824 return 0;
3825 }
3826
3827 return idx;
3828}
3829
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003830static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3831 struct device_attribute *attr,
3832 char *buf)
3833{
3834 struct wl1271 *wl = dev_get_drvdata(dev);
3835 ssize_t len;
3836
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003837 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003838
3839 mutex_lock(&wl->mutex);
3840 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3841 wl->sg_enabled);
3842 mutex_unlock(&wl->mutex);
3843
3844 return len;
3845
3846}
3847
3848static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3849 struct device_attribute *attr,
3850 const char *buf, size_t count)
3851{
3852 struct wl1271 *wl = dev_get_drvdata(dev);
3853 unsigned long res;
3854 int ret;
3855
Luciano Coelho6277ed62011-04-01 17:49:54 +03003856 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003857 if (ret < 0) {
3858 wl1271_warning("incorrect value written to bt_coex_mode");
3859 return count;
3860 }
3861
3862 mutex_lock(&wl->mutex);
3863
3864 res = !!res;
3865
3866 if (res == wl->sg_enabled)
3867 goto out;
3868
3869 wl->sg_enabled = res;
3870
3871 if (wl->state == WL1271_STATE_OFF)
3872 goto out;
3873
Ido Yariva6208652011-03-01 15:14:41 +02003874 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003875 if (ret < 0)
3876 goto out;
3877
3878 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3879 wl1271_ps_elp_sleep(wl);
3880
3881 out:
3882 mutex_unlock(&wl->mutex);
3883 return count;
3884}
3885
3886static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3887 wl1271_sysfs_show_bt_coex_state,
3888 wl1271_sysfs_store_bt_coex_state);
3889
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003890static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3891 struct device_attribute *attr,
3892 char *buf)
3893{
3894 struct wl1271 *wl = dev_get_drvdata(dev);
3895 ssize_t len;
3896
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003897 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003898
3899 mutex_lock(&wl->mutex);
3900 if (wl->hw_pg_ver >= 0)
3901 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3902 else
3903 len = snprintf(buf, len, "n/a\n");
3904 mutex_unlock(&wl->mutex);
3905
3906 return len;
3907}
3908
3909static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3910 wl1271_sysfs_show_hw_pg_ver, NULL);
3911
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003912int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003913{
3914 int ret;
3915
3916 if (wl->mac80211_registered)
3917 return 0;
3918
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003919 ret = wl1271_fetch_nvs(wl);
3920 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003921 /* NOTE: The wl->nvs->nvs element must be first, in
3922 * order to simplify the casting, we assume it is at
3923 * the beginning of the wl->nvs structure.
3924 */
3925 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003926
3927 wl->mac_addr[0] = nvs_ptr[11];
3928 wl->mac_addr[1] = nvs_ptr[10];
3929 wl->mac_addr[2] = nvs_ptr[6];
3930 wl->mac_addr[3] = nvs_ptr[5];
3931 wl->mac_addr[4] = nvs_ptr[4];
3932 wl->mac_addr[5] = nvs_ptr[3];
3933 }
3934
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003935 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3936
3937 ret = ieee80211_register_hw(wl->hw);
3938 if (ret < 0) {
3939 wl1271_error("unable to register mac80211 hw: %d", ret);
3940 return ret;
3941 }
3942
3943 wl->mac80211_registered = true;
3944
Eliad Pellerd60080a2010-11-24 12:53:16 +02003945 wl1271_debugfs_init(wl);
3946
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003947 register_netdevice_notifier(&wl1271_dev_notifier);
3948
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003949 wl1271_notice("loaded");
3950
3951 return 0;
3952}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003953EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003954
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003955void wl1271_unregister_hw(struct wl1271 *wl)
3956{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003957 if (wl->state == WL1271_STATE_PLT)
3958 __wl1271_plt_stop(wl);
3959
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003960 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003961 ieee80211_unregister_hw(wl->hw);
3962 wl->mac80211_registered = false;
3963
3964}
3965EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3966
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003967int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003968{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003969 static const u32 cipher_suites[] = {
3970 WLAN_CIPHER_SUITE_WEP40,
3971 WLAN_CIPHER_SUITE_WEP104,
3972 WLAN_CIPHER_SUITE_TKIP,
3973 WLAN_CIPHER_SUITE_CCMP,
3974 WL1271_CIPHER_SUITE_GEM,
3975 };
3976
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003977 /* The tx descriptor buffer and the TKIP space. */
3978 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3979 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003980
3981 /* unit us */
3982 /* FIXME: find a proper value */
3983 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003984 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003985
3986 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003987 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003988 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003989 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003990 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003991 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003992 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003993 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003994 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003995 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003996
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003997 wl->hw->wiphy->cipher_suites = cipher_suites;
3998 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3999
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004000 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004001 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004002 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004003 /*
4004 * Maximum length of elements in scanning probe request templates
4005 * should be the maximum length possible for a template, without
4006 * the IEEE80211 header of the template
4007 */
4008 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
4009 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004010
Luciano Coelho4a31c112011-03-21 23:16:14 +02004011 /* make sure all our channels fit in the scanned_ch bitmask */
4012 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4013 ARRAY_SIZE(wl1271_channels_5ghz) >
4014 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004015 /*
4016 * We keep local copies of the band structs because we need to
4017 * modify them on a per-device basis.
4018 */
4019 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4020 sizeof(wl1271_band_2ghz));
4021 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4022 sizeof(wl1271_band_5ghz));
4023
4024 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4025 &wl->bands[IEEE80211_BAND_2GHZ];
4026 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4027 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004028
Kalle Valo12bd8942010-03-18 12:26:33 +02004029 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004030 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004031
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004032 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4033
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004034 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004035
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004036 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4037
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004038 wl->hw->max_rx_aggregation_subframes = 8;
4039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004040 return 0;
4041}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004042EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004044#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004045
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004046struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004047{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004048 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004049 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004050 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004051 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004052 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004053
4054 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4055 if (!hw) {
4056 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004057 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004058 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004059 }
4060
Julia Lawall929ebd32010-05-15 23:16:39 +02004061 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004062 if (!plat_dev) {
4063 wl1271_error("could not allocate platform_device");
4064 ret = -ENOMEM;
4065 goto err_plat_alloc;
4066 }
4067
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004068 wl = hw->priv;
4069 memset(wl, 0, sizeof(*wl));
4070
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004071 INIT_LIST_HEAD(&wl->list);
4072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004073 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004074 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004075
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004076 for (i = 0; i < NUM_TX_QUEUES; i++)
4077 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004078
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004079 for (i = 0; i < NUM_TX_QUEUES; i++)
4080 for (j = 0; j < AP_MAX_LINKS; j++)
4081 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4082
Ido Yariva6208652011-03-01 15:14:41 +02004083 skb_queue_head_init(&wl->deferred_rx_queue);
4084 skb_queue_head_init(&wl->deferred_tx_queue);
4085
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004086 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004087 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004088 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004089 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4090 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4091 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004092 INIT_WORK(&wl->rx_streaming_enable_work,
4093 wl1271_rx_streaming_enable_work);
4094 INIT_WORK(&wl->rx_streaming_disable_work,
4095 wl1271_rx_streaming_disable_work);
4096
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004097 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004098 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004099 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004100 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02004101 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
4102 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004103 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004104 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004105 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004106 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004107 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004108 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004109 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004110 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004111 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004112 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004113 wl->bss_type = MAX_BSS_TYPE;
4114 wl->set_bss_type = MAX_BSS_TYPE;
4115 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004116 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004117 wl->ap_ps_map = 0;
4118 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004119 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004120 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004121 wl->sched_scanning = false;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004122 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4123 (unsigned long) wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004124
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004125 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004126 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004127 wl->tx_frames[i] = NULL;
4128
4129 spin_lock_init(&wl->wl_lock);
4130
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004131 wl->state = WL1271_STATE_OFF;
4132 mutex_init(&wl->mutex);
4133
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004134 /* Apply default driver configuration. */
4135 wl1271_conf_init(wl);
4136
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004137 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4138 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4139 if (!wl->aggr_buf) {
4140 ret = -ENOMEM;
4141 goto err_hw;
4142 }
4143
Ido Yariv990f5de2011-03-31 10:06:59 +02004144 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4145 if (!wl->dummy_packet) {
4146 ret = -ENOMEM;
4147 goto err_aggr;
4148 }
4149
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004150 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004151 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004152 if (ret) {
4153 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004154 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004155 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004156 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004157
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004158 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004159 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004160 if (ret < 0) {
4161 wl1271_error("failed to create sysfs file bt_coex_state");
4162 goto err_platform;
4163 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004164
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004165 /* Create sysfs file to get HW PG version */
4166 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4167 if (ret < 0) {
4168 wl1271_error("failed to create sysfs file hw_pg_ver");
4169 goto err_bt_coex_state;
4170 }
4171
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004172 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004173
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004174err_bt_coex_state:
4175 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4176
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004177err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004178 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004179
Ido Yariv990f5de2011-03-31 10:06:59 +02004180err_dummy_packet:
4181 dev_kfree_skb(wl->dummy_packet);
4182
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004183err_aggr:
4184 free_pages((unsigned long)wl->aggr_buf, order);
4185
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004186err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004187 wl1271_debugfs_exit(wl);
4188 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004189
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004190err_plat_alloc:
4191 ieee80211_free_hw(hw);
4192
4193err_hw_alloc:
4194
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004195 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004196}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004197EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004198
4199int wl1271_free_hw(struct wl1271 *wl)
4200{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004201 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004202 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004203 free_pages((unsigned long)wl->aggr_buf,
4204 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004205 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004206
4207 wl1271_debugfs_exit(wl);
4208
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004209 vfree(wl->fw);
4210 wl->fw = NULL;
4211 kfree(wl->nvs);
4212 wl->nvs = NULL;
4213
4214 kfree(wl->fw_status);
4215 kfree(wl->tx_res_if);
4216
4217 ieee80211_free_hw(wl->hw);
4218
4219 return 0;
4220}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004221EXPORT_SYMBOL_GPL(wl1271_free_hw);
4222
Guy Eilam491bbd62011-01-12 10:33:29 +01004223u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004224EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004225module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004226MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4227
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004228MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004229MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004230MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");