blob: 6926d0a3e5c6ac26b0cb5f1c70d7f5236d513cc5 [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-Cohen958b20e02011-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
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300397static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
398{
399 int ret;
400 if (operstate != IF_OPER_UP)
401 return 0;
402
403 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
404 return 0;
405
406 ret = wl1271_cmd_set_sta_state(wl);
407 if (ret < 0)
408 return ret;
409
410 wl1271_info("Association completed.");
411 return 0;
412}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300413static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
414 void *arg)
415{
416 struct net_device *dev = arg;
417 struct wireless_dev *wdev;
418 struct wiphy *wiphy;
419 struct ieee80211_hw *hw;
420 struct wl1271 *wl;
421 struct wl1271 *wl_temp;
422 int ret = 0;
423
424 /* Check that this notification is for us. */
425 if (what != NETDEV_CHANGE)
426 return NOTIFY_DONE;
427
428 wdev = dev->ieee80211_ptr;
429 if (wdev == NULL)
430 return NOTIFY_DONE;
431
432 wiphy = wdev->wiphy;
433 if (wiphy == NULL)
434 return NOTIFY_DONE;
435
436 hw = wiphy_priv(wiphy);
437 if (hw == NULL)
438 return NOTIFY_DONE;
439
440 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200441 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300442 list_for_each_entry(wl, &wl_list, list) {
443 if (wl == wl_temp)
444 break;
445 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200446 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300447 if (wl != wl_temp)
448 return NOTIFY_DONE;
449
450 mutex_lock(&wl->mutex);
451
452 if (wl->state == WL1271_STATE_OFF)
453 goto out;
454
455 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
456 goto out;
457
Ido Yariva6208652011-03-01 15:14:41 +0200458 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300459 if (ret < 0)
460 goto out;
461
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300462 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300463
464 wl1271_ps_elp_sleep(wl);
465
466out:
467 mutex_unlock(&wl->mutex);
468
469 return NOTIFY_OK;
470}
471
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100472static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200473 struct regulatory_request *request)
474{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100475 struct ieee80211_supported_band *band;
476 struct ieee80211_channel *ch;
477 int i;
478
479 band = wiphy->bands[IEEE80211_BAND_5GHZ];
480 for (i = 0; i < band->n_channels; i++) {
481 ch = &band->channels[i];
482 if (ch->flags & IEEE80211_CHAN_DISABLED)
483 continue;
484
485 if (ch->flags & IEEE80211_CHAN_RADAR)
486 ch->flags |= IEEE80211_CHAN_NO_IBSS |
487 IEEE80211_CHAN_PASSIVE_SCAN;
488
489 }
490
491 return 0;
492}
493
Eliad Peller77ddaa12011-05-15 11:10:29 +0300494static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
495{
496 int ret = 0;
497
498 /* we should hold wl->mutex */
499 ret = wl1271_acx_ps_rx_streaming(wl, enable);
500 if (ret < 0)
501 goto out;
502
503 if (enable)
504 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
505 else
506 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
507out:
508 return ret;
509}
510
511/*
512 * this function is being called when the rx_streaming interval
513 * has beed changed or rx_streaming should be disabled
514 */
515int wl1271_recalc_rx_streaming(struct wl1271 *wl)
516{
517 int ret = 0;
518 int period = wl->conf.rx_streaming.interval;
519
520 /* don't reconfigure if rx_streaming is disabled */
521 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
522 goto out;
523
524 /* reconfigure/disable according to new streaming_period */
525 if (period &&
526 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
527 (wl->conf.rx_streaming.always ||
528 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
529 ret = wl1271_set_rx_streaming(wl, true);
530 else {
531 ret = wl1271_set_rx_streaming(wl, false);
532 /* don't cancel_work_sync since we might deadlock */
533 del_timer_sync(&wl->rx_streaming_timer);
534 }
535out:
536 return ret;
537}
538
539static void wl1271_rx_streaming_enable_work(struct work_struct *work)
540{
541 int ret;
542 struct wl1271 *wl =
543 container_of(work, struct wl1271, rx_streaming_enable_work);
544
545 mutex_lock(&wl->mutex);
546
547 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
548 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
549 (!wl->conf.rx_streaming.always &&
550 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
551 goto out;
552
553 if (!wl->conf.rx_streaming.interval)
554 goto out;
555
556 ret = wl1271_ps_elp_wakeup(wl);
557 if (ret < 0)
558 goto out;
559
560 ret = wl1271_set_rx_streaming(wl, true);
561 if (ret < 0)
562 goto out_sleep;
563
564 /* stop it after some time of inactivity */
565 mod_timer(&wl->rx_streaming_timer,
566 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
567
568out_sleep:
569 wl1271_ps_elp_sleep(wl);
570out:
571 mutex_unlock(&wl->mutex);
572}
573
574static void wl1271_rx_streaming_disable_work(struct work_struct *work)
575{
576 int ret;
577 struct wl1271 *wl =
578 container_of(work, struct wl1271, rx_streaming_disable_work);
579
580 mutex_lock(&wl->mutex);
581
582 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
583 goto out;
584
585 ret = wl1271_ps_elp_wakeup(wl);
586 if (ret < 0)
587 goto out;
588
589 ret = wl1271_set_rx_streaming(wl, false);
590 if (ret)
591 goto out_sleep;
592
593out_sleep:
594 wl1271_ps_elp_sleep(wl);
595out:
596 mutex_unlock(&wl->mutex);
597}
598
599static void wl1271_rx_streaming_timer(unsigned long data)
600{
601 struct wl1271 *wl = (struct wl1271 *)data;
602 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
603}
604
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300605static void wl1271_conf_init(struct wl1271 *wl)
606{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300607
608 /*
609 * This function applies the default configuration to the driver. This
610 * function is invoked upon driver load (spi probe.)
611 *
612 * The configuration is stored in a run-time structure in order to
613 * facilitate for run-time adjustment of any of the parameters. Making
614 * changes to the configuration structure will apply the new values on
615 * the next interface up (wl1271_op_start.)
616 */
617
618 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300619 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620}
621
622
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300623static int wl1271_plt_init(struct wl1271 *wl)
624{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200625 struct conf_tx_ac_category *conf_ac;
626 struct conf_tx_tid *conf_tid;
627 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300628
Shahar Levi49d750ca2011-03-06 16:32:09 +0200629 if (wl->chip.id == CHIP_ID_1283_PG20)
630 ret = wl128x_cmd_general_parms(wl);
631 else
632 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200633 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200634 return ret;
635
Shahar Levi49d750ca2011-03-06 16:32:09 +0200636 if (wl->chip.id == CHIP_ID_1283_PG20)
637 ret = wl128x_cmd_radio_parms(wl);
638 else
639 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200640 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200641 return ret;
642
Shahar Levi49d750ca2011-03-06 16:32:09 +0200643 if (wl->chip.id != CHIP_ID_1283_PG20) {
644 ret = wl1271_cmd_ext_radio_parms(wl);
645 if (ret < 0)
646 return ret;
647 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200648 if (ret < 0)
649 return ret;
650
Shahar Levi48a61472011-03-06 16:32:08 +0200651 /* Chip-specific initializations */
652 ret = wl1271_chip_specific_init(wl);
653 if (ret < 0)
654 return ret;
655
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200656 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200657 if (ret < 0)
658 return ret;
659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660 ret = wl1271_acx_init_mem_config(wl);
661 if (ret < 0)
662 return ret;
663
Luciano Coelho12419cce2010-02-18 13:25:44 +0200664 /* PHY layer config */
665 ret = wl1271_init_phy_config(wl);
666 if (ret < 0)
667 goto out_free_memmap;
668
669 ret = wl1271_acx_dco_itrim_params(wl);
670 if (ret < 0)
671 goto out_free_memmap;
672
673 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200674 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200675 if (ret < 0)
676 goto out_free_memmap;
677
678 /* Bluetooth WLAN coexistence */
679 ret = wl1271_init_pta(wl);
680 if (ret < 0)
681 goto out_free_memmap;
682
Shahar Leviff868432011-04-11 15:41:46 +0300683 /* FM WLAN coexistence */
684 ret = wl1271_acx_fm_coex(wl);
685 if (ret < 0)
686 goto out_free_memmap;
687
Luciano Coelho12419cce2010-02-18 13:25:44 +0200688 /* Energy detection */
689 ret = wl1271_init_energy_detection(wl);
690 if (ret < 0)
691 goto out_free_memmap;
692
Gery Kahn1ec610e2011-02-01 03:03:08 -0600693 ret = wl1271_acx_sta_mem_cfg(wl);
694 if (ret < 0)
695 goto out_free_memmap;
696
Luciano Coelho12419cce2010-02-18 13:25:44 +0200697 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100698 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200699 if (ret < 0)
700 goto out_free_memmap;
701
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200702 /* Default TID/AC configuration */
703 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200704 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200705 conf_ac = &wl->conf.tx.ac_conf[i];
706 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
707 conf_ac->cw_max, conf_ac->aifsn,
708 conf_ac->tx_op_limit);
709 if (ret < 0)
710 goto out_free_memmap;
711
Luciano Coelho12419cce2010-02-18 13:25:44 +0200712 conf_tid = &wl->conf.tx.tid_conf[i];
713 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
714 conf_tid->channel_type,
715 conf_tid->tsid,
716 conf_tid->ps_scheme,
717 conf_tid->ack_policy,
718 conf_tid->apsd_conf[0],
719 conf_tid->apsd_conf[1]);
720 if (ret < 0)
721 goto out_free_memmap;
722 }
723
Luciano Coelho12419cce2010-02-18 13:25:44 +0200724 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200725 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200727 goto out_free_memmap;
728
729 /* Configure for CAM power saving (ie. always active) */
730 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
731 if (ret < 0)
732 goto out_free_memmap;
733
734 /* configure PM */
735 ret = wl1271_acx_pm_config(wl);
736 if (ret < 0)
737 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300738
739 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200740
741 out_free_memmap:
742 kfree(wl->target_mem_map);
743 wl->target_mem_map = NULL;
744
745 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746}
747
Arik Nemtsovb622d992011-02-23 00:22:31 +0200748static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
749{
750 bool fw_ps;
751
752 /* only regulate station links */
753 if (hlid < WL1271_AP_STA_HLID_START)
754 return;
755
756 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
757
758 /*
759 * Wake up from high level PS if the STA is asleep with too little
760 * blocks in FW or if the STA is awake.
761 */
762 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
763 wl1271_ps_link_end(wl, hlid);
764
765 /* Start high-level PS if the STA is asleep with enough blocks in FW */
766 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
767 wl1271_ps_link_start(wl, hlid, true);
768}
769
770static void wl1271_irq_update_links_status(struct wl1271 *wl,
771 struct wl1271_fw_ap_status *status)
772{
773 u32 cur_fw_ps_map;
774 u8 hlid;
775
776 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
777 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
778 wl1271_debug(DEBUG_PSM,
779 "link ps prev 0x%x cur 0x%x changed 0x%x",
780 wl->ap_fw_ps_map, cur_fw_ps_map,
781 wl->ap_fw_ps_map ^ cur_fw_ps_map);
782
783 wl->ap_fw_ps_map = cur_fw_ps_map;
784 }
785
786 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
787 u8 cnt = status->tx_lnk_free_blks[hlid] -
788 wl->links[hlid].prev_freed_blks;
789
790 wl->links[hlid].prev_freed_blks =
791 status->tx_lnk_free_blks[hlid];
792 wl->links[hlid].allocated_blks -= cnt;
793
794 wl1271_irq_ps_regulate_link(wl, hlid,
795 wl->links[hlid].allocated_blks);
796 }
797}
798
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300799static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200800 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300801{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200802 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200803 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200804 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200805 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300806 int i;
807
Shahar Levi13b107d2011-03-06 16:32:12 +0200808 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200809 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
810 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200811 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200812 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
813 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200814 }
815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300816 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
817 "drv_rx_counter = %d, tx_results_counter = %d)",
818 status->intr,
819 status->fw_rx_counter,
820 status->drv_rx_counter,
821 status->tx_results_counter);
822
823 /* update number of available TX blocks */
824 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200825 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
826 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300827
828 wl->tx_blocks_freed[i] =
829 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200830 }
831
Ido Yarivd2f4d472011-03-31 10:07:00 +0200832 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200833
Ido Yarivd2f4d472011-03-31 10:07:00 +0200834 if (wl->bss_type == BSS_TYPE_AP_BSS) {
835 /* Update num of allocated TX blocks per link and ps status */
836 wl1271_irq_update_links_status(wl, &full_status->ap);
837 wl->tx_blocks_available += freed_blocks;
838 } else {
839 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
840
841 /*
842 * The FW might change the total number of TX memblocks before
843 * we get a notification about blocks being released. Thus, the
844 * available blocks calculation might yield a temporary result
845 * which is lower than the actual available blocks. Keeping in
846 * mind that only blocks that were allocated can be moved from
847 * TX to RX, tx_blocks_available should never decrease here.
848 */
849 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
850 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851 }
852
Ido Yariva5225502010-10-12 14:49:10 +0200853 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200854 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200855 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856
857 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200858 getnstimeofday(&ts);
859 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
860 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861}
862
Ido Yariva6208652011-03-01 15:14:41 +0200863static void wl1271_flush_deferred_work(struct wl1271 *wl)
864{
865 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200866
Ido Yariva6208652011-03-01 15:14:41 +0200867 /* Pass all received frames to the network stack */
868 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
869 ieee80211_rx_ni(wl->hw, skb);
870
871 /* Return sent skbs to the network stack */
872 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300873 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200874}
875
876static void wl1271_netstack_work(struct work_struct *work)
877{
878 struct wl1271 *wl =
879 container_of(work, struct wl1271, netstack_work);
880
881 do {
882 wl1271_flush_deferred_work(wl);
883 } while (skb_queue_len(&wl->deferred_rx_queue));
884}
885
886#define WL1271_IRQ_MAX_LOOPS 256
887
888irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300891 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200892 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200893 struct wl1271 *wl = (struct wl1271 *)cookie;
894 bool done = false;
895 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200896 unsigned long flags;
897
898 /* TX might be handled here, avoid redundant work */
899 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
900 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901
Ido Yariv341b7cd2011-03-31 10:07:01 +0200902 /*
903 * In case edge triggered interrupt must be used, we cannot iterate
904 * more than once without introducing race conditions with the hardirq.
905 */
906 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
907 loopcount = 1;
908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300909 mutex_lock(&wl->mutex);
910
911 wl1271_debug(DEBUG_IRQ, "IRQ work");
912
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300914 goto out;
915
Ido Yariva6208652011-03-01 15:14:41 +0200916 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917 if (ret < 0)
918 goto out;
919
Ido Yariva6208652011-03-01 15:14:41 +0200920 while (!done && loopcount--) {
921 /*
922 * In order to avoid a race with the hardirq, clear the flag
923 * before acknowledging the chip. Since the mutex is held,
924 * wl1271_ps_elp_wakeup cannot be called concurrently.
925 */
926 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
927 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200928
929 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200930 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200931 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200932 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200933 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200934 continue;
935 }
936
Eliad Pellerccc83b02010-10-27 14:09:57 +0200937 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
938 wl1271_error("watchdog interrupt received! "
939 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300940 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200941
942 /* restarting the chip. ignore any other interrupt. */
943 goto out;
944 }
945
Ido Yariva6208652011-03-01 15:14:41 +0200946 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200947 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
948
Ido Yariv8aad2462011-03-01 15:14:38 +0200949 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200950
Ido Yariva5225502010-10-12 14:49:10 +0200951 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200952 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200953 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200954 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200955 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200956 /*
957 * In order to avoid starvation of the TX path,
958 * call the work function directly.
959 */
960 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200961 } else {
962 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200963 }
964
Ido Yariv8aad2462011-03-01 15:14:38 +0200965 /* check for tx results */
966 if (wl->fw_status->common.tx_results_counter !=
967 (wl->tx_results_count & 0xff))
968 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200969
970 /* Make sure the deferred queues don't get too long */
971 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
972 skb_queue_len(&wl->deferred_rx_queue);
973 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
974 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975 }
976
977 if (intr & WL1271_ACX_INTR_EVENT_A) {
978 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
979 wl1271_event_handle(wl, 0);
980 }
981
982 if (intr & WL1271_ACX_INTR_EVENT_B) {
983 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
984 wl1271_event_handle(wl, 1);
985 }
986
987 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
988 wl1271_debug(DEBUG_IRQ,
989 "WL1271_ACX_INTR_INIT_COMPLETE");
990
991 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
992 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993 }
994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995 wl1271_ps_elp_sleep(wl);
996
997out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200998 spin_lock_irqsave(&wl->wl_lock, flags);
999 /* In case TX was not handled here, queue TX work */
1000 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1001 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1002 wl->tx_queue_count)
1003 ieee80211_queue_work(wl->hw, &wl->tx_work);
1004 spin_unlock_irqrestore(&wl->wl_lock, flags);
1005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001006 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001007
1008 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009}
Ido Yariva6208652011-03-01 15:14:41 +02001010EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012static int wl1271_fetch_firmware(struct wl1271 *wl)
1013{
1014 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 int ret;
1017
Arik Nemtsov166d5042010-10-16 21:44:57 +02001018 switch (wl->bss_type) {
1019 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +02001020 if (wl->chip.id == CHIP_ID_1283_PG20)
1021 fw_name = WL128X_AP_FW_NAME;
1022 else
1023 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001024 break;
1025 case BSS_TYPE_IBSS:
1026 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +02001027 if (wl->chip.id == CHIP_ID_1283_PG20)
1028 fw_name = WL128X_FW_NAME;
1029 else
1030 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001031 break;
1032 default:
1033 wl1271_error("no compatible firmware for bss_type %d",
1034 wl->bss_type);
1035 return -EINVAL;
1036 }
1037
1038 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1039
1040 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041
1042 if (ret < 0) {
1043 wl1271_error("could not get firmware: %d", ret);
1044 return ret;
1045 }
1046
1047 if (fw->size % 4) {
1048 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1049 fw->size);
1050 ret = -EILSEQ;
1051 goto out;
1052 }
1053
Arik Nemtsov166d5042010-10-16 21:44:57 +02001054 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001056 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057
1058 if (!wl->fw) {
1059 wl1271_error("could not allocate memory for the firmware");
1060 ret = -ENOMEM;
1061 goto out;
1062 }
1063
1064 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +02001065 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 ret = 0;
1067
1068out:
1069 release_firmware(fw);
1070
1071 return ret;
1072}
1073
1074static int wl1271_fetch_nvs(struct wl1271 *wl)
1075{
1076 const struct firmware *fw;
1077 int ret;
1078
Shahar Levi5aa42342011-03-06 16:32:07 +02001079 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080
1081 if (ret < 0) {
1082 wl1271_error("could not get nvs file: %d", ret);
1083 return ret;
1084 }
1085
Shahar Levibc765bf2011-03-06 16:32:10 +02001086 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001087
1088 if (!wl->nvs) {
1089 wl1271_error("could not allocate memory for the nvs file");
1090 ret = -ENOMEM;
1091 goto out;
1092 }
1093
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001094 wl->nvs_len = fw->size;
1095
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096out:
1097 release_firmware(fw);
1098
1099 return ret;
1100}
1101
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001102void wl12xx_queue_recovery_work(struct wl1271 *wl)
1103{
1104 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1105 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1106}
1107
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001108static void wl1271_recovery_work(struct work_struct *work)
1109{
1110 struct wl1271 *wl =
1111 container_of(work, struct wl1271, recovery_work);
1112
1113 mutex_lock(&wl->mutex);
1114
1115 if (wl->state != WL1271_STATE_ON)
1116 goto out;
1117
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001118 /* Avoid a recursive recovery */
1119 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1120
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001121 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1122 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001123
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001124 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1125 ieee80211_connection_loss(wl->vif);
1126
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001127 /* Prevent spurious TX during FW restart */
1128 ieee80211_stop_queues(wl->hw);
1129
Luciano Coelho33c2c062011-05-10 14:46:02 +03001130 if (wl->sched_scanning) {
1131 ieee80211_sched_scan_stopped(wl->hw);
1132 wl->sched_scanning = false;
1133 }
1134
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001135 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001136 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001137
1138 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1139
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001140 ieee80211_restart_hw(wl->hw);
1141
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001142 /*
1143 * Its safe to enable TX now - the queues are stopped after a request
1144 * to restart the HW.
1145 */
1146 ieee80211_wake_queues(wl->hw);
1147
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001148out:
1149 mutex_unlock(&wl->mutex);
1150}
1151
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001152static void wl1271_fw_wakeup(struct wl1271 *wl)
1153{
1154 u32 elp_reg;
1155
1156 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001157 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158}
1159
1160static int wl1271_setup(struct wl1271 *wl)
1161{
1162 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1163 if (!wl->fw_status)
1164 return -ENOMEM;
1165
1166 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1167 if (!wl->tx_res_if) {
1168 kfree(wl->fw_status);
1169 return -ENOMEM;
1170 }
1171
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172 return 0;
1173}
1174
1175static int wl1271_chip_wakeup(struct wl1271 *wl)
1176{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001177 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178 int ret = 0;
1179
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001180 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001181 ret = wl1271_power_on(wl);
1182 if (ret < 0)
1183 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001184 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001185 wl1271_io_reset(wl);
1186 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001187
1188 /* We don't need a real memory partition here, because we only want
1189 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001190 memset(&partition, 0, sizeof(partition));
1191 partition.reg.start = REGISTERS_BASE;
1192 partition.reg.size = REGISTERS_DOWN_SIZE;
1193 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194
1195 /* ELP module wake up */
1196 wl1271_fw_wakeup(wl);
1197
1198 /* whal_FwCtrl_BootSm() */
1199
1200 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001201 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202
1203 /* 1. check if chip id is valid */
1204
1205 switch (wl->chip.id) {
1206 case CHIP_ID_1271_PG10:
1207 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1208 wl->chip.id);
1209
1210 ret = wl1271_setup(wl);
1211 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001212 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213 break;
1214 case CHIP_ID_1271_PG20:
1215 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1216 wl->chip.id);
1217
Shahar Levi0c005042011-06-12 10:34:43 +03001218 /*
1219 * 'end-of-transaction flag' and 'LPD mode flag'
1220 * should be set in wl127x AP mode only
1221 */
Shahar Levi564f5952011-04-04 10:20:39 +03001222 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001223 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1224 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 ret = wl1271_setup(wl);
1227 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001228 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001230 case CHIP_ID_1283_PG20:
1231 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1232 wl->chip.id);
1233
1234 ret = wl1271_setup(wl);
1235 if (ret < 0)
1236 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001237
Ido Yariv0da13da2011-03-31 10:06:58 +02001238 if (wl1271_set_block_size(wl))
1239 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001240 break;
1241 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001243 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001245 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246 }
1247
Arik Nemtsov166d5042010-10-16 21:44:57 +02001248 /* Make sure the firmware type matches the BSS type */
1249 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250 ret = wl1271_fetch_firmware(wl);
1251 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001252 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253 }
1254
1255 /* No NVS from netlink, try to get it from the filesystem */
1256 if (wl->nvs == NULL) {
1257 ret = wl1271_fetch_nvs(wl);
1258 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001259 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260 }
1261
1262out:
1263 return ret;
1264}
1265
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001266int wl1271_plt_start(struct wl1271 *wl)
1267{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001268 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269 int ret;
1270
1271 mutex_lock(&wl->mutex);
1272
1273 wl1271_notice("power up");
1274
1275 if (wl->state != WL1271_STATE_OFF) {
1276 wl1271_error("cannot go into PLT state because not "
1277 "in off state: %d", wl->state);
1278 ret = -EBUSY;
1279 goto out;
1280 }
1281
Arik Nemtsov166d5042010-10-16 21:44:57 +02001282 wl->bss_type = BSS_TYPE_STA_BSS;
1283
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001284 while (retries) {
1285 retries--;
1286 ret = wl1271_chip_wakeup(wl);
1287 if (ret < 0)
1288 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001290 ret = wl1271_boot(wl);
1291 if (ret < 0)
1292 goto power_off;
1293
1294 ret = wl1271_plt_init(wl);
1295 if (ret < 0)
1296 goto irq_disable;
1297
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001298 wl->state = WL1271_STATE_PLT;
1299 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001300 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 goto out;
1303
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001304irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001305 mutex_unlock(&wl->mutex);
1306 /* Unlocking the mutex in the middle of handling is
1307 inherently unsafe. In this case we deem it safe to do,
1308 because we need to let any possibly pending IRQ out of
1309 the system (and while we are WL1271_STATE_OFF the IRQ
1310 work function will not do anything.) Also, any other
1311 possible concurrent operations will fail due to the
1312 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001313 wl1271_disable_interrupts(wl);
1314 wl1271_flush_deferred_work(wl);
1315 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001316 mutex_lock(&wl->mutex);
1317power_off:
1318 wl1271_power_off(wl);
1319 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001321 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1322 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323out:
1324 mutex_unlock(&wl->mutex);
1325
1326 return ret;
1327}
1328
Luciano Coelho4623ec72011-03-21 19:26:41 +02001329static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330{
1331 int ret = 0;
1332
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 wl1271_notice("power down");
1334
1335 if (wl->state != WL1271_STATE_PLT) {
1336 wl1271_error("cannot power down because not in PLT "
1337 "state: %d", wl->state);
1338 ret = -EBUSY;
1339 goto out;
1340 }
1341
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 wl1271_power_off(wl);
1343
1344 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001345 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001348 wl1271_disable_interrupts(wl);
1349 wl1271_flush_deferred_work(wl);
1350 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001351 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001352 mutex_lock(&wl->mutex);
1353out:
1354 return ret;
1355}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001356
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001357int wl1271_plt_stop(struct wl1271 *wl)
1358{
1359 int ret;
1360
1361 mutex_lock(&wl->mutex);
1362 ret = __wl1271_plt_stop(wl);
1363 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364 return ret;
1365}
1366
Johannes Berg7bb45682011-02-24 14:42:06 +01001367static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368{
1369 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001370 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001371 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001372 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373
Ido Yarivb07d4032011-03-01 15:14:43 +02001374 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1375
1376 if (wl->bss_type == BSS_TYPE_AP_BSS)
1377 hlid = wl1271_tx_get_hlid(skb);
1378
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001379 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001380
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001381 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001382
1383 /*
1384 * The workqueue is slow to process the tx_queue and we need stop
1385 * the queue here, otherwise the queue will get too long.
1386 */
1387 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1388 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1389 ieee80211_stop_queues(wl->hw);
1390 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1391 }
1392
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001393 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001394 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001395 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1396 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1397 } else {
1398 skb_queue_tail(&wl->tx_queue[q], skb);
1399 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
1401 /*
1402 * The chip specific setup must run before the first TX packet -
1403 * before that, the tx_work will not be initialized!
1404 */
1405
Ido Yarivb07d4032011-03-01 15:14:43 +02001406 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1407 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001408 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001409
1410 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411}
1412
Shahar Leviae47c452011-03-06 16:32:14 +02001413int wl1271_tx_dummy_packet(struct wl1271 *wl)
1414{
Ido Yariv990f5de2011-03-31 10:06:59 +02001415 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001416
Ido Yariv990f5de2011-03-31 10:06:59 +02001417 spin_lock_irqsave(&wl->wl_lock, flags);
1418 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1419 wl->tx_queue_count++;
1420 spin_unlock_irqrestore(&wl->wl_lock, flags);
1421
1422 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1423 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1424 wl1271_tx_work_locked(wl);
1425
1426 /*
1427 * If the FW TX is busy, TX work will be scheduled by the threaded
1428 * interrupt handler function
1429 */
1430 return 0;
1431}
1432
1433/*
1434 * The size of the dummy packet should be at least 1400 bytes. However, in
1435 * order to minimize the number of bus transactions, aligning it to 512 bytes
1436 * boundaries could be beneficial, performance wise
1437 */
1438#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1439
Luciano Coelhocf27d862011-04-01 21:08:23 +03001440static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001441{
1442 struct sk_buff *skb;
1443 struct ieee80211_hdr_3addr *hdr;
1444 unsigned int dummy_packet_size;
1445
1446 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1447 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1448
1449 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001450 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001451 wl1271_warning("Failed to allocate a dummy packet skb");
1452 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001453 }
1454
1455 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1456
1457 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1458 memset(hdr, 0, sizeof(*hdr));
1459 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001460 IEEE80211_STYPE_NULLFUNC |
1461 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001462
Ido Yariv990f5de2011-03-31 10:06:59 +02001463 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001464
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001465 /* Dummy packets require the TID to be management */
1466 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001467
1468 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001469 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001470 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001471
Ido Yariv990f5de2011-03-31 10:06:59 +02001472 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001473}
1474
Ido Yariv990f5de2011-03-31 10:06:59 +02001475
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001476static struct notifier_block wl1271_dev_notifier = {
1477 .notifier_call = wl1271_dev_notify,
1478};
1479
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001480#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001481static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001482{
1483 int ret;
1484
Eliad Peller94390642011-05-13 11:57:13 +03001485 mutex_lock(&wl->mutex);
1486
1487 ret = wl1271_ps_elp_wakeup(wl);
1488 if (ret < 0)
1489 goto out_unlock;
1490
1491 /* enter psm if needed*/
1492 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1493 DECLARE_COMPLETION_ONSTACK(compl);
1494
1495 wl->ps_compl = &compl;
1496 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1497 wl->basic_rate, true);
1498 if (ret < 0)
1499 goto out_sleep;
1500
1501 /* we must unlock here so we will be able to get events */
1502 wl1271_ps_elp_sleep(wl);
1503 mutex_unlock(&wl->mutex);
1504
1505 ret = wait_for_completion_timeout(
1506 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1507 if (ret <= 0) {
1508 wl1271_warning("couldn't enter ps mode!");
1509 ret = -EBUSY;
1510 goto out;
1511 }
1512
1513 /* take mutex again, and wakeup */
1514 mutex_lock(&wl->mutex);
1515
1516 ret = wl1271_ps_elp_wakeup(wl);
1517 if (ret < 0)
1518 goto out_unlock;
1519 }
1520out_sleep:
1521 wl1271_ps_elp_sleep(wl);
1522out_unlock:
1523 mutex_unlock(&wl->mutex);
1524out:
1525 return ret;
1526
1527}
1528
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001529static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001530{
1531 int ret;
1532
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001533 mutex_lock(&wl->mutex);
1534
1535 ret = wl1271_ps_elp_wakeup(wl);
1536 if (ret < 0)
1537 goto out_unlock;
1538
1539 ret = wl1271_acx_set_ap_beacon_filter(wl, true);
1540
1541 wl1271_ps_elp_sleep(wl);
1542out_unlock:
1543 mutex_unlock(&wl->mutex);
1544 return ret;
1545
1546}
1547
1548static int wl1271_configure_suspend(struct wl1271 *wl)
1549{
1550 if (wl->bss_type == BSS_TYPE_STA_BSS)
1551 return wl1271_configure_suspend_sta(wl);
1552 if (wl->bss_type == BSS_TYPE_AP_BSS)
1553 return wl1271_configure_suspend_ap(wl);
1554 return 0;
1555}
1556
1557static void wl1271_configure_resume(struct wl1271 *wl)
1558{
1559 int ret;
1560 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1561 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1562
1563 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001564 return;
1565
1566 mutex_lock(&wl->mutex);
1567 ret = wl1271_ps_elp_wakeup(wl);
1568 if (ret < 0)
1569 goto out;
1570
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001571 if (is_sta) {
1572 /* exit psm if it wasn't configured */
1573 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1574 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1575 wl->basic_rate, true);
1576 } else if (is_ap) {
1577 wl1271_acx_set_ap_beacon_filter(wl, false);
1578 }
Eliad Peller94390642011-05-13 11:57:13 +03001579
1580 wl1271_ps_elp_sleep(wl);
1581out:
1582 mutex_unlock(&wl->mutex);
1583}
1584
Eliad Peller402e48612011-05-13 11:57:09 +03001585static int wl1271_op_suspend(struct ieee80211_hw *hw,
1586 struct cfg80211_wowlan *wow)
1587{
1588 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001589 int ret;
1590
Eliad Peller402e48612011-05-13 11:57:09 +03001591 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001592 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001593
Eliad Peller4a859df2011-06-06 12:21:52 +03001594 wl->wow_enabled = true;
1595 ret = wl1271_configure_suspend(wl);
1596 if (ret < 0) {
1597 wl1271_warning("couldn't prepare device to suspend");
1598 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001599 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001600 /* flush any remaining work */
1601 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1602 flush_delayed_work(&wl->scan_complete_work);
1603
1604 /*
1605 * disable and re-enable interrupts in order to flush
1606 * the threaded_irq
1607 */
1608 wl1271_disable_interrupts(wl);
1609
1610 /*
1611 * set suspended flag to avoid triggering a new threaded_irq
1612 * work. no need for spinlock as interrupts are disabled.
1613 */
1614 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1615
1616 wl1271_enable_interrupts(wl);
1617 flush_work(&wl->tx_work);
1618 flush_delayed_work(&wl->pspoll_work);
1619 flush_delayed_work(&wl->elp_work);
1620
Eliad Peller402e48612011-05-13 11:57:09 +03001621 return 0;
1622}
1623
1624static int wl1271_op_resume(struct ieee80211_hw *hw)
1625{
1626 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001627 unsigned long flags;
1628 bool run_irq_work = false;
1629
Eliad Peller402e48612011-05-13 11:57:09 +03001630 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1631 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001632 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001633
1634 /*
1635 * re-enable irq_work enqueuing, and call irq_work directly if
1636 * there is a pending work.
1637 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001638 spin_lock_irqsave(&wl->wl_lock, flags);
1639 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1640 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1641 run_irq_work = true;
1642 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001643
Eliad Peller4a859df2011-06-06 12:21:52 +03001644 if (run_irq_work) {
1645 wl1271_debug(DEBUG_MAC80211,
1646 "run postponed irq_work directly");
1647 wl1271_irq(0, wl);
1648 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001649 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001650 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001651 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001652
Eliad Peller402e48612011-05-13 11:57:09 +03001653 return 0;
1654}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001655#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001656
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657static int wl1271_op_start(struct ieee80211_hw *hw)
1658{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001659 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1660
1661 /*
1662 * We have to delay the booting of the hardware because
1663 * we need to know the local MAC address before downloading and
1664 * initializing the firmware. The MAC address cannot be changed
1665 * after boot, and without the proper MAC address, the firmware
1666 * will not function properly.
1667 *
1668 * The MAC address is first known when the corresponding interface
1669 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001670 *
1671 * In addition, we currently have different firmwares for AP and managed
1672 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001673 */
1674
1675 return 0;
1676}
1677
1678static void wl1271_op_stop(struct ieee80211_hw *hw)
1679{
1680 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1681}
1682
1683static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1684 struct ieee80211_vif *vif)
1685{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001686 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001687 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001688 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001690 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001691
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001692 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1693 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001694
1695 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001696 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001697 wl1271_debug(DEBUG_MAC80211,
1698 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001699 ret = -EBUSY;
1700 goto out;
1701 }
1702
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001703 /*
1704 * in some very corner case HW recovery scenarios its possible to
1705 * get here before __wl1271_op_remove_interface is complete, so
1706 * opt out if that is the case.
1707 */
1708 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1709 ret = -EBUSY;
1710 goto out;
1711 }
1712
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001713 switch (vif->type) {
1714 case NL80211_IFTYPE_STATION:
1715 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001716 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001717 break;
1718 case NL80211_IFTYPE_ADHOC:
1719 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001720 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001721 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001722 case NL80211_IFTYPE_AP:
1723 wl->bss_type = BSS_TYPE_AP_BSS;
1724 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001725 default:
1726 ret = -EOPNOTSUPP;
1727 goto out;
1728 }
1729
1730 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001731
1732 if (wl->state != WL1271_STATE_OFF) {
1733 wl1271_error("cannot start because not in off state: %d",
1734 wl->state);
1735 ret = -EBUSY;
1736 goto out;
1737 }
1738
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001739 while (retries) {
1740 retries--;
1741 ret = wl1271_chip_wakeup(wl);
1742 if (ret < 0)
1743 goto power_off;
1744
1745 ret = wl1271_boot(wl);
1746 if (ret < 0)
1747 goto power_off;
1748
1749 ret = wl1271_hw_init(wl);
1750 if (ret < 0)
1751 goto irq_disable;
1752
Eliad Peller71125ab2010-10-28 21:46:43 +02001753 booted = true;
1754 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001755
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001756irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001757 mutex_unlock(&wl->mutex);
1758 /* Unlocking the mutex in the middle of handling is
1759 inherently unsafe. In this case we deem it safe to do,
1760 because we need to let any possibly pending IRQ out of
1761 the system (and while we are WL1271_STATE_OFF the IRQ
1762 work function will not do anything.) Also, any other
1763 possible concurrent operations will fail due to the
1764 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001765 wl1271_disable_interrupts(wl);
1766 wl1271_flush_deferred_work(wl);
1767 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001768 mutex_lock(&wl->mutex);
1769power_off:
1770 wl1271_power_off(wl);
1771 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001772
Eliad Peller71125ab2010-10-28 21:46:43 +02001773 if (!booted) {
1774 wl1271_error("firmware boot failed despite %d retries",
1775 WL1271_BOOT_RETRIES);
1776 goto out;
1777 }
1778
1779 wl->vif = vif;
1780 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001781 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001782 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001783
1784 /* update hw/fw version info in wiphy struct */
1785 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001786 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001787 sizeof(wiphy->fw_version));
1788
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001789 /*
1790 * Now we know if 11a is supported (info from the NVS), so disable
1791 * 11a channels if not supported
1792 */
1793 if (!wl->enable_11a)
1794 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1795
1796 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1797 wl->enable_11a ? "" : "not ");
1798
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001799out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001800 mutex_unlock(&wl->mutex);
1801
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001802 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001803 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001804 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001805 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807 return ret;
1808}
1809
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001810static void __wl1271_op_remove_interface(struct wl1271 *wl,
1811 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001813 int i;
1814
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001815 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001817 /* because of hardware recovery, we may get here twice */
1818 if (wl->state != WL1271_STATE_ON)
1819 return;
1820
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001821 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001822
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001823 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001824 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001825 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001826
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001827 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001828 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001829 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001830
Luciano Coelho08688d62010-07-08 17:50:07 +03001831 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001832 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001833 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001834 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001835 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001836 }
1837
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001838 /*
1839 * this must be before the cancel_work calls below, so that the work
1840 * functions don't perform further work.
1841 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001842 wl->state = WL1271_STATE_OFF;
1843
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844 mutex_unlock(&wl->mutex);
1845
Ido Yariva6208652011-03-01 15:14:41 +02001846 wl1271_disable_interrupts(wl);
1847 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001848 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001849 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001850 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03001851 del_timer_sync(&wl->rx_streaming_timer);
1852 cancel_work_sync(&wl->rx_streaming_enable_work);
1853 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001854 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001855 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001856
1857 mutex_lock(&wl->mutex);
1858
1859 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001860 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 wl1271_power_off(wl);
1862
1863 memset(wl->bssid, 0, ETH_ALEN);
1864 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1865 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001866 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001867 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001868 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001869
1870 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001871 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1873 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001874 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875 wl->tx_results_count = 0;
1876 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001877 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001878 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001879 wl->time_offset = 0;
1880 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001881 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001882 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001883 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001884 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001885 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001886 wl->ap_fw_ps_map = 0;
1887 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001888 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001889
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001890 /*
1891 * this is performed after the cancel_work calls and the associated
1892 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1893 * get executed before all these vars have been reset.
1894 */
1895 wl->flags = 0;
1896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001897 for (i = 0; i < NUM_TX_QUEUES; i++)
1898 wl->tx_blocks_freed[i] = 0;
1899
1900 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001901
1902 kfree(wl->fw_status);
1903 wl->fw_status = NULL;
1904 kfree(wl->tx_res_if);
1905 wl->tx_res_if = NULL;
1906 kfree(wl->target_mem_map);
1907 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001908}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001909
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001910static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1911 struct ieee80211_vif *vif)
1912{
1913 struct wl1271 *wl = hw->priv;
1914
1915 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001916 /*
1917 * wl->vif can be null here if someone shuts down the interface
1918 * just when hardware recovery has been started.
1919 */
1920 if (wl->vif) {
1921 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001922 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001923 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001924
Juuso Oikarinen67353292010-11-18 15:19:02 +02001925 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001926 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001927}
1928
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001929void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001930{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001931 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001932
1933 /* combine requested filters with current filter config */
1934 filters = wl->filters | filters;
1935
1936 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1937
1938 if (filters & FIF_PROMISC_IN_BSS) {
1939 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1940 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1941 wl->rx_config |= CFG_BSSID_FILTER_EN;
1942 }
1943 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1944 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1945 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1946 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1947 }
1948 if (filters & FIF_OTHER_BSS) {
1949 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1950 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1951 }
1952 if (filters & FIF_CONTROL) {
1953 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1954 wl->rx_filter |= CFG_RX_CTL_EN;
1955 }
1956 if (filters & FIF_FCSFAIL) {
1957 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1958 wl->rx_filter |= CFG_RX_FCS_ERROR;
1959 }
1960}
1961
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001962static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001963{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001964 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001965 /* we need to use a dummy BSSID for now */
1966 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1967 0xad, 0xbe, 0xef };
1968
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001969 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1970
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001971 /* pass through frames from all BSS */
1972 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1973
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001974 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001975 if (ret < 0)
1976 goto out;
1977
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001978 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001979
1980out:
1981 return ret;
1982}
1983
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001984static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001985{
1986 int ret;
1987
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001988 /*
1989 * One of the side effects of the JOIN command is that is clears
1990 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1991 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001992 * Currently the only valid scenario for JOIN during association
1993 * is on roaming, in which case we will also be given new keys.
1994 * Keep the below message for now, unless it starts bothering
1995 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001996 */
1997 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1998 wl1271_info("JOIN while associated.");
1999
2000 if (set_assoc)
2001 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2002
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002003 ret = wl1271_cmd_join(wl, wl->set_bss_type);
2004 if (ret < 0)
2005 goto out;
2006
2007 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2008
2009 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2010 goto out;
2011
2012 /*
2013 * The join command disable the keep-alive mode, shut down its process,
2014 * and also clear the template config, so we need to reset it all after
2015 * the join. The acx_aid starts the keep-alive process, and the order
2016 * of the commands below is relevant.
2017 */
2018 ret = wl1271_acx_keep_alive_mode(wl, true);
2019 if (ret < 0)
2020 goto out;
2021
2022 ret = wl1271_acx_aid(wl, wl->aid);
2023 if (ret < 0)
2024 goto out;
2025
2026 ret = wl1271_cmd_build_klv_null_data(wl);
2027 if (ret < 0)
2028 goto out;
2029
2030 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2031 ACX_KEEP_ALIVE_TPL_VALID);
2032 if (ret < 0)
2033 goto out;
2034
2035out:
2036 return ret;
2037}
2038
2039static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002040{
2041 int ret;
2042
2043 /* to stop listening to a channel, we disconnect */
2044 ret = wl1271_cmd_disconnect(wl);
2045 if (ret < 0)
2046 goto out;
2047
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002048 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002049 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002050
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02002051 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002052 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002053
2054out:
2055 return ret;
2056}
2057
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002058static void wl1271_set_band_rate(struct wl1271 *wl)
2059{
2060 if (wl->band == IEEE80211_BAND_2GHZ)
2061 wl->basic_rate_set = wl->conf.tx.basic_rate;
2062 else
2063 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2064}
2065
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002066static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002067{
2068 int ret;
2069
2070 if (idle) {
2071 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2072 ret = wl1271_unjoin(wl);
2073 if (ret < 0)
2074 goto out;
2075 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002076 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002077 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002078 if (ret < 0)
2079 goto out;
2080 ret = wl1271_acx_keep_alive_config(
2081 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2082 ACX_KEEP_ALIVE_TPL_INVALID);
2083 if (ret < 0)
2084 goto out;
2085 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2086 } else {
2087 /* increment the session counter */
2088 wl->session_counter++;
2089 if (wl->session_counter >= SESSION_COUNTER_MAX)
2090 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002091
2092 /* The current firmware only supports sched_scan in idle */
2093 if (wl->sched_scanning) {
2094 wl1271_scan_sched_scan_stop(wl);
2095 ieee80211_sched_scan_stopped(wl->hw);
2096 }
2097
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002098 ret = wl1271_dummy_join(wl);
2099 if (ret < 0)
2100 goto out;
2101 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2102 }
2103
2104out:
2105 return ret;
2106}
2107
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2109{
2110 struct wl1271 *wl = hw->priv;
2111 struct ieee80211_conf *conf = &hw->conf;
2112 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002113 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114
2115 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2116
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002117 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2118 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119 channel,
2120 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002121 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002122 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2123 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002124
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002125 /*
2126 * mac80211 will go to idle nearly immediately after transmitting some
2127 * frames, such as the deauth. To make sure those frames reach the air,
2128 * wait here until the TX queue is fully flushed.
2129 */
2130 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2131 (conf->flags & IEEE80211_CONF_IDLE))
2132 wl1271_tx_flush(wl);
2133
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134 mutex_lock(&wl->mutex);
2135
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002136 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002137 /* we support configuring the channel and band while off */
2138 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2139 wl->band = conf->channel->band;
2140 wl->channel = channel;
2141 }
2142
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002143 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002144 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002145
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002146 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2147
Ido Yariva6208652011-03-01 15:14:41 +02002148 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002149 if (ret < 0)
2150 goto out;
2151
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002152 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002153 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2154 ((wl->band != conf->channel->band) ||
2155 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002156 wl->band = conf->channel->band;
2157 wl->channel = channel;
2158
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002159 if (!is_ap) {
2160 /*
2161 * FIXME: the mac80211 should really provide a fixed
2162 * rate to use here. for now, just use the smallest
2163 * possible rate for the band as a fixed rate for
2164 * association frames and other control messages.
2165 */
2166 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2167 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002168
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002169 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2170 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002171 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002172 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002173 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002174
2175 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2176 ret = wl1271_join(wl, false);
2177 if (ret < 0)
2178 wl1271_warning("cmd join on channel "
2179 "failed %d", ret);
2180 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002181 }
2182 }
2183
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002184 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2185 ret = wl1271_sta_handle_idle(wl,
2186 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002187 if (ret < 0)
2188 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189 }
2190
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002191 /*
2192 * if mac80211 changes the PSM mode, make sure the mode is not
2193 * incorrectly changed after the pspoll failure active window.
2194 */
2195 if (changed & IEEE80211_CONF_CHANGE_PS)
2196 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2197
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002198 if (conf->flags & IEEE80211_CONF_PS &&
2199 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2200 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201
2202 /*
2203 * We enter PSM only if we're already associated.
2204 * If we're not, we'll enter it when joining an SSID,
2205 * through the bss_info_changed() hook.
2206 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002207 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002208 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002209 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002210 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002211 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002212 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002213 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002214 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002216 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002218 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002219 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002220 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221 }
2222
2223 if (conf->power_level != wl->power_level) {
2224 ret = wl1271_acx_tx_power(wl, conf->power_level);
2225 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002226 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002227
2228 wl->power_level = conf->power_level;
2229 }
2230
2231out_sleep:
2232 wl1271_ps_elp_sleep(wl);
2233
2234out:
2235 mutex_unlock(&wl->mutex);
2236
2237 return ret;
2238}
2239
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002240struct wl1271_filter_params {
2241 bool enabled;
2242 int mc_list_length;
2243 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2244};
2245
Jiri Pirko22bedad32010-04-01 21:22:57 +00002246static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2247 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002248{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002249 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002250 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002251 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002252
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002253 if (unlikely(wl->state == WL1271_STATE_OFF))
2254 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002255
Juuso Oikarinen74441132009-10-13 12:47:53 +03002256 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002257 if (!fp) {
2258 wl1271_error("Out of memory setting filters.");
2259 return 0;
2260 }
2261
2262 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002263 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002264 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2265 fp->enabled = false;
2266 } else {
2267 fp->enabled = true;
2268 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002269 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002270 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002271 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002272 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002273 }
2274
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002275 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002276}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002277
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002278#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2279 FIF_ALLMULTI | \
2280 FIF_FCSFAIL | \
2281 FIF_BCN_PRBRESP_PROMISC | \
2282 FIF_CONTROL | \
2283 FIF_OTHER_BSS)
2284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002285static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2286 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002287 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002289 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002291 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292
Arik Nemtsov7d057862010-10-16 19:25:35 +02002293 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2294 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002296 mutex_lock(&wl->mutex);
2297
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002298 *total &= WL1271_SUPPORTED_FILTERS;
2299 changed &= WL1271_SUPPORTED_FILTERS;
2300
2301 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002302 goto out;
2303
Ido Yariva6208652011-03-01 15:14:41 +02002304 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002305 if (ret < 0)
2306 goto out;
2307
Arik Nemtsov7d057862010-10-16 19:25:35 +02002308 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2309 if (*total & FIF_ALLMULTI)
2310 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2311 else if (fp)
2312 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2313 fp->mc_list,
2314 fp->mc_list_length);
2315 if (ret < 0)
2316 goto out_sleep;
2317 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002319 /* determine, whether supported filter values have changed */
2320 if (changed == 0)
2321 goto out_sleep;
2322
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002323 /* configure filters */
2324 wl->filters = *total;
2325 wl1271_configure_filters(wl, 0);
2326
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002327 /* apply configured filters */
2328 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2329 if (ret < 0)
2330 goto out_sleep;
2331
2332out_sleep:
2333 wl1271_ps_elp_sleep(wl);
2334
2335out:
2336 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002337 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338}
2339
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002340static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2341 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2342 u16 tx_seq_16)
2343{
2344 struct wl1271_ap_key *ap_key;
2345 int i;
2346
2347 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2348
2349 if (key_size > MAX_KEY_SIZE)
2350 return -EINVAL;
2351
2352 /*
2353 * Find next free entry in ap_keys. Also check we are not replacing
2354 * an existing key.
2355 */
2356 for (i = 0; i < MAX_NUM_KEYS; i++) {
2357 if (wl->recorded_ap_keys[i] == NULL)
2358 break;
2359
2360 if (wl->recorded_ap_keys[i]->id == id) {
2361 wl1271_warning("trying to record key replacement");
2362 return -EINVAL;
2363 }
2364 }
2365
2366 if (i == MAX_NUM_KEYS)
2367 return -EBUSY;
2368
2369 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2370 if (!ap_key)
2371 return -ENOMEM;
2372
2373 ap_key->id = id;
2374 ap_key->key_type = key_type;
2375 ap_key->key_size = key_size;
2376 memcpy(ap_key->key, key, key_size);
2377 ap_key->hlid = hlid;
2378 ap_key->tx_seq_32 = tx_seq_32;
2379 ap_key->tx_seq_16 = tx_seq_16;
2380
2381 wl->recorded_ap_keys[i] = ap_key;
2382 return 0;
2383}
2384
2385static void wl1271_free_ap_keys(struct wl1271 *wl)
2386{
2387 int i;
2388
2389 for (i = 0; i < MAX_NUM_KEYS; i++) {
2390 kfree(wl->recorded_ap_keys[i]);
2391 wl->recorded_ap_keys[i] = NULL;
2392 }
2393}
2394
2395static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2396{
2397 int i, ret = 0;
2398 struct wl1271_ap_key *key;
2399 bool wep_key_added = false;
2400
2401 for (i = 0; i < MAX_NUM_KEYS; i++) {
2402 if (wl->recorded_ap_keys[i] == NULL)
2403 break;
2404
2405 key = wl->recorded_ap_keys[i];
2406 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2407 key->id, key->key_type,
2408 key->key_size, key->key,
2409 key->hlid, key->tx_seq_32,
2410 key->tx_seq_16);
2411 if (ret < 0)
2412 goto out;
2413
2414 if (key->key_type == KEY_WEP)
2415 wep_key_added = true;
2416 }
2417
2418 if (wep_key_added) {
2419 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2420 if (ret < 0)
2421 goto out;
2422 }
2423
2424out:
2425 wl1271_free_ap_keys(wl);
2426 return ret;
2427}
2428
2429static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2430 u8 key_size, const u8 *key, u32 tx_seq_32,
2431 u16 tx_seq_16, struct ieee80211_sta *sta)
2432{
2433 int ret;
2434 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2435
2436 if (is_ap) {
2437 struct wl1271_station *wl_sta;
2438 u8 hlid;
2439
2440 if (sta) {
2441 wl_sta = (struct wl1271_station *)sta->drv_priv;
2442 hlid = wl_sta->hlid;
2443 } else {
2444 hlid = WL1271_AP_BROADCAST_HLID;
2445 }
2446
2447 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2448 /*
2449 * We do not support removing keys after AP shutdown.
2450 * Pretend we do to make mac80211 happy.
2451 */
2452 if (action != KEY_ADD_OR_REPLACE)
2453 return 0;
2454
2455 ret = wl1271_record_ap_key(wl, id,
2456 key_type, key_size,
2457 key, hlid, tx_seq_32,
2458 tx_seq_16);
2459 } else {
2460 ret = wl1271_cmd_set_ap_key(wl, action,
2461 id, key_type, key_size,
2462 key, hlid, tx_seq_32,
2463 tx_seq_16);
2464 }
2465
2466 if (ret < 0)
2467 return ret;
2468 } else {
2469 const u8 *addr;
2470 static const u8 bcast_addr[ETH_ALEN] = {
2471 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2472 };
2473
2474 addr = sta ? sta->addr : bcast_addr;
2475
2476 if (is_zero_ether_addr(addr)) {
2477 /* We dont support TX only encryption */
2478 return -EOPNOTSUPP;
2479 }
2480
2481 /* The wl1271 does not allow to remove unicast keys - they
2482 will be cleared automatically on next CMD_JOIN. Ignore the
2483 request silently, as we dont want the mac80211 to emit
2484 an error message. */
2485 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2486 return 0;
2487
2488 ret = wl1271_cmd_set_sta_key(wl, action,
2489 id, key_type, key_size,
2490 key, addr, tx_seq_32,
2491 tx_seq_16);
2492 if (ret < 0)
2493 return ret;
2494
2495 /* the default WEP key needs to be configured at least once */
2496 if (key_type == KEY_WEP) {
2497 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2498 wl->default_key);
2499 if (ret < 0)
2500 return ret;
2501 }
2502 }
2503
2504 return 0;
2505}
2506
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2508 struct ieee80211_vif *vif,
2509 struct ieee80211_sta *sta,
2510 struct ieee80211_key_conf *key_conf)
2511{
2512 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002513 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002514 u32 tx_seq_32 = 0;
2515 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002516 u8 key_type;
2517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2519
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002520 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002522 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002523 key_conf->keylen, key_conf->flags);
2524 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2525
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002526 mutex_lock(&wl->mutex);
2527
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002528 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2529 ret = -EAGAIN;
2530 goto out_unlock;
2531 }
2532
Ido Yariva6208652011-03-01 15:14:41 +02002533 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002534 if (ret < 0)
2535 goto out_unlock;
2536
Johannes Berg97359d12010-08-10 09:46:38 +02002537 switch (key_conf->cipher) {
2538 case WLAN_CIPHER_SUITE_WEP40:
2539 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540 key_type = KEY_WEP;
2541
2542 key_conf->hw_key_idx = key_conf->keyidx;
2543 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002544 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 key_type = KEY_TKIP;
2546
2547 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002548 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2549 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002550 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002551 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552 key_type = KEY_AES;
2553
2554 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002555 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2556 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002558 case WL1271_CIPHER_SUITE_GEM:
2559 key_type = KEY_GEM;
2560 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2561 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2562 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002564 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002565
2566 ret = -EOPNOTSUPP;
2567 goto out_sleep;
2568 }
2569
2570 switch (cmd) {
2571 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002572 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2573 key_conf->keyidx, key_type,
2574 key_conf->keylen, key_conf->key,
2575 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576 if (ret < 0) {
2577 wl1271_error("Could not add or replace key");
2578 goto out_sleep;
2579 }
2580 break;
2581
2582 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002583 ret = wl1271_set_key(wl, KEY_REMOVE,
2584 key_conf->keyidx, key_type,
2585 key_conf->keylen, key_conf->key,
2586 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 if (ret < 0) {
2588 wl1271_error("Could not remove key");
2589 goto out_sleep;
2590 }
2591 break;
2592
2593 default:
2594 wl1271_error("Unsupported key cmd 0x%x", cmd);
2595 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002596 break;
2597 }
2598
2599out_sleep:
2600 wl1271_ps_elp_sleep(wl);
2601
2602out_unlock:
2603 mutex_unlock(&wl->mutex);
2604
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 return ret;
2606}
2607
2608static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002609 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002610 struct cfg80211_scan_request *req)
2611{
2612 struct wl1271 *wl = hw->priv;
2613 int ret;
2614 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002615 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002616
2617 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2618
2619 if (req->n_ssids) {
2620 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002621 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002622 }
2623
2624 mutex_lock(&wl->mutex);
2625
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002626 if (wl->state == WL1271_STATE_OFF) {
2627 /*
2628 * We cannot return -EBUSY here because cfg80211 will expect
2629 * a call to ieee80211_scan_completed if we do - in this case
2630 * there won't be any call.
2631 */
2632 ret = -EAGAIN;
2633 goto out;
2634 }
2635
Ido Yariva6208652011-03-01 15:14:41 +02002636 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002637 if (ret < 0)
2638 goto out;
2639
Luciano Coelho5924f892010-08-04 03:46:22 +03002640 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002641
2642 wl1271_ps_elp_sleep(wl);
2643
2644out:
2645 mutex_unlock(&wl->mutex);
2646
2647 return ret;
2648}
2649
Luciano Coelho33c2c062011-05-10 14:46:02 +03002650static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2651 struct ieee80211_vif *vif,
2652 struct cfg80211_sched_scan_request *req,
2653 struct ieee80211_sched_scan_ies *ies)
2654{
2655 struct wl1271 *wl = hw->priv;
2656 int ret;
2657
2658 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2659
2660 mutex_lock(&wl->mutex);
2661
2662 ret = wl1271_ps_elp_wakeup(wl);
2663 if (ret < 0)
2664 goto out;
2665
2666 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2667 if (ret < 0)
2668 goto out_sleep;
2669
2670 ret = wl1271_scan_sched_scan_start(wl);
2671 if (ret < 0)
2672 goto out_sleep;
2673
2674 wl->sched_scanning = true;
2675
2676out_sleep:
2677 wl1271_ps_elp_sleep(wl);
2678out:
2679 mutex_unlock(&wl->mutex);
2680 return ret;
2681}
2682
2683static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2684 struct ieee80211_vif *vif)
2685{
2686 struct wl1271 *wl = hw->priv;
2687 int ret;
2688
2689 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2690
2691 mutex_lock(&wl->mutex);
2692
2693 ret = wl1271_ps_elp_wakeup(wl);
2694 if (ret < 0)
2695 goto out;
2696
2697 wl1271_scan_sched_scan_stop(wl);
2698
2699 wl1271_ps_elp_sleep(wl);
2700out:
2701 mutex_unlock(&wl->mutex);
2702}
2703
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002704static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2705{
2706 struct wl1271 *wl = hw->priv;
2707 int ret = 0;
2708
2709 mutex_lock(&wl->mutex);
2710
2711 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2712 ret = -EAGAIN;
2713 goto out;
2714 }
2715
Ido Yariva6208652011-03-01 15:14:41 +02002716 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002717 if (ret < 0)
2718 goto out;
2719
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002720 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002721 if (ret < 0)
2722 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2723
2724 wl1271_ps_elp_sleep(wl);
2725
2726out:
2727 mutex_unlock(&wl->mutex);
2728
2729 return ret;
2730}
2731
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2733{
2734 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002735 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736
2737 mutex_lock(&wl->mutex);
2738
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002739 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2740 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002741 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002742 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002743
Ido Yariva6208652011-03-01 15:14:41 +02002744 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002745 if (ret < 0)
2746 goto out;
2747
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002748 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749 if (ret < 0)
2750 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2751
2752 wl1271_ps_elp_sleep(wl);
2753
2754out:
2755 mutex_unlock(&wl->mutex);
2756
2757 return ret;
2758}
2759
Arik Nemtsove78a2872010-10-16 19:07:21 +02002760static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002761 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002762{
Eliad Peller889cb362011-05-01 09:56:45 +03002763 u8 ssid_len;
2764 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2765 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002766
Eliad Peller889cb362011-05-01 09:56:45 +03002767 if (!ptr) {
2768 wl1271_error("No SSID in IEs!");
2769 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002770 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002771
Eliad Peller889cb362011-05-01 09:56:45 +03002772 ssid_len = ptr[1];
2773 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2774 wl1271_error("SSID is too long!");
2775 return -EINVAL;
2776 }
2777
2778 wl->ssid_len = ssid_len;
2779 memcpy(wl->ssid, ptr+2, ssid_len);
2780 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002781}
2782
Arik Nemtsove78a2872010-10-16 19:07:21 +02002783static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2784 struct ieee80211_bss_conf *bss_conf,
2785 u32 changed)
2786{
2787 int ret = 0;
2788
2789 if (changed & BSS_CHANGED_ERP_SLOT) {
2790 if (bss_conf->use_short_slot)
2791 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2792 else
2793 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2794 if (ret < 0) {
2795 wl1271_warning("Set slot time failed %d", ret);
2796 goto out;
2797 }
2798 }
2799
2800 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2801 if (bss_conf->use_short_preamble)
2802 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2803 else
2804 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2805 }
2806
2807 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2808 if (bss_conf->use_cts_prot)
2809 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2810 else
2811 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2812 if (ret < 0) {
2813 wl1271_warning("Set ctsprotect failed %d", ret);
2814 goto out;
2815 }
2816 }
2817
2818out:
2819 return ret;
2820}
2821
2822static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2823 struct ieee80211_vif *vif,
2824 struct ieee80211_bss_conf *bss_conf,
2825 u32 changed)
2826{
2827 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2828 int ret = 0;
2829
2830 if ((changed & BSS_CHANGED_BEACON_INT)) {
2831 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2832 bss_conf->beacon_int);
2833
2834 wl->beacon_int = bss_conf->beacon_int;
2835 }
2836
2837 if ((changed & BSS_CHANGED_BEACON)) {
2838 struct ieee80211_hdr *hdr;
2839 int ieoffset = offsetof(struct ieee80211_mgmt,
2840 u.beacon.variable);
2841 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2842 u16 tmpl_id;
2843
2844 if (!beacon)
2845 goto out;
2846
2847 wl1271_debug(DEBUG_MASTER, "beacon updated");
2848
2849 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2850 if (ret < 0) {
2851 dev_kfree_skb(beacon);
2852 goto out;
2853 }
2854 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2855 CMD_TEMPL_BEACON;
2856 ret = wl1271_cmd_template_set(wl, tmpl_id,
2857 beacon->data,
2858 beacon->len, 0,
2859 wl1271_tx_min_rate_get(wl));
2860 if (ret < 0) {
2861 dev_kfree_skb(beacon);
2862 goto out;
2863 }
2864
2865 hdr = (struct ieee80211_hdr *) beacon->data;
2866 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2867 IEEE80211_STYPE_PROBE_RESP);
2868
2869 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2870 CMD_TEMPL_PROBE_RESPONSE;
2871 ret = wl1271_cmd_template_set(wl,
2872 tmpl_id,
2873 beacon->data,
2874 beacon->len, 0,
2875 wl1271_tx_min_rate_get(wl));
2876 dev_kfree_skb(beacon);
2877 if (ret < 0)
2878 goto out;
2879 }
2880
2881out:
2882 return ret;
2883}
2884
2885/* AP mode changes */
2886static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002887 struct ieee80211_vif *vif,
2888 struct ieee80211_bss_conf *bss_conf,
2889 u32 changed)
2890{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002891 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002892
Arik Nemtsove78a2872010-10-16 19:07:21 +02002893 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2894 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002895
Arik Nemtsove78a2872010-10-16 19:07:21 +02002896 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2897 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898
Arik Nemtsov70f47422011-04-18 14:15:25 +03002899 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002900 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002901 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002902 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002903 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002904
2905 ret = wl1271_ap_init_templates(wl);
2906 if (ret < 0)
2907 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002908 }
2909
Arik Nemtsove78a2872010-10-16 19:07:21 +02002910 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2911 if (ret < 0)
2912 goto out;
2913
2914 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2915 if (bss_conf->enable_beacon) {
2916 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2917 ret = wl1271_cmd_start_bss(wl);
2918 if (ret < 0)
2919 goto out;
2920
2921 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2922 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002923
2924 ret = wl1271_ap_init_hwenc(wl);
2925 if (ret < 0)
2926 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002927 }
2928 } else {
2929 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2930 ret = wl1271_cmd_stop_bss(wl);
2931 if (ret < 0)
2932 goto out;
2933
2934 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2935 wl1271_debug(DEBUG_AP, "stopped AP");
2936 }
2937 }
2938 }
2939
2940 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2941 if (ret < 0)
2942 goto out;
2943out:
2944 return;
2945}
2946
2947/* STA/IBSS mode changes */
2948static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2949 struct ieee80211_vif *vif,
2950 struct ieee80211_bss_conf *bss_conf,
2951 u32 changed)
2952{
2953 bool do_join = false, set_assoc = false;
2954 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002955 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002956 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002957 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002958 bool sta_exists = false;
2959 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002960
2961 if (is_ibss) {
2962 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2963 changed);
2964 if (ret < 0)
2965 goto out;
2966 }
2967
2968 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2969 do_join = true;
2970
2971 /* Need to update the SSID (for filtering etc) */
2972 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2973 do_join = true;
2974
2975 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002976 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2977 bss_conf->enable_beacon ? "enabled" : "disabled");
2978
2979 if (bss_conf->enable_beacon)
2980 wl->set_bss_type = BSS_TYPE_IBSS;
2981 else
2982 wl->set_bss_type = BSS_TYPE_STA_BSS;
2983 do_join = true;
2984 }
2985
Arik Nemtsove78a2872010-10-16 19:07:21 +02002986 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002987 bool enable = false;
2988 if (bss_conf->cqm_rssi_thold)
2989 enable = true;
2990 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2991 bss_conf->cqm_rssi_thold,
2992 bss_conf->cqm_rssi_hyst);
2993 if (ret < 0)
2994 goto out;
2995 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2996 }
2997
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002998 if ((changed & BSS_CHANGED_BSSID) &&
2999 /*
3000 * Now we know the correct bssid, so we send a new join command
3001 * and enable the BSSID filter
3002 */
3003 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003004 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003005
Eliad Pellerfa287b82010-12-26 09:27:50 +01003006 if (!is_zero_ether_addr(wl->bssid)) {
3007 ret = wl1271_cmd_build_null_data(wl);
3008 if (ret < 0)
3009 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003010
Eliad Pellerfa287b82010-12-26 09:27:50 +01003011 ret = wl1271_build_qos_null_data(wl);
3012 if (ret < 0)
3013 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003014
Eliad Pellerfa287b82010-12-26 09:27:50 +01003015 /* filter out all packets not from this BSSID */
3016 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02003017
Eliad Pellerfa287b82010-12-26 09:27:50 +01003018 /* Need to update the BSSID (for filtering etc) */
3019 do_join = true;
3020 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003021 }
3022
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003023 rcu_read_lock();
3024 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3025 if (sta) {
3026 /* save the supp_rates of the ap */
3027 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3028 if (sta->ht_cap.ht_supported)
3029 sta_rate_set |=
3030 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003031 sta_ht_cap = sta->ht_cap;
3032 sta_exists = true;
3033 }
3034 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003035
Arik Nemtsova1008852011-02-12 23:24:20 +02003036 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003037 /* handle new association with HT and HT information change */
3038 if ((changed & BSS_CHANGED_HT) &&
3039 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003040 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003041 true);
3042 if (ret < 0) {
3043 wl1271_warning("Set ht cap true failed %d",
3044 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003045 goto out;
3046 }
3047 ret = wl1271_acx_set_ht_information(wl,
3048 bss_conf->ht_operation_mode);
3049 if (ret < 0) {
3050 wl1271_warning("Set ht information failed %d",
3051 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003052 goto out;
3053 }
3054 }
3055 /* handle new association without HT and disassociation */
3056 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003057 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003058 false);
3059 if (ret < 0) {
3060 wl1271_warning("Set ht cap false failed %d",
3061 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003062 goto out;
3063 }
3064 }
3065 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003066
Arik Nemtsove78a2872010-10-16 19:07:21 +02003067 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003068 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003069 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003070 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003071 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003072 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003074 wl->ps_poll_failures = 0;
3075
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003076 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003077 * use basic rates from AP, and determine lowest rate
3078 * to use with control frames.
3079 */
3080 rates = bss_conf->basic_rates;
3081 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3082 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003083 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003084 if (sta_rate_set)
3085 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3086 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003087 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003088 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003089 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003090
3091 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003092 * with wl1271, we don't need to update the
3093 * beacon_int and dtim_period, because the firmware
3094 * updates it by itself when the first beacon is
3095 * received after a join.
3096 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003097 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3098 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003099 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003100
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003101 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003102 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003103 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003104 dev_kfree_skb(wl->probereq);
3105 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3106 ieoffset = offsetof(struct ieee80211_mgmt,
3107 u.probe_req.variable);
3108 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003109
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003110 /* enable the connection monitoring feature */
3111 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003112 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003113 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114
3115 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003116 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3117 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003118 enum wl1271_cmd_ps_mode mode;
3119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003120 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003121 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003122 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003123 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003124 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003125 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003126 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003127 } else {
3128 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003129 bool was_assoc =
3130 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3131 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003132 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003133 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003134
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003135 /* free probe-request template */
3136 dev_kfree_skb(wl->probereq);
3137 wl->probereq = NULL;
3138
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003139 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003140 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003141
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003142 /* revert back to minimum rates for the current band */
3143 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003144 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003145 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003146 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003147 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003148
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003149 /* disable connection monitor features */
3150 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003151
3152 /* Disable the keep-alive feature */
3153 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003154 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003155 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003156
3157 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003158 if (was_assoc) {
3159 wl1271_unjoin(wl);
3160 wl1271_dummy_join(wl);
3161 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003162 }
3163 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003164
Eliad Pellerd192d262011-05-24 14:33:08 +03003165 if (changed & BSS_CHANGED_IBSS) {
3166 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3167 bss_conf->ibss_joined);
3168
3169 if (bss_conf->ibss_joined) {
3170 u32 rates = bss_conf->basic_rates;
3171 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3172 rates);
3173 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3174
3175 /* by default, use 11b rates */
3176 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3177 ret = wl1271_acx_sta_rate_policies(wl);
3178 if (ret < 0)
3179 goto out;
3180 }
3181 }
3182
Arik Nemtsove78a2872010-10-16 19:07:21 +02003183 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3184 if (ret < 0)
3185 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003186
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003187 if (changed & BSS_CHANGED_ARP_FILTER) {
3188 __be32 addr = bss_conf->arp_addr_list[0];
3189 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3190
Eliad Pellerc5312772010-12-09 11:31:27 +02003191 if (bss_conf->arp_addr_cnt == 1 &&
3192 bss_conf->arp_filter_enabled) {
3193 /*
3194 * The template should have been configured only upon
3195 * association. however, it seems that the correct ip
3196 * isn't being set (when sending), so we have to
3197 * reconfigure the template upon every ip change.
3198 */
3199 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3200 if (ret < 0) {
3201 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003202 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003203 }
3204
3205 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003206 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003207 addr);
3208 } else
3209 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003210
3211 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003212 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003213 }
3214
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003215 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003216 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003217 if (ret < 0) {
3218 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003219 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003220 }
Eliad Pelleref4b29e2011-06-06 13:03:12 +03003221 wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003222 }
3223
Arik Nemtsove78a2872010-10-16 19:07:21 +02003224out:
3225 return;
3226}
3227
3228static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3229 struct ieee80211_vif *vif,
3230 struct ieee80211_bss_conf *bss_conf,
3231 u32 changed)
3232{
3233 struct wl1271 *wl = hw->priv;
3234 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3235 int ret;
3236
3237 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3238 (int)changed);
3239
3240 mutex_lock(&wl->mutex);
3241
3242 if (unlikely(wl->state == WL1271_STATE_OFF))
3243 goto out;
3244
Ido Yariva6208652011-03-01 15:14:41 +02003245 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003246 if (ret < 0)
3247 goto out;
3248
3249 if (is_ap)
3250 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3251 else
3252 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3253
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003254 wl1271_ps_elp_sleep(wl);
3255
3256out:
3257 mutex_unlock(&wl->mutex);
3258}
3259
Kalle Valoc6999d82010-02-18 13:25:41 +02003260static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3261 const struct ieee80211_tx_queue_params *params)
3262{
3263 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003264 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003265 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003266
3267 mutex_lock(&wl->mutex);
3268
3269 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3270
Kalle Valo4695dc92010-03-18 12:26:38 +02003271 if (params->uapsd)
3272 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3273 else
3274 ps_scheme = CONF_PS_SCHEME_LEGACY;
3275
Arik Nemtsov488fc542010-10-16 20:33:45 +02003276 if (wl->state == WL1271_STATE_OFF) {
3277 /*
3278 * If the state is off, the parameters will be recorded and
3279 * configured on init. This happens in AP-mode.
3280 */
3281 struct conf_tx_ac_category *conf_ac =
3282 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3283 struct conf_tx_tid *conf_tid =
3284 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3285
3286 conf_ac->ac = wl1271_tx_get_queue(queue);
3287 conf_ac->cw_min = (u8)params->cw_min;
3288 conf_ac->cw_max = params->cw_max;
3289 conf_ac->aifsn = params->aifs;
3290 conf_ac->tx_op_limit = params->txop << 5;
3291
3292 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3293 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3294 conf_tid->tsid = wl1271_tx_get_queue(queue);
3295 conf_tid->ps_scheme = ps_scheme;
3296 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3297 conf_tid->apsd_conf[0] = 0;
3298 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003299 goto out;
3300 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003301
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003302 ret = wl1271_ps_elp_wakeup(wl);
3303 if (ret < 0)
3304 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003305
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003306 /*
3307 * the txop is confed in units of 32us by the mac80211,
3308 * we need us
3309 */
3310 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3311 params->cw_min, params->cw_max,
3312 params->aifs, params->txop << 5);
3313 if (ret < 0)
3314 goto out_sleep;
3315
3316 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3317 CONF_CHANNEL_TYPE_EDCF,
3318 wl1271_tx_get_queue(queue),
3319 ps_scheme, CONF_ACK_POLICY_LEGACY,
3320 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003321
3322out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003323 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003324
3325out:
3326 mutex_unlock(&wl->mutex);
3327
3328 return ret;
3329}
3330
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003331static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3332{
3333
3334 struct wl1271 *wl = hw->priv;
3335 u64 mactime = ULLONG_MAX;
3336 int ret;
3337
3338 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3339
3340 mutex_lock(&wl->mutex);
3341
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003342 if (unlikely(wl->state == WL1271_STATE_OFF))
3343 goto out;
3344
Ido Yariva6208652011-03-01 15:14:41 +02003345 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003346 if (ret < 0)
3347 goto out;
3348
3349 ret = wl1271_acx_tsf_info(wl, &mactime);
3350 if (ret < 0)
3351 goto out_sleep;
3352
3353out_sleep:
3354 wl1271_ps_elp_sleep(wl);
3355
3356out:
3357 mutex_unlock(&wl->mutex);
3358 return mactime;
3359}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003360
John W. Linvilleece550d2010-07-28 16:41:06 -04003361static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3362 struct survey_info *survey)
3363{
3364 struct wl1271 *wl = hw->priv;
3365 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003366
John W. Linvilleece550d2010-07-28 16:41:06 -04003367 if (idx != 0)
3368 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003369
John W. Linvilleece550d2010-07-28 16:41:06 -04003370 survey->channel = conf->channel;
3371 survey->filled = SURVEY_INFO_NOISE_DBM;
3372 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003373
John W. Linvilleece550d2010-07-28 16:41:06 -04003374 return 0;
3375}
3376
Arik Nemtsov409622e2011-02-23 00:22:29 +02003377static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003378 struct ieee80211_sta *sta,
3379 u8 *hlid)
3380{
3381 struct wl1271_station *wl_sta;
3382 int id;
3383
3384 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3385 if (id >= AP_MAX_STATIONS) {
3386 wl1271_warning("could not allocate HLID - too much stations");
3387 return -EBUSY;
3388 }
3389
3390 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003391 __set_bit(id, wl->ap_hlid_map);
3392 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3393 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003394 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003395 return 0;
3396}
3397
Arik Nemtsov409622e2011-02-23 00:22:29 +02003398static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003399{
3400 int id = hlid - WL1271_AP_STA_HLID_START;
3401
Arik Nemtsov409622e2011-02-23 00:22:29 +02003402 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3403 return;
3404
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003405 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003406 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003407 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003408 __clear_bit(hlid, &wl->ap_ps_map);
3409 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003410}
3411
3412static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3413 struct ieee80211_vif *vif,
3414 struct ieee80211_sta *sta)
3415{
3416 struct wl1271 *wl = hw->priv;
3417 int ret = 0;
3418 u8 hlid;
3419
3420 mutex_lock(&wl->mutex);
3421
3422 if (unlikely(wl->state == WL1271_STATE_OFF))
3423 goto out;
3424
3425 if (wl->bss_type != BSS_TYPE_AP_BSS)
3426 goto out;
3427
3428 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3429
Arik Nemtsov409622e2011-02-23 00:22:29 +02003430 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003431 if (ret < 0)
3432 goto out;
3433
Ido Yariva6208652011-03-01 15:14:41 +02003434 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003435 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003436 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003437
3438 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3439 if (ret < 0)
3440 goto out_sleep;
3441
3442out_sleep:
3443 wl1271_ps_elp_sleep(wl);
3444
Arik Nemtsov409622e2011-02-23 00:22:29 +02003445out_free_sta:
3446 if (ret < 0)
3447 wl1271_free_sta(wl, hlid);
3448
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003449out:
3450 mutex_unlock(&wl->mutex);
3451 return ret;
3452}
3453
3454static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3455 struct ieee80211_vif *vif,
3456 struct ieee80211_sta *sta)
3457{
3458 struct wl1271 *wl = hw->priv;
3459 struct wl1271_station *wl_sta;
3460 int ret = 0, id;
3461
3462 mutex_lock(&wl->mutex);
3463
3464 if (unlikely(wl->state == WL1271_STATE_OFF))
3465 goto out;
3466
3467 if (wl->bss_type != BSS_TYPE_AP_BSS)
3468 goto out;
3469
3470 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3471
3472 wl_sta = (struct wl1271_station *)sta->drv_priv;
3473 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3474 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3475 goto out;
3476
Ido Yariva6208652011-03-01 15:14:41 +02003477 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003478 if (ret < 0)
3479 goto out;
3480
3481 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3482 if (ret < 0)
3483 goto out_sleep;
3484
Arik Nemtsov409622e2011-02-23 00:22:29 +02003485 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003486
3487out_sleep:
3488 wl1271_ps_elp_sleep(wl);
3489
3490out:
3491 mutex_unlock(&wl->mutex);
3492 return ret;
3493}
3494
Luciano Coelho4623ec72011-03-21 19:26:41 +02003495static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3496 struct ieee80211_vif *vif,
3497 enum ieee80211_ampdu_mlme_action action,
3498 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3499 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003500{
3501 struct wl1271 *wl = hw->priv;
3502 int ret;
3503
3504 mutex_lock(&wl->mutex);
3505
3506 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3507 ret = -EAGAIN;
3508 goto out;
3509 }
3510
Ido Yariva6208652011-03-01 15:14:41 +02003511 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003512 if (ret < 0)
3513 goto out;
3514
Shahar Levi70559a02011-05-22 16:10:22 +03003515 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3516 tid, action);
3517
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003518 switch (action) {
3519 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003520 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003521 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3522 true);
3523 if (!ret)
3524 wl->ba_rx_bitmap |= BIT(tid);
3525 } else {
3526 ret = -ENOTSUPP;
3527 }
3528 break;
3529
3530 case IEEE80211_AMPDU_RX_STOP:
3531 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3532 if (!ret)
3533 wl->ba_rx_bitmap &= ~BIT(tid);
3534 break;
3535
3536 /*
3537 * The BA initiator session management in FW independently.
3538 * Falling break here on purpose for all TX APDU commands.
3539 */
3540 case IEEE80211_AMPDU_TX_START:
3541 case IEEE80211_AMPDU_TX_STOP:
3542 case IEEE80211_AMPDU_TX_OPERATIONAL:
3543 ret = -EINVAL;
3544 break;
3545
3546 default:
3547 wl1271_error("Incorrect ampdu action id=%x\n", action);
3548 ret = -EINVAL;
3549 }
3550
3551 wl1271_ps_elp_sleep(wl);
3552
3553out:
3554 mutex_unlock(&wl->mutex);
3555
3556 return ret;
3557}
3558
Arik Nemtsov33437892011-04-26 23:35:39 +03003559static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3560{
3561 struct wl1271 *wl = hw->priv;
3562 bool ret = false;
3563
3564 mutex_lock(&wl->mutex);
3565
3566 if (unlikely(wl->state == WL1271_STATE_OFF))
3567 goto out;
3568
3569 /* packets are considered pending if in the TX queue or the FW */
3570 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3571
3572 /* the above is appropriate for STA mode for PS purposes */
3573 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3574
3575out:
3576 mutex_unlock(&wl->mutex);
3577
3578 return ret;
3579}
3580
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003581/* can't be const, mac80211 writes to this */
3582static struct ieee80211_rate wl1271_rates[] = {
3583 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003584 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3585 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003586 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003587 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3588 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003589 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3590 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003591 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3592 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003593 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3594 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003595 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3596 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3598 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003599 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3600 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003601 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003602 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3603 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003604 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003605 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3606 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003607 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003608 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3609 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003610 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003611 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3612 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003613 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003614 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3615 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003616 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003617 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3618 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003619 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003620 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3621 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003622};
3623
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003624/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003625static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003626 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003627 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003628 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3629 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3630 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003631 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003632 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3633 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3634 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003635 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003636 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3637 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3638 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003639 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003640};
3641
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003642/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003643static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003644 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003645 7, /* CONF_HW_RXTX_RATE_MCS7 */
3646 6, /* CONF_HW_RXTX_RATE_MCS6 */
3647 5, /* CONF_HW_RXTX_RATE_MCS5 */
3648 4, /* CONF_HW_RXTX_RATE_MCS4 */
3649 3, /* CONF_HW_RXTX_RATE_MCS3 */
3650 2, /* CONF_HW_RXTX_RATE_MCS2 */
3651 1, /* CONF_HW_RXTX_RATE_MCS1 */
3652 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003653
3654 11, /* CONF_HW_RXTX_RATE_54 */
3655 10, /* CONF_HW_RXTX_RATE_48 */
3656 9, /* CONF_HW_RXTX_RATE_36 */
3657 8, /* CONF_HW_RXTX_RATE_24 */
3658
3659 /* TI-specific rate */
3660 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3661
3662 7, /* CONF_HW_RXTX_RATE_18 */
3663 6, /* CONF_HW_RXTX_RATE_12 */
3664 3, /* CONF_HW_RXTX_RATE_11 */
3665 5, /* CONF_HW_RXTX_RATE_9 */
3666 4, /* CONF_HW_RXTX_RATE_6 */
3667 2, /* CONF_HW_RXTX_RATE_5_5 */
3668 1, /* CONF_HW_RXTX_RATE_2 */
3669 0 /* CONF_HW_RXTX_RATE_1 */
3670};
3671
Shahar Levie8b03a22010-10-13 16:09:39 +02003672/* 11n STA capabilities */
3673#define HW_RX_HIGHEST_RATE 72
3674
Shahar Levi00d20102010-11-08 11:20:10 +00003675#ifdef CONFIG_WL12XX_HT
3676#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003677 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3678 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003679 .ht_supported = true, \
3680 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3681 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3682 .mcs = { \
3683 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3684 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3685 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3686 }, \
3687}
Shahar Levi18357852010-10-13 16:09:41 +02003688#else
Shahar Levi00d20102010-11-08 11:20:10 +00003689#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003690 .ht_supported = false, \
3691}
3692#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003693
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003694/* can't be const, mac80211 writes to this */
3695static struct ieee80211_supported_band wl1271_band_2ghz = {
3696 .channels = wl1271_channels,
3697 .n_channels = ARRAY_SIZE(wl1271_channels),
3698 .bitrates = wl1271_rates,
3699 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003700 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003701};
3702
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003703/* 5 GHz data rates for WL1273 */
3704static struct ieee80211_rate wl1271_rates_5ghz[] = {
3705 { .bitrate = 60,
3706 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3707 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3708 { .bitrate = 90,
3709 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3710 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3711 { .bitrate = 120,
3712 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3713 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3714 { .bitrate = 180,
3715 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3716 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3717 { .bitrate = 240,
3718 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3719 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3720 { .bitrate = 360,
3721 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3722 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3723 { .bitrate = 480,
3724 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3725 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3726 { .bitrate = 540,
3727 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3728 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3729};
3730
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003731/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003732static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003733 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003734 { .hw_value = 8, .center_freq = 5040},
3735 { .hw_value = 9, .center_freq = 5045},
3736 { .hw_value = 11, .center_freq = 5055},
3737 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003738 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003739 { .hw_value = 34, .center_freq = 5170},
3740 { .hw_value = 36, .center_freq = 5180},
3741 { .hw_value = 38, .center_freq = 5190},
3742 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003743 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003744 { .hw_value = 44, .center_freq = 5220},
3745 { .hw_value = 46, .center_freq = 5230},
3746 { .hw_value = 48, .center_freq = 5240},
3747 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003748 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003749 { .hw_value = 60, .center_freq = 5300},
3750 { .hw_value = 64, .center_freq = 5320},
3751 { .hw_value = 100, .center_freq = 5500},
3752 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003753 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003754 { .hw_value = 112, .center_freq = 5560},
3755 { .hw_value = 116, .center_freq = 5580},
3756 { .hw_value = 120, .center_freq = 5600},
3757 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003758 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003759 { .hw_value = 132, .center_freq = 5660},
3760 { .hw_value = 136, .center_freq = 5680},
3761 { .hw_value = 140, .center_freq = 5700},
3762 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003763 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003764 { .hw_value = 157, .center_freq = 5785},
3765 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003766 { .hw_value = 165, .center_freq = 5825},
3767};
3768
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003769/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003770static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003771 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003772 7, /* CONF_HW_RXTX_RATE_MCS7 */
3773 6, /* CONF_HW_RXTX_RATE_MCS6 */
3774 5, /* CONF_HW_RXTX_RATE_MCS5 */
3775 4, /* CONF_HW_RXTX_RATE_MCS4 */
3776 3, /* CONF_HW_RXTX_RATE_MCS3 */
3777 2, /* CONF_HW_RXTX_RATE_MCS2 */
3778 1, /* CONF_HW_RXTX_RATE_MCS1 */
3779 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003780
3781 7, /* CONF_HW_RXTX_RATE_54 */
3782 6, /* CONF_HW_RXTX_RATE_48 */
3783 5, /* CONF_HW_RXTX_RATE_36 */
3784 4, /* CONF_HW_RXTX_RATE_24 */
3785
3786 /* TI-specific rate */
3787 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3788
3789 3, /* CONF_HW_RXTX_RATE_18 */
3790 2, /* CONF_HW_RXTX_RATE_12 */
3791 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3792 1, /* CONF_HW_RXTX_RATE_9 */
3793 0, /* CONF_HW_RXTX_RATE_6 */
3794 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3795 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3796 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3797};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003798
3799static struct ieee80211_supported_band wl1271_band_5ghz = {
3800 .channels = wl1271_channels_5ghz,
3801 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3802 .bitrates = wl1271_rates_5ghz,
3803 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003804 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003805};
3806
Tobias Klausera0ea9492010-05-20 10:38:11 +02003807static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003808 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3809 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3810};
3811
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003812static const struct ieee80211_ops wl1271_ops = {
3813 .start = wl1271_op_start,
3814 .stop = wl1271_op_stop,
3815 .add_interface = wl1271_op_add_interface,
3816 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003817#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003818 .suspend = wl1271_op_suspend,
3819 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003820#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003821 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003822 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003823 .configure_filter = wl1271_op_configure_filter,
3824 .tx = wl1271_op_tx,
3825 .set_key = wl1271_op_set_key,
3826 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003827 .sched_scan_start = wl1271_op_sched_scan_start,
3828 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003829 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003830 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003831 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003832 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003833 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003834 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003835 .sta_add = wl1271_op_sta_add,
3836 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003837 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003838 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003839 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003840};
3841
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003842
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003843u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003844{
3845 u8 idx;
3846
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003847 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003848
3849 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3850 wl1271_error("Illegal RX rate from HW: %d", rate);
3851 return 0;
3852 }
3853
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003854 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003855 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3856 wl1271_error("Unsupported RX rate from HW: %d", rate);
3857 return 0;
3858 }
3859
3860 return idx;
3861}
3862
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003863static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3864 struct device_attribute *attr,
3865 char *buf)
3866{
3867 struct wl1271 *wl = dev_get_drvdata(dev);
3868 ssize_t len;
3869
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003870 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003871
3872 mutex_lock(&wl->mutex);
3873 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3874 wl->sg_enabled);
3875 mutex_unlock(&wl->mutex);
3876
3877 return len;
3878
3879}
3880
3881static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3882 struct device_attribute *attr,
3883 const char *buf, size_t count)
3884{
3885 struct wl1271 *wl = dev_get_drvdata(dev);
3886 unsigned long res;
3887 int ret;
3888
Luciano Coelho6277ed62011-04-01 17:49:54 +03003889 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003890 if (ret < 0) {
3891 wl1271_warning("incorrect value written to bt_coex_mode");
3892 return count;
3893 }
3894
3895 mutex_lock(&wl->mutex);
3896
3897 res = !!res;
3898
3899 if (res == wl->sg_enabled)
3900 goto out;
3901
3902 wl->sg_enabled = res;
3903
3904 if (wl->state == WL1271_STATE_OFF)
3905 goto out;
3906
Ido Yariva6208652011-03-01 15:14:41 +02003907 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003908 if (ret < 0)
3909 goto out;
3910
3911 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3912 wl1271_ps_elp_sleep(wl);
3913
3914 out:
3915 mutex_unlock(&wl->mutex);
3916 return count;
3917}
3918
3919static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3920 wl1271_sysfs_show_bt_coex_state,
3921 wl1271_sysfs_store_bt_coex_state);
3922
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003923static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3924 struct device_attribute *attr,
3925 char *buf)
3926{
3927 struct wl1271 *wl = dev_get_drvdata(dev);
3928 ssize_t len;
3929
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003930 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003931
3932 mutex_lock(&wl->mutex);
3933 if (wl->hw_pg_ver >= 0)
3934 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3935 else
3936 len = snprintf(buf, len, "n/a\n");
3937 mutex_unlock(&wl->mutex);
3938
3939 return len;
3940}
3941
3942static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3943 wl1271_sysfs_show_hw_pg_ver, NULL);
3944
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003945int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003946{
3947 int ret;
3948
3949 if (wl->mac80211_registered)
3950 return 0;
3951
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003952 ret = wl1271_fetch_nvs(wl);
3953 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003954 /* NOTE: The wl->nvs->nvs element must be first, in
3955 * order to simplify the casting, we assume it is at
3956 * the beginning of the wl->nvs structure.
3957 */
3958 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003959
3960 wl->mac_addr[0] = nvs_ptr[11];
3961 wl->mac_addr[1] = nvs_ptr[10];
3962 wl->mac_addr[2] = nvs_ptr[6];
3963 wl->mac_addr[3] = nvs_ptr[5];
3964 wl->mac_addr[4] = nvs_ptr[4];
3965 wl->mac_addr[5] = nvs_ptr[3];
3966 }
3967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003968 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3969
3970 ret = ieee80211_register_hw(wl->hw);
3971 if (ret < 0) {
3972 wl1271_error("unable to register mac80211 hw: %d", ret);
3973 return ret;
3974 }
3975
3976 wl->mac80211_registered = true;
3977
Eliad Pellerd60080a2010-11-24 12:53:16 +02003978 wl1271_debugfs_init(wl);
3979
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003980 register_netdevice_notifier(&wl1271_dev_notifier);
3981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003982 wl1271_notice("loaded");
3983
3984 return 0;
3985}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003986EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003987
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003988void wl1271_unregister_hw(struct wl1271 *wl)
3989{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003990 if (wl->state == WL1271_STATE_PLT)
3991 __wl1271_plt_stop(wl);
3992
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003993 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003994 ieee80211_unregister_hw(wl->hw);
3995 wl->mac80211_registered = false;
3996
3997}
3998EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3999
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004000int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004001{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004002 static const u32 cipher_suites[] = {
4003 WLAN_CIPHER_SUITE_WEP40,
4004 WLAN_CIPHER_SUITE_WEP104,
4005 WLAN_CIPHER_SUITE_TKIP,
4006 WLAN_CIPHER_SUITE_CCMP,
4007 WL1271_CIPHER_SUITE_GEM,
4008 };
4009
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004010 /* The tx descriptor buffer and the TKIP space. */
4011 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4012 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004013
4014 /* unit us */
4015 /* FIXME: find a proper value */
4016 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004017 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004018
4019 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004020 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004021 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004022 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004023 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004024 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004025 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004026 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004027 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004028 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004029
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004030 wl->hw->wiphy->cipher_suites = cipher_suites;
4031 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4032
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004033 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004034 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004035 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004036 /*
4037 * Maximum length of elements in scanning probe request templates
4038 * should be the maximum length possible for a template, without
4039 * the IEEE80211 header of the template
4040 */
4041 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
4042 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004043
Luciano Coelho4a31c112011-03-21 23:16:14 +02004044 /* make sure all our channels fit in the scanned_ch bitmask */
4045 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4046 ARRAY_SIZE(wl1271_channels_5ghz) >
4047 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004048 /*
4049 * We keep local copies of the band structs because we need to
4050 * modify them on a per-device basis.
4051 */
4052 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4053 sizeof(wl1271_band_2ghz));
4054 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4055 sizeof(wl1271_band_5ghz));
4056
4057 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4058 &wl->bands[IEEE80211_BAND_2GHZ];
4059 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4060 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004061
Kalle Valo12bd8942010-03-18 12:26:33 +02004062 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004063 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004064
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004065 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4066
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004067 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004068
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004069 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4070
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004071 wl->hw->max_rx_aggregation_subframes = 8;
4072
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004073 return 0;
4074}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004075EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004076
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004077#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004078
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004079struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004080{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004081 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004082 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004083 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004084 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004085 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004086
4087 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4088 if (!hw) {
4089 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004090 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004091 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004092 }
4093
Julia Lawall929ebd32010-05-15 23:16:39 +02004094 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004095 if (!plat_dev) {
4096 wl1271_error("could not allocate platform_device");
4097 ret = -ENOMEM;
4098 goto err_plat_alloc;
4099 }
4100
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004101 wl = hw->priv;
4102 memset(wl, 0, sizeof(*wl));
4103
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004104 INIT_LIST_HEAD(&wl->list);
4105
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004106 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004107 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004108
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004109 for (i = 0; i < NUM_TX_QUEUES; i++)
4110 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004111
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004112 for (i = 0; i < NUM_TX_QUEUES; i++)
4113 for (j = 0; j < AP_MAX_LINKS; j++)
4114 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4115
Ido Yariva6208652011-03-01 15:14:41 +02004116 skb_queue_head_init(&wl->deferred_rx_queue);
4117 skb_queue_head_init(&wl->deferred_tx_queue);
4118
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004119 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004120 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004121 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004122 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4123 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4124 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004125 INIT_WORK(&wl->rx_streaming_enable_work,
4126 wl1271_rx_streaming_enable_work);
4127 INIT_WORK(&wl->rx_streaming_disable_work,
4128 wl1271_rx_streaming_disable_work);
4129
Eliad Peller92ef8962011-06-07 12:50:46 +03004130 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4131 if (!wl->freezable_wq) {
4132 ret = -ENOMEM;
4133 goto err_hw;
4134 }
4135
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004136 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004137 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004138 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004139 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02004140 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
4141 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004142 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004143 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004144 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004145 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004146 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004147 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004148 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004149 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004150 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004151 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004152 wl->bss_type = MAX_BSS_TYPE;
4153 wl->set_bss_type = MAX_BSS_TYPE;
4154 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004155 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004156 wl->ap_ps_map = 0;
4157 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004158 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004159 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004160 wl->sched_scanning = false;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004161 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4162 (unsigned long) wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004163
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004164 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004165 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004166 wl->tx_frames[i] = NULL;
4167
4168 spin_lock_init(&wl->wl_lock);
4169
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004170 wl->state = WL1271_STATE_OFF;
4171 mutex_init(&wl->mutex);
4172
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004173 /* Apply default driver configuration. */
4174 wl1271_conf_init(wl);
4175
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004176 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4177 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4178 if (!wl->aggr_buf) {
4179 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004180 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004181 }
4182
Ido Yariv990f5de2011-03-31 10:06:59 +02004183 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4184 if (!wl->dummy_packet) {
4185 ret = -ENOMEM;
4186 goto err_aggr;
4187 }
4188
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004189 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004190 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004191 if (ret) {
4192 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004193 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004194 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004195 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004196
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004197 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004198 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004199 if (ret < 0) {
4200 wl1271_error("failed to create sysfs file bt_coex_state");
4201 goto err_platform;
4202 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004203
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004204 /* Create sysfs file to get HW PG version */
4205 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4206 if (ret < 0) {
4207 wl1271_error("failed to create sysfs file hw_pg_ver");
4208 goto err_bt_coex_state;
4209 }
4210
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004211 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004212
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004213err_bt_coex_state:
4214 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4215
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004216err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004217 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004218
Ido Yariv990f5de2011-03-31 10:06:59 +02004219err_dummy_packet:
4220 dev_kfree_skb(wl->dummy_packet);
4221
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004222err_aggr:
4223 free_pages((unsigned long)wl->aggr_buf, order);
4224
Eliad Peller92ef8962011-06-07 12:50:46 +03004225err_wq:
4226 destroy_workqueue(wl->freezable_wq);
4227
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004228err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004229 wl1271_debugfs_exit(wl);
4230 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004231
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004232err_plat_alloc:
4233 ieee80211_free_hw(hw);
4234
4235err_hw_alloc:
4236
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004237 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004238}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004239EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004240
4241int wl1271_free_hw(struct wl1271 *wl)
4242{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004243 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004244 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004245 free_pages((unsigned long)wl->aggr_buf,
4246 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004247 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004248
4249 wl1271_debugfs_exit(wl);
4250
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004251 vfree(wl->fw);
4252 wl->fw = NULL;
4253 kfree(wl->nvs);
4254 wl->nvs = NULL;
4255
4256 kfree(wl->fw_status);
4257 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004258 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004259
4260 ieee80211_free_hw(wl->hw);
4261
4262 return 0;
4263}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004264EXPORT_SYMBOL_GPL(wl1271_free_hw);
4265
Guy Eilam491bbd62011-01-12 10:33:29 +01004266u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004267EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004268module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004269MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4270
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004271MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004272MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004273MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");