blob: 8e2f560812d4f1e56fd066e1cf0c5988ba857114 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300314 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300315 .num_probe_reqs = 2,
316 .rssi_threshold = -90,
317 .snr_threshold = 0,
318 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200319 .rf = {
320 .tx_per_channel_power_compensation_2 = {
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 },
323 .tx_per_channel_power_compensation_5 = {
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 },
328 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100329 .ht = {
330 .tx_ba_win_size = 64,
331 .inactivity_timeout = 10000,
332 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200333 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200334 .num_stations = 1,
335 .ssid_profiles = 1,
336 .rx_block_num = 70,
337 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300338 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200339 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200340 .min_req_rx_blocks = 22,
341 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200342 },
343 .mem_wl128x = {
344 .num_stations = 1,
345 .ssid_profiles = 1,
346 .rx_block_num = 40,
347 .tx_min_block_num = 40,
348 .dynamic_memory = 1,
349 .min_req_tx_blocks = 45,
350 .min_req_rx_blocks = 22,
351 .tx_min = 27,
352 },
Shahar Leviff868432011-04-11 15:41:46 +0300353 .fm_coex = {
354 .enable = true,
355 .swallow_period = 5,
356 .n_divider_fref_set_1 = 0xff, /* default */
357 .n_divider_fref_set_2 = 12,
358 .m_divider_fref_set_1 = 148,
359 .m_divider_fref_set_2 = 0xffff, /* default */
360 .coex_pll_stabilization_time = 0xffffffff, /* default */
361 .ldo_stabilization_time = 0xffff, /* default */
362 .fm_disturbed_band_margin = 0xff, /* default */
363 .swallow_clk_diff = 0xff, /* default */
364 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300365 .rx_streaming = {
366 .duration = 150,
367 .queues = 0x1,
368 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300369 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300370 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300371 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300372};
373
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300374static void __wl1271_op_remove_interface(struct wl1271 *wl,
375 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200376static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200377
378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200379static void wl1271_device_release(struct device *dev)
380{
381
382}
383
384static struct platform_device wl1271_device = {
385 .name = "wl1271",
386 .id = -1,
387
388 /* device model insists to have a release function */
389 .dev = {
390 .release = wl1271_device_release,
391 },
392};
393
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200394static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300395static LIST_HEAD(wl_list);
396
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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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)))
873 ieee80211_tx_status(wl->hw, skb);
874}
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.");
940 ieee80211_queue_work(wl->hw, &wl->recovery_work);
941
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
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001102static void wl1271_recovery_work(struct work_struct *work)
1103{
1104 struct wl1271 *wl =
1105 container_of(work, struct wl1271, recovery_work);
1106
1107 mutex_lock(&wl->mutex);
1108
1109 if (wl->state != WL1271_STATE_ON)
1110 goto out;
1111
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001112 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1113 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001114
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001115 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1116 ieee80211_connection_loss(wl->vif);
1117
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001118 /* Prevent spurious TX during FW restart */
1119 ieee80211_stop_queues(wl->hw);
1120
Luciano Coelho33c2c062011-05-10 14:46:02 +03001121 if (wl->sched_scanning) {
1122 ieee80211_sched_scan_stopped(wl->hw);
1123 wl->sched_scanning = false;
1124 }
1125
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001126 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001127 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001128 ieee80211_restart_hw(wl->hw);
1129
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001130 /*
1131 * Its safe to enable TX now - the queues are stopped after a request
1132 * to restart the HW.
1133 */
1134 ieee80211_wake_queues(wl->hw);
1135
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001136out:
1137 mutex_unlock(&wl->mutex);
1138}
1139
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140static void wl1271_fw_wakeup(struct wl1271 *wl)
1141{
1142 u32 elp_reg;
1143
1144 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001145 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146}
1147
1148static int wl1271_setup(struct wl1271 *wl)
1149{
1150 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1151 if (!wl->fw_status)
1152 return -ENOMEM;
1153
1154 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1155 if (!wl->tx_res_if) {
1156 kfree(wl->fw_status);
1157 return -ENOMEM;
1158 }
1159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 return 0;
1161}
1162
1163static int wl1271_chip_wakeup(struct wl1271 *wl)
1164{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001165 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166 int ret = 0;
1167
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001168 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001169 ret = wl1271_power_on(wl);
1170 if (ret < 0)
1171 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001172 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001173 wl1271_io_reset(wl);
1174 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175
1176 /* We don't need a real memory partition here, because we only want
1177 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001178 memset(&partition, 0, sizeof(partition));
1179 partition.reg.start = REGISTERS_BASE;
1180 partition.reg.size = REGISTERS_DOWN_SIZE;
1181 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182
1183 /* ELP module wake up */
1184 wl1271_fw_wakeup(wl);
1185
1186 /* whal_FwCtrl_BootSm() */
1187
1188 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001189 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001190
1191 /* 1. check if chip id is valid */
1192
1193 switch (wl->chip.id) {
1194 case CHIP_ID_1271_PG10:
1195 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1196 wl->chip.id);
1197
1198 ret = wl1271_setup(wl);
1199 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001200 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 break;
1202 case CHIP_ID_1271_PG20:
1203 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1204 wl->chip.id);
1205
Shahar Levi0c005042011-06-12 10:34:43 +03001206 /*
1207 * 'end-of-transaction flag' and 'LPD mode flag'
1208 * should be set in wl127x AP mode only
1209 */
Shahar Levi564f5952011-04-04 10:20:39 +03001210 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001211 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1212 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001213
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214 ret = wl1271_setup(wl);
1215 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001216 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001217 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001218 case CHIP_ID_1283_PG20:
1219 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1220 wl->chip.id);
1221
1222 ret = wl1271_setup(wl);
1223 if (ret < 0)
1224 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001225
Ido Yariv0da13da2011-03-31 10:06:58 +02001226 if (wl1271_set_block_size(wl))
1227 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001228 break;
1229 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001231 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001233 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001234 }
1235
Arik Nemtsov166d5042010-10-16 21:44:57 +02001236 /* Make sure the firmware type matches the BSS type */
1237 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 ret = wl1271_fetch_firmware(wl);
1239 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001240 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241 }
1242
1243 /* No NVS from netlink, try to get it from the filesystem */
1244 if (wl->nvs == NULL) {
1245 ret = wl1271_fetch_nvs(wl);
1246 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001247 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248 }
1249
1250out:
1251 return ret;
1252}
1253
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001254static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1255{
1256 unsigned int quirks = 0;
1257 unsigned int *fw_ver = wl->chip.fw_ver;
1258
1259 /* Only for wl127x */
1260 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1261 /* Check STA version */
1262 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1263 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1264 /* Check AP version */
1265 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1266 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1267 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1268
1269 return quirks;
1270}
1271
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001272int wl1271_plt_start(struct wl1271 *wl)
1273{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001274 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275 int ret;
1276
1277 mutex_lock(&wl->mutex);
1278
1279 wl1271_notice("power up");
1280
1281 if (wl->state != WL1271_STATE_OFF) {
1282 wl1271_error("cannot go into PLT state because not "
1283 "in off state: %d", wl->state);
1284 ret = -EBUSY;
1285 goto out;
1286 }
1287
Arik Nemtsov166d5042010-10-16 21:44:57 +02001288 wl->bss_type = BSS_TYPE_STA_BSS;
1289
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001290 while (retries) {
1291 retries--;
1292 ret = wl1271_chip_wakeup(wl);
1293 if (ret < 0)
1294 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001296 ret = wl1271_boot(wl);
1297 if (ret < 0)
1298 goto power_off;
1299
1300 ret = wl1271_plt_init(wl);
1301 if (ret < 0)
1302 goto irq_disable;
1303
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001304 wl->state = WL1271_STATE_PLT;
1305 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001306 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001307
1308 /* Check if any quirks are needed with older fw versions */
1309 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001310 goto out;
1311
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001312irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 mutex_unlock(&wl->mutex);
1314 /* Unlocking the mutex in the middle of handling is
1315 inherently unsafe. In this case we deem it safe to do,
1316 because we need to let any possibly pending IRQ out of
1317 the system (and while we are WL1271_STATE_OFF the IRQ
1318 work function will not do anything.) Also, any other
1319 possible concurrent operations will fail due to the
1320 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001321 wl1271_disable_interrupts(wl);
1322 wl1271_flush_deferred_work(wl);
1323 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001324 mutex_lock(&wl->mutex);
1325power_off:
1326 wl1271_power_off(wl);
1327 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1330 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001331out:
1332 mutex_unlock(&wl->mutex);
1333
1334 return ret;
1335}
1336
Luciano Coelho4623ec72011-03-21 19:26:41 +02001337static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338{
1339 int ret = 0;
1340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001341 wl1271_notice("power down");
1342
1343 if (wl->state != WL1271_STATE_PLT) {
1344 wl1271_error("cannot power down because not in PLT "
1345 "state: %d", wl->state);
1346 ret = -EBUSY;
1347 goto out;
1348 }
1349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 wl1271_power_off(wl);
1351
1352 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001353 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001356 wl1271_disable_interrupts(wl);
1357 wl1271_flush_deferred_work(wl);
1358 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001359 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001360 mutex_lock(&wl->mutex);
1361out:
1362 return ret;
1363}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001364
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001365int wl1271_plt_stop(struct wl1271 *wl)
1366{
1367 int ret;
1368
1369 mutex_lock(&wl->mutex);
1370 ret = __wl1271_plt_stop(wl);
1371 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 return ret;
1373}
1374
Johannes Berg7bb45682011-02-24 14:42:06 +01001375static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376{
1377 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001378 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001379 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001380 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001381
Ido Yarivb07d4032011-03-01 15:14:43 +02001382 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1383
1384 if (wl->bss_type == BSS_TYPE_AP_BSS)
1385 hlid = wl1271_tx_get_hlid(skb);
1386
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001387 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001388
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001389 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001390
1391 /*
1392 * The workqueue is slow to process the tx_queue and we need stop
1393 * the queue here, otherwise the queue will get too long.
1394 */
1395 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1396 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1397 ieee80211_stop_queues(wl->hw);
1398 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1399 }
1400
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001401 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001402 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001403 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1404 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1405 } else {
1406 skb_queue_tail(&wl->tx_queue[q], skb);
1407 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408
1409 /*
1410 * The chip specific setup must run before the first TX packet -
1411 * before that, the tx_work will not be initialized!
1412 */
1413
Ido Yarivb07d4032011-03-01 15:14:43 +02001414 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1415 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001416 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001417
1418 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001419}
1420
Shahar Leviae47c452011-03-06 16:32:14 +02001421int wl1271_tx_dummy_packet(struct wl1271 *wl)
1422{
Ido Yariv990f5de2011-03-31 10:06:59 +02001423 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001424
Ido Yariv990f5de2011-03-31 10:06:59 +02001425 spin_lock_irqsave(&wl->wl_lock, flags);
1426 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1427 wl->tx_queue_count++;
1428 spin_unlock_irqrestore(&wl->wl_lock, flags);
1429
1430 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1431 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1432 wl1271_tx_work_locked(wl);
1433
1434 /*
1435 * If the FW TX is busy, TX work will be scheduled by the threaded
1436 * interrupt handler function
1437 */
1438 return 0;
1439}
1440
1441/*
1442 * The size of the dummy packet should be at least 1400 bytes. However, in
1443 * order to minimize the number of bus transactions, aligning it to 512 bytes
1444 * boundaries could be beneficial, performance wise
1445 */
1446#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1447
Luciano Coelhocf27d862011-04-01 21:08:23 +03001448static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001449{
1450 struct sk_buff *skb;
1451 struct ieee80211_hdr_3addr *hdr;
1452 unsigned int dummy_packet_size;
1453
1454 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1455 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1456
1457 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001458 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001459 wl1271_warning("Failed to allocate a dummy packet skb");
1460 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001461 }
1462
1463 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1464
1465 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1466 memset(hdr, 0, sizeof(*hdr));
1467 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001468 IEEE80211_STYPE_NULLFUNC |
1469 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001470
Ido Yariv990f5de2011-03-31 10:06:59 +02001471 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001472
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001473 /* Dummy packets require the TID to be management */
1474 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001475
1476 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001477 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001478 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001479
Ido Yariv990f5de2011-03-31 10:06:59 +02001480 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001481}
1482
Ido Yariv990f5de2011-03-31 10:06:59 +02001483
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001484static struct notifier_block wl1271_dev_notifier = {
1485 .notifier_call = wl1271_dev_notify,
1486};
1487
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001488#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001489static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001490{
1491 int ret;
1492
Eliad Peller94390642011-05-13 11:57:13 +03001493 mutex_lock(&wl->mutex);
1494
1495 ret = wl1271_ps_elp_wakeup(wl);
1496 if (ret < 0)
1497 goto out_unlock;
1498
1499 /* enter psm if needed*/
1500 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1501 DECLARE_COMPLETION_ONSTACK(compl);
1502
1503 wl->ps_compl = &compl;
1504 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1505 wl->basic_rate, true);
1506 if (ret < 0)
1507 goto out_sleep;
1508
1509 /* we must unlock here so we will be able to get events */
1510 wl1271_ps_elp_sleep(wl);
1511 mutex_unlock(&wl->mutex);
1512
1513 ret = wait_for_completion_timeout(
1514 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1515 if (ret <= 0) {
1516 wl1271_warning("couldn't enter ps mode!");
1517 ret = -EBUSY;
1518 goto out;
1519 }
1520
1521 /* take mutex again, and wakeup */
1522 mutex_lock(&wl->mutex);
1523
1524 ret = wl1271_ps_elp_wakeup(wl);
1525 if (ret < 0)
1526 goto out_unlock;
1527 }
1528out_sleep:
1529 wl1271_ps_elp_sleep(wl);
1530out_unlock:
1531 mutex_unlock(&wl->mutex);
1532out:
1533 return ret;
1534
1535}
1536
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001537static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001538{
1539 int ret;
1540
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001541 mutex_lock(&wl->mutex);
1542
1543 ret = wl1271_ps_elp_wakeup(wl);
1544 if (ret < 0)
1545 goto out_unlock;
1546
1547 ret = wl1271_acx_set_ap_beacon_filter(wl, true);
1548
1549 wl1271_ps_elp_sleep(wl);
1550out_unlock:
1551 mutex_unlock(&wl->mutex);
1552 return ret;
1553
1554}
1555
1556static int wl1271_configure_suspend(struct wl1271 *wl)
1557{
1558 if (wl->bss_type == BSS_TYPE_STA_BSS)
1559 return wl1271_configure_suspend_sta(wl);
1560 if (wl->bss_type == BSS_TYPE_AP_BSS)
1561 return wl1271_configure_suspend_ap(wl);
1562 return 0;
1563}
1564
1565static void wl1271_configure_resume(struct wl1271 *wl)
1566{
1567 int ret;
1568 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1569 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1570
1571 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001572 return;
1573
1574 mutex_lock(&wl->mutex);
1575 ret = wl1271_ps_elp_wakeup(wl);
1576 if (ret < 0)
1577 goto out;
1578
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001579 if (is_sta) {
1580 /* exit psm if it wasn't configured */
1581 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1582 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1583 wl->basic_rate, true);
1584 } else if (is_ap) {
1585 wl1271_acx_set_ap_beacon_filter(wl, false);
1586 }
Eliad Peller94390642011-05-13 11:57:13 +03001587
1588 wl1271_ps_elp_sleep(wl);
1589out:
1590 mutex_unlock(&wl->mutex);
1591}
1592
Eliad Peller402e48612011-05-13 11:57:09 +03001593static int wl1271_op_suspend(struct ieee80211_hw *hw,
1594 struct cfg80211_wowlan *wow)
1595{
1596 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001597 int ret;
1598
Eliad Peller402e48612011-05-13 11:57:09 +03001599 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001600 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001601
Eliad Peller4a859df2011-06-06 12:21:52 +03001602 wl->wow_enabled = true;
1603 ret = wl1271_configure_suspend(wl);
1604 if (ret < 0) {
1605 wl1271_warning("couldn't prepare device to suspend");
1606 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001607 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001608 /* flush any remaining work */
1609 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1610 flush_delayed_work(&wl->scan_complete_work);
1611
1612 /*
1613 * disable and re-enable interrupts in order to flush
1614 * the threaded_irq
1615 */
1616 wl1271_disable_interrupts(wl);
1617
1618 /*
1619 * set suspended flag to avoid triggering a new threaded_irq
1620 * work. no need for spinlock as interrupts are disabled.
1621 */
1622 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1623
1624 wl1271_enable_interrupts(wl);
1625 flush_work(&wl->tx_work);
1626 flush_delayed_work(&wl->pspoll_work);
1627 flush_delayed_work(&wl->elp_work);
1628
Eliad Peller402e48612011-05-13 11:57:09 +03001629 return 0;
1630}
1631
1632static int wl1271_op_resume(struct ieee80211_hw *hw)
1633{
1634 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001635 unsigned long flags;
1636 bool run_irq_work = false;
1637
Eliad Peller402e48612011-05-13 11:57:09 +03001638 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1639 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001640 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001641
1642 /*
1643 * re-enable irq_work enqueuing, and call irq_work directly if
1644 * there is a pending work.
1645 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001646 spin_lock_irqsave(&wl->wl_lock, flags);
1647 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1648 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1649 run_irq_work = true;
1650 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001651
Eliad Peller4a859df2011-06-06 12:21:52 +03001652 if (run_irq_work) {
1653 wl1271_debug(DEBUG_MAC80211,
1654 "run postponed irq_work directly");
1655 wl1271_irq(0, wl);
1656 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001657 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001658 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001659 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001660
Eliad Peller402e48612011-05-13 11:57:09 +03001661 return 0;
1662}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001663#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001664
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665static int wl1271_op_start(struct ieee80211_hw *hw)
1666{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001667 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1668
1669 /*
1670 * We have to delay the booting of the hardware because
1671 * we need to know the local MAC address before downloading and
1672 * initializing the firmware. The MAC address cannot be changed
1673 * after boot, and without the proper MAC address, the firmware
1674 * will not function properly.
1675 *
1676 * The MAC address is first known when the corresponding interface
1677 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001678 *
1679 * In addition, we currently have different firmwares for AP and managed
1680 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001681 */
1682
1683 return 0;
1684}
1685
1686static void wl1271_op_stop(struct ieee80211_hw *hw)
1687{
1688 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1689}
1690
1691static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1692 struct ieee80211_vif *vif)
1693{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001694 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001695 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001696 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001697 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001698 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001700 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1701 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001702
1703 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001704 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001705 wl1271_debug(DEBUG_MAC80211,
1706 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001707 ret = -EBUSY;
1708 goto out;
1709 }
1710
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001711 /*
1712 * in some very corner case HW recovery scenarios its possible to
1713 * get here before __wl1271_op_remove_interface is complete, so
1714 * opt out if that is the case.
1715 */
1716 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1717 ret = -EBUSY;
1718 goto out;
1719 }
1720
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001721 switch (vif->type) {
1722 case NL80211_IFTYPE_STATION:
1723 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001724 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001725 break;
1726 case NL80211_IFTYPE_ADHOC:
1727 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001728 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001729 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001730 case NL80211_IFTYPE_AP:
1731 wl->bss_type = BSS_TYPE_AP_BSS;
1732 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001733 default:
1734 ret = -EOPNOTSUPP;
1735 goto out;
1736 }
1737
1738 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739
1740 if (wl->state != WL1271_STATE_OFF) {
1741 wl1271_error("cannot start because not in off state: %d",
1742 wl->state);
1743 ret = -EBUSY;
1744 goto out;
1745 }
1746
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001747 while (retries) {
1748 retries--;
1749 ret = wl1271_chip_wakeup(wl);
1750 if (ret < 0)
1751 goto power_off;
1752
1753 ret = wl1271_boot(wl);
1754 if (ret < 0)
1755 goto power_off;
1756
1757 ret = wl1271_hw_init(wl);
1758 if (ret < 0)
1759 goto irq_disable;
1760
Eliad Peller71125ab2010-10-28 21:46:43 +02001761 booted = true;
1762 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001763
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001764irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001765 mutex_unlock(&wl->mutex);
1766 /* Unlocking the mutex in the middle of handling is
1767 inherently unsafe. In this case we deem it safe to do,
1768 because we need to let any possibly pending IRQ out of
1769 the system (and while we are WL1271_STATE_OFF the IRQ
1770 work function will not do anything.) Also, any other
1771 possible concurrent operations will fail due to the
1772 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001773 wl1271_disable_interrupts(wl);
1774 wl1271_flush_deferred_work(wl);
1775 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001776 mutex_lock(&wl->mutex);
1777power_off:
1778 wl1271_power_off(wl);
1779 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780
Eliad Peller71125ab2010-10-28 21:46:43 +02001781 if (!booted) {
1782 wl1271_error("firmware boot failed despite %d retries",
1783 WL1271_BOOT_RETRIES);
1784 goto out;
1785 }
1786
1787 wl->vif = vif;
1788 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001789 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001790 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001791
1792 /* update hw/fw version info in wiphy struct */
1793 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001794 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001795 sizeof(wiphy->fw_version));
1796
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001797 /* Check if any quirks are needed with older fw versions */
1798 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1799
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001800 /*
1801 * Now we know if 11a is supported (info from the NVS), so disable
1802 * 11a channels if not supported
1803 */
1804 if (!wl->enable_11a)
1805 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1806
1807 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1808 wl->enable_11a ? "" : "not ");
1809
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001810out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811 mutex_unlock(&wl->mutex);
1812
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001813 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001814 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001815 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001816 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001817
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001818 return ret;
1819}
1820
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001821static void __wl1271_op_remove_interface(struct wl1271 *wl,
1822 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 int i;
1825
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001826 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001828 /* because of hardware recovery, we may get here twice */
1829 if (wl->state != WL1271_STATE_ON)
1830 return;
1831
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001832 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001833
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001834 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001835 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001836 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001837
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001838 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001839 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001840 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001841
Luciano Coelho08688d62010-07-08 17:50:07 +03001842 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001843 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001844 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001845 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001846 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 }
1848
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001849 /*
1850 * this must be before the cancel_work calls below, so that the work
1851 * functions don't perform further work.
1852 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001853 wl->state = WL1271_STATE_OFF;
1854
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855 mutex_unlock(&wl->mutex);
1856
Ido Yariva6208652011-03-01 15:14:41 +02001857 wl1271_disable_interrupts(wl);
1858 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001859 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001860 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001861 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03001862 del_timer_sync(&wl->rx_streaming_timer);
1863 cancel_work_sync(&wl->rx_streaming_enable_work);
1864 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001865 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001866 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001867
1868 mutex_lock(&wl->mutex);
1869
1870 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001871 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872 wl1271_power_off(wl);
1873
1874 memset(wl->bssid, 0, ETH_ALEN);
1875 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1876 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001877 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001878 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001879 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001880
1881 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001882 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1884 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001885 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001886 wl->tx_results_count = 0;
1887 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001888 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001889 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001890 wl->time_offset = 0;
1891 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001892 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001893 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001894 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001895 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001896 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001897 wl->ap_fw_ps_map = 0;
1898 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001899 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001900
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001901 /*
1902 * this is performed after the cancel_work calls and the associated
1903 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1904 * get executed before all these vars have been reset.
1905 */
1906 wl->flags = 0;
1907
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001908 for (i = 0; i < NUM_TX_QUEUES; i++)
1909 wl->tx_blocks_freed[i] = 0;
1910
1911 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001912
1913 kfree(wl->fw_status);
1914 wl->fw_status = NULL;
1915 kfree(wl->tx_res_if);
1916 wl->tx_res_if = NULL;
1917 kfree(wl->target_mem_map);
1918 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001919}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001920
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001921static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1922 struct ieee80211_vif *vif)
1923{
1924 struct wl1271 *wl = hw->priv;
1925
1926 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001927 /*
1928 * wl->vif can be null here if someone shuts down the interface
1929 * just when hardware recovery has been started.
1930 */
1931 if (wl->vif) {
1932 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001933 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001934 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001935
Juuso Oikarinen67353292010-11-18 15:19:02 +02001936 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001937 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001938}
1939
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001940void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001941{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001942 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001943
1944 /* combine requested filters with current filter config */
1945 filters = wl->filters | filters;
1946
1947 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1948
1949 if (filters & FIF_PROMISC_IN_BSS) {
1950 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1951 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1952 wl->rx_config |= CFG_BSSID_FILTER_EN;
1953 }
1954 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1955 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1956 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1957 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1958 }
1959 if (filters & FIF_OTHER_BSS) {
1960 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1961 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1962 }
1963 if (filters & FIF_CONTROL) {
1964 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1965 wl->rx_filter |= CFG_RX_CTL_EN;
1966 }
1967 if (filters & FIF_FCSFAIL) {
1968 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1969 wl->rx_filter |= CFG_RX_FCS_ERROR;
1970 }
1971}
1972
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001973static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001974{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001975 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001976 /* we need to use a dummy BSSID for now */
1977 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1978 0xad, 0xbe, 0xef };
1979
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001980 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1981
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001982 /* pass through frames from all BSS */
1983 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1984
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001985 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001986 if (ret < 0)
1987 goto out;
1988
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001989 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001990
1991out:
1992 return ret;
1993}
1994
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001995static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001996{
1997 int ret;
1998
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001999 /*
2000 * One of the side effects of the JOIN command is that is clears
2001 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2002 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002003 * Currently the only valid scenario for JOIN during association
2004 * is on roaming, in which case we will also be given new keys.
2005 * Keep the below message for now, unless it starts bothering
2006 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002007 */
2008 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2009 wl1271_info("JOIN while associated.");
2010
2011 if (set_assoc)
2012 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2013
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002014 ret = wl1271_cmd_join(wl, wl->set_bss_type);
2015 if (ret < 0)
2016 goto out;
2017
2018 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2019
2020 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2021 goto out;
2022
2023 /*
2024 * The join command disable the keep-alive mode, shut down its process,
2025 * and also clear the template config, so we need to reset it all after
2026 * the join. The acx_aid starts the keep-alive process, and the order
2027 * of the commands below is relevant.
2028 */
2029 ret = wl1271_acx_keep_alive_mode(wl, true);
2030 if (ret < 0)
2031 goto out;
2032
2033 ret = wl1271_acx_aid(wl, wl->aid);
2034 if (ret < 0)
2035 goto out;
2036
2037 ret = wl1271_cmd_build_klv_null_data(wl);
2038 if (ret < 0)
2039 goto out;
2040
2041 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2042 ACX_KEEP_ALIVE_TPL_VALID);
2043 if (ret < 0)
2044 goto out;
2045
2046out:
2047 return ret;
2048}
2049
2050static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002051{
2052 int ret;
2053
2054 /* to stop listening to a channel, we disconnect */
2055 ret = wl1271_cmd_disconnect(wl);
2056 if (ret < 0)
2057 goto out;
2058
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002059 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002060 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002061
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02002062 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002063 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002064
2065out:
2066 return ret;
2067}
2068
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002069static void wl1271_set_band_rate(struct wl1271 *wl)
2070{
2071 if (wl->band == IEEE80211_BAND_2GHZ)
2072 wl->basic_rate_set = wl->conf.tx.basic_rate;
2073 else
2074 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2075}
2076
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002077static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002078{
2079 int ret;
2080
2081 if (idle) {
2082 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2083 ret = wl1271_unjoin(wl);
2084 if (ret < 0)
2085 goto out;
2086 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002087 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002088 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002089 if (ret < 0)
2090 goto out;
2091 ret = wl1271_acx_keep_alive_config(
2092 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2093 ACX_KEEP_ALIVE_TPL_INVALID);
2094 if (ret < 0)
2095 goto out;
2096 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2097 } else {
2098 /* increment the session counter */
2099 wl->session_counter++;
2100 if (wl->session_counter >= SESSION_COUNTER_MAX)
2101 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002102
2103 /* The current firmware only supports sched_scan in idle */
2104 if (wl->sched_scanning) {
2105 wl1271_scan_sched_scan_stop(wl);
2106 ieee80211_sched_scan_stopped(wl->hw);
2107 }
2108
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002109 ret = wl1271_dummy_join(wl);
2110 if (ret < 0)
2111 goto out;
2112 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2113 }
2114
2115out:
2116 return ret;
2117}
2118
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2120{
2121 struct wl1271 *wl = hw->priv;
2122 struct ieee80211_conf *conf = &hw->conf;
2123 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002124 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125
2126 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2127
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002128 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2129 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130 channel,
2131 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002132 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002133 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2134 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002136 /*
2137 * mac80211 will go to idle nearly immediately after transmitting some
2138 * frames, such as the deauth. To make sure those frames reach the air,
2139 * wait here until the TX queue is fully flushed.
2140 */
2141 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2142 (conf->flags & IEEE80211_CONF_IDLE))
2143 wl1271_tx_flush(wl);
2144
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002145 mutex_lock(&wl->mutex);
2146
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002147 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002148 /* we support configuring the channel and band while off */
2149 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2150 wl->band = conf->channel->band;
2151 wl->channel = channel;
2152 }
2153
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002154 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002155 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002156
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002157 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2158
Ido Yariva6208652011-03-01 15:14:41 +02002159 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160 if (ret < 0)
2161 goto out;
2162
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002163 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002164 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2165 ((wl->band != conf->channel->band) ||
2166 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002167 wl->band = conf->channel->band;
2168 wl->channel = channel;
2169
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002170 if (!is_ap) {
2171 /*
2172 * FIXME: the mac80211 should really provide a fixed
2173 * rate to use here. for now, just use the smallest
2174 * possible rate for the band as a fixed rate for
2175 * association frames and other control messages.
2176 */
2177 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2178 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002179
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002180 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2181 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002182 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002183 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002184 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002185
2186 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2187 ret = wl1271_join(wl, false);
2188 if (ret < 0)
2189 wl1271_warning("cmd join on channel "
2190 "failed %d", ret);
2191 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002192 }
2193 }
2194
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002195 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2196 ret = wl1271_sta_handle_idle(wl,
2197 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002198 if (ret < 0)
2199 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200 }
2201
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002202 /*
2203 * if mac80211 changes the PSM mode, make sure the mode is not
2204 * incorrectly changed after the pspoll failure active window.
2205 */
2206 if (changed & IEEE80211_CONF_CHANGE_PS)
2207 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2208
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002209 if (conf->flags & IEEE80211_CONF_PS &&
2210 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2211 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002212
2213 /*
2214 * We enter PSM only if we're already associated.
2215 * If we're not, we'll enter it when joining an SSID,
2216 * through the bss_info_changed() hook.
2217 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002218 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002219 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002220 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002221 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002222 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002224 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002225 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002227 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002228
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002229 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002230 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002231 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002232 }
2233
2234 if (conf->power_level != wl->power_level) {
2235 ret = wl1271_acx_tx_power(wl, conf->power_level);
2236 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002237 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002238
2239 wl->power_level = conf->power_level;
2240 }
2241
2242out_sleep:
2243 wl1271_ps_elp_sleep(wl);
2244
2245out:
2246 mutex_unlock(&wl->mutex);
2247
2248 return ret;
2249}
2250
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002251struct wl1271_filter_params {
2252 bool enabled;
2253 int mc_list_length;
2254 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2255};
2256
Jiri Pirko22bedad2010-04-01 21:22:57 +00002257static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2258 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002259{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002260 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002261 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002262 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002263
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002264 if (unlikely(wl->state == WL1271_STATE_OFF))
2265 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002266
Juuso Oikarinen74441132009-10-13 12:47:53 +03002267 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002268 if (!fp) {
2269 wl1271_error("Out of memory setting filters.");
2270 return 0;
2271 }
2272
2273 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002274 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002275 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2276 fp->enabled = false;
2277 } else {
2278 fp->enabled = true;
2279 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002280 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002281 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002282 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002283 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002284 }
2285
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002286 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002287}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002289#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2290 FIF_ALLMULTI | \
2291 FIF_FCSFAIL | \
2292 FIF_BCN_PRBRESP_PROMISC | \
2293 FIF_CONTROL | \
2294 FIF_OTHER_BSS)
2295
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2297 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002298 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002300 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002302 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002303
Arik Nemtsov7d057862010-10-16 19:25:35 +02002304 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2305 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002306
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002307 mutex_lock(&wl->mutex);
2308
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002309 *total &= WL1271_SUPPORTED_FILTERS;
2310 changed &= WL1271_SUPPORTED_FILTERS;
2311
2312 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002313 goto out;
2314
Ido Yariva6208652011-03-01 15:14:41 +02002315 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002316 if (ret < 0)
2317 goto out;
2318
Arik Nemtsov7d057862010-10-16 19:25:35 +02002319 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2320 if (*total & FIF_ALLMULTI)
2321 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2322 else if (fp)
2323 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2324 fp->mc_list,
2325 fp->mc_list_length);
2326 if (ret < 0)
2327 goto out_sleep;
2328 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002330 /* determine, whether supported filter values have changed */
2331 if (changed == 0)
2332 goto out_sleep;
2333
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002334 /* configure filters */
2335 wl->filters = *total;
2336 wl1271_configure_filters(wl, 0);
2337
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002338 /* apply configured filters */
2339 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2340 if (ret < 0)
2341 goto out_sleep;
2342
2343out_sleep:
2344 wl1271_ps_elp_sleep(wl);
2345
2346out:
2347 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002348 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349}
2350
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002351static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2352 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2353 u16 tx_seq_16)
2354{
2355 struct wl1271_ap_key *ap_key;
2356 int i;
2357
2358 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2359
2360 if (key_size > MAX_KEY_SIZE)
2361 return -EINVAL;
2362
2363 /*
2364 * Find next free entry in ap_keys. Also check we are not replacing
2365 * an existing key.
2366 */
2367 for (i = 0; i < MAX_NUM_KEYS; i++) {
2368 if (wl->recorded_ap_keys[i] == NULL)
2369 break;
2370
2371 if (wl->recorded_ap_keys[i]->id == id) {
2372 wl1271_warning("trying to record key replacement");
2373 return -EINVAL;
2374 }
2375 }
2376
2377 if (i == MAX_NUM_KEYS)
2378 return -EBUSY;
2379
2380 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2381 if (!ap_key)
2382 return -ENOMEM;
2383
2384 ap_key->id = id;
2385 ap_key->key_type = key_type;
2386 ap_key->key_size = key_size;
2387 memcpy(ap_key->key, key, key_size);
2388 ap_key->hlid = hlid;
2389 ap_key->tx_seq_32 = tx_seq_32;
2390 ap_key->tx_seq_16 = tx_seq_16;
2391
2392 wl->recorded_ap_keys[i] = ap_key;
2393 return 0;
2394}
2395
2396static void wl1271_free_ap_keys(struct wl1271 *wl)
2397{
2398 int i;
2399
2400 for (i = 0; i < MAX_NUM_KEYS; i++) {
2401 kfree(wl->recorded_ap_keys[i]);
2402 wl->recorded_ap_keys[i] = NULL;
2403 }
2404}
2405
2406static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2407{
2408 int i, ret = 0;
2409 struct wl1271_ap_key *key;
2410 bool wep_key_added = false;
2411
2412 for (i = 0; i < MAX_NUM_KEYS; i++) {
2413 if (wl->recorded_ap_keys[i] == NULL)
2414 break;
2415
2416 key = wl->recorded_ap_keys[i];
2417 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2418 key->id, key->key_type,
2419 key->key_size, key->key,
2420 key->hlid, key->tx_seq_32,
2421 key->tx_seq_16);
2422 if (ret < 0)
2423 goto out;
2424
2425 if (key->key_type == KEY_WEP)
2426 wep_key_added = true;
2427 }
2428
2429 if (wep_key_added) {
2430 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2431 if (ret < 0)
2432 goto out;
2433 }
2434
2435out:
2436 wl1271_free_ap_keys(wl);
2437 return ret;
2438}
2439
2440static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2441 u8 key_size, const u8 *key, u32 tx_seq_32,
2442 u16 tx_seq_16, struct ieee80211_sta *sta)
2443{
2444 int ret;
2445 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2446
2447 if (is_ap) {
2448 struct wl1271_station *wl_sta;
2449 u8 hlid;
2450
2451 if (sta) {
2452 wl_sta = (struct wl1271_station *)sta->drv_priv;
2453 hlid = wl_sta->hlid;
2454 } else {
2455 hlid = WL1271_AP_BROADCAST_HLID;
2456 }
2457
2458 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2459 /*
2460 * We do not support removing keys after AP shutdown.
2461 * Pretend we do to make mac80211 happy.
2462 */
2463 if (action != KEY_ADD_OR_REPLACE)
2464 return 0;
2465
2466 ret = wl1271_record_ap_key(wl, id,
2467 key_type, key_size,
2468 key, hlid, tx_seq_32,
2469 tx_seq_16);
2470 } else {
2471 ret = wl1271_cmd_set_ap_key(wl, action,
2472 id, key_type, key_size,
2473 key, hlid, tx_seq_32,
2474 tx_seq_16);
2475 }
2476
2477 if (ret < 0)
2478 return ret;
2479 } else {
2480 const u8 *addr;
2481 static const u8 bcast_addr[ETH_ALEN] = {
2482 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2483 };
2484
2485 addr = sta ? sta->addr : bcast_addr;
2486
2487 if (is_zero_ether_addr(addr)) {
2488 /* We dont support TX only encryption */
2489 return -EOPNOTSUPP;
2490 }
2491
2492 /* The wl1271 does not allow to remove unicast keys - they
2493 will be cleared automatically on next CMD_JOIN. Ignore the
2494 request silently, as we dont want the mac80211 to emit
2495 an error message. */
2496 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2497 return 0;
2498
2499 ret = wl1271_cmd_set_sta_key(wl, action,
2500 id, key_type, key_size,
2501 key, addr, tx_seq_32,
2502 tx_seq_16);
2503 if (ret < 0)
2504 return ret;
2505
2506 /* the default WEP key needs to be configured at least once */
2507 if (key_type == KEY_WEP) {
2508 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2509 wl->default_key);
2510 if (ret < 0)
2511 return ret;
2512 }
2513 }
2514
2515 return 0;
2516}
2517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2519 struct ieee80211_vif *vif,
2520 struct ieee80211_sta *sta,
2521 struct ieee80211_key_conf *key_conf)
2522{
2523 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002525 u32 tx_seq_32 = 0;
2526 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002527 u8 key_type;
2528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002529 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2530
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002531 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002532 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002533 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002534 key_conf->keylen, key_conf->flags);
2535 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2536
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537 mutex_lock(&wl->mutex);
2538
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002539 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2540 ret = -EAGAIN;
2541 goto out_unlock;
2542 }
2543
Ido Yariva6208652011-03-01 15:14:41 +02002544 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 if (ret < 0)
2546 goto out_unlock;
2547
Johannes Berg97359d12010-08-10 09:46:38 +02002548 switch (key_conf->cipher) {
2549 case WLAN_CIPHER_SUITE_WEP40:
2550 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551 key_type = KEY_WEP;
2552
2553 key_conf->hw_key_idx = key_conf->keyidx;
2554 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002555 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556 key_type = KEY_TKIP;
2557
2558 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002559 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2560 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002561 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002562 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 key_type = KEY_AES;
2564
2565 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002566 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2567 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002568 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002569 case WL1271_CIPHER_SUITE_GEM:
2570 key_type = KEY_GEM;
2571 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2572 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2573 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002574 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002575 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576
2577 ret = -EOPNOTSUPP;
2578 goto out_sleep;
2579 }
2580
2581 switch (cmd) {
2582 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002583 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2584 key_conf->keyidx, key_type,
2585 key_conf->keylen, key_conf->key,
2586 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 if (ret < 0) {
2588 wl1271_error("Could not add or replace key");
2589 goto out_sleep;
2590 }
2591 break;
2592
2593 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002594 ret = wl1271_set_key(wl, KEY_REMOVE,
2595 key_conf->keyidx, key_type,
2596 key_conf->keylen, key_conf->key,
2597 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002598 if (ret < 0) {
2599 wl1271_error("Could not remove key");
2600 goto out_sleep;
2601 }
2602 break;
2603
2604 default:
2605 wl1271_error("Unsupported key cmd 0x%x", cmd);
2606 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002607 break;
2608 }
2609
2610out_sleep:
2611 wl1271_ps_elp_sleep(wl);
2612
2613out_unlock:
2614 mutex_unlock(&wl->mutex);
2615
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002616 return ret;
2617}
2618
2619static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002620 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002621 struct cfg80211_scan_request *req)
2622{
2623 struct wl1271 *wl = hw->priv;
2624 int ret;
2625 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002626 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627
2628 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2629
2630 if (req->n_ssids) {
2631 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002632 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002633 }
2634
2635 mutex_lock(&wl->mutex);
2636
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002637 if (wl->state == WL1271_STATE_OFF) {
2638 /*
2639 * We cannot return -EBUSY here because cfg80211 will expect
2640 * a call to ieee80211_scan_completed if we do - in this case
2641 * there won't be any call.
2642 */
2643 ret = -EAGAIN;
2644 goto out;
2645 }
2646
Ido Yariva6208652011-03-01 15:14:41 +02002647 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002648 if (ret < 0)
2649 goto out;
2650
Luciano Coelho5924f892010-08-04 03:46:22 +03002651 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002652
2653 wl1271_ps_elp_sleep(wl);
2654
2655out:
2656 mutex_unlock(&wl->mutex);
2657
2658 return ret;
2659}
2660
Luciano Coelho33c2c062011-05-10 14:46:02 +03002661static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2662 struct ieee80211_vif *vif,
2663 struct cfg80211_sched_scan_request *req,
2664 struct ieee80211_sched_scan_ies *ies)
2665{
2666 struct wl1271 *wl = hw->priv;
2667 int ret;
2668
2669 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2670
2671 mutex_lock(&wl->mutex);
2672
2673 ret = wl1271_ps_elp_wakeup(wl);
2674 if (ret < 0)
2675 goto out;
2676
2677 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2678 if (ret < 0)
2679 goto out_sleep;
2680
2681 ret = wl1271_scan_sched_scan_start(wl);
2682 if (ret < 0)
2683 goto out_sleep;
2684
2685 wl->sched_scanning = true;
2686
2687out_sleep:
2688 wl1271_ps_elp_sleep(wl);
2689out:
2690 mutex_unlock(&wl->mutex);
2691 return ret;
2692}
2693
2694static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2695 struct ieee80211_vif *vif)
2696{
2697 struct wl1271 *wl = hw->priv;
2698 int ret;
2699
2700 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2701
2702 mutex_lock(&wl->mutex);
2703
2704 ret = wl1271_ps_elp_wakeup(wl);
2705 if (ret < 0)
2706 goto out;
2707
2708 wl1271_scan_sched_scan_stop(wl);
2709
2710 wl1271_ps_elp_sleep(wl);
2711out:
2712 mutex_unlock(&wl->mutex);
2713}
2714
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002715static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2716{
2717 struct wl1271 *wl = hw->priv;
2718 int ret = 0;
2719
2720 mutex_lock(&wl->mutex);
2721
2722 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2723 ret = -EAGAIN;
2724 goto out;
2725 }
2726
Ido Yariva6208652011-03-01 15:14:41 +02002727 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002728 if (ret < 0)
2729 goto out;
2730
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002731 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002732 if (ret < 0)
2733 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2734
2735 wl1271_ps_elp_sleep(wl);
2736
2737out:
2738 mutex_unlock(&wl->mutex);
2739
2740 return ret;
2741}
2742
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2744{
2745 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002746 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747
2748 mutex_lock(&wl->mutex);
2749
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002750 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2751 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002752 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002753 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002754
Ido Yariva6208652011-03-01 15:14:41 +02002755 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002756 if (ret < 0)
2757 goto out;
2758
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002759 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002760 if (ret < 0)
2761 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2762
2763 wl1271_ps_elp_sleep(wl);
2764
2765out:
2766 mutex_unlock(&wl->mutex);
2767
2768 return ret;
2769}
2770
Arik Nemtsove78a2872010-10-16 19:07:21 +02002771static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002772 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002773{
Eliad Peller889cb362011-05-01 09:56:45 +03002774 u8 ssid_len;
2775 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2776 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002777
Eliad Peller889cb362011-05-01 09:56:45 +03002778 if (!ptr) {
2779 wl1271_error("No SSID in IEs!");
2780 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002781 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002782
Eliad Peller889cb362011-05-01 09:56:45 +03002783 ssid_len = ptr[1];
2784 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2785 wl1271_error("SSID is too long!");
2786 return -EINVAL;
2787 }
2788
2789 wl->ssid_len = ssid_len;
2790 memcpy(wl->ssid, ptr+2, ssid_len);
2791 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002792}
2793
Arik Nemtsove78a2872010-10-16 19:07:21 +02002794static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2795 struct ieee80211_bss_conf *bss_conf,
2796 u32 changed)
2797{
2798 int ret = 0;
2799
2800 if (changed & BSS_CHANGED_ERP_SLOT) {
2801 if (bss_conf->use_short_slot)
2802 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2803 else
2804 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2805 if (ret < 0) {
2806 wl1271_warning("Set slot time failed %d", ret);
2807 goto out;
2808 }
2809 }
2810
2811 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2812 if (bss_conf->use_short_preamble)
2813 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2814 else
2815 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2816 }
2817
2818 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2819 if (bss_conf->use_cts_prot)
2820 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2821 else
2822 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2823 if (ret < 0) {
2824 wl1271_warning("Set ctsprotect failed %d", ret);
2825 goto out;
2826 }
2827 }
2828
2829out:
2830 return ret;
2831}
2832
2833static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2834 struct ieee80211_vif *vif,
2835 struct ieee80211_bss_conf *bss_conf,
2836 u32 changed)
2837{
2838 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2839 int ret = 0;
2840
2841 if ((changed & BSS_CHANGED_BEACON_INT)) {
2842 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2843 bss_conf->beacon_int);
2844
2845 wl->beacon_int = bss_conf->beacon_int;
2846 }
2847
2848 if ((changed & BSS_CHANGED_BEACON)) {
2849 struct ieee80211_hdr *hdr;
2850 int ieoffset = offsetof(struct ieee80211_mgmt,
2851 u.beacon.variable);
2852 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2853 u16 tmpl_id;
2854
2855 if (!beacon)
2856 goto out;
2857
2858 wl1271_debug(DEBUG_MASTER, "beacon updated");
2859
2860 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2861 if (ret < 0) {
2862 dev_kfree_skb(beacon);
2863 goto out;
2864 }
2865 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2866 CMD_TEMPL_BEACON;
2867 ret = wl1271_cmd_template_set(wl, tmpl_id,
2868 beacon->data,
2869 beacon->len, 0,
2870 wl1271_tx_min_rate_get(wl));
2871 if (ret < 0) {
2872 dev_kfree_skb(beacon);
2873 goto out;
2874 }
2875
2876 hdr = (struct ieee80211_hdr *) beacon->data;
2877 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2878 IEEE80211_STYPE_PROBE_RESP);
2879
2880 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2881 CMD_TEMPL_PROBE_RESPONSE;
2882 ret = wl1271_cmd_template_set(wl,
2883 tmpl_id,
2884 beacon->data,
2885 beacon->len, 0,
2886 wl1271_tx_min_rate_get(wl));
2887 dev_kfree_skb(beacon);
2888 if (ret < 0)
2889 goto out;
2890 }
2891
2892out:
2893 return ret;
2894}
2895
2896/* AP mode changes */
2897static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002898 struct ieee80211_vif *vif,
2899 struct ieee80211_bss_conf *bss_conf,
2900 u32 changed)
2901{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002902 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002903
Arik Nemtsove78a2872010-10-16 19:07:21 +02002904 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2905 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002906
Arik Nemtsove78a2872010-10-16 19:07:21 +02002907 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2908 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002909
Arik Nemtsov70f47422011-04-18 14:15:25 +03002910 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002911 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002912 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002913 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002914 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002915
2916 ret = wl1271_ap_init_templates(wl);
2917 if (ret < 0)
2918 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002919 }
2920
Arik Nemtsove78a2872010-10-16 19:07:21 +02002921 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2922 if (ret < 0)
2923 goto out;
2924
2925 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2926 if (bss_conf->enable_beacon) {
2927 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2928 ret = wl1271_cmd_start_bss(wl);
2929 if (ret < 0)
2930 goto out;
2931
2932 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2933 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002934
2935 ret = wl1271_ap_init_hwenc(wl);
2936 if (ret < 0)
2937 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002938 }
2939 } else {
2940 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2941 ret = wl1271_cmd_stop_bss(wl);
2942 if (ret < 0)
2943 goto out;
2944
2945 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2946 wl1271_debug(DEBUG_AP, "stopped AP");
2947 }
2948 }
2949 }
2950
2951 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2952 if (ret < 0)
2953 goto out;
2954out:
2955 return;
2956}
2957
2958/* STA/IBSS mode changes */
2959static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2960 struct ieee80211_vif *vif,
2961 struct ieee80211_bss_conf *bss_conf,
2962 u32 changed)
2963{
2964 bool do_join = false, set_assoc = false;
2965 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002966 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002967 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002968 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002969 bool sta_exists = false;
2970 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002971
2972 if (is_ibss) {
2973 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2974 changed);
2975 if (ret < 0)
2976 goto out;
2977 }
2978
2979 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2980 do_join = true;
2981
2982 /* Need to update the SSID (for filtering etc) */
2983 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2984 do_join = true;
2985
2986 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002987 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2988 bss_conf->enable_beacon ? "enabled" : "disabled");
2989
2990 if (bss_conf->enable_beacon)
2991 wl->set_bss_type = BSS_TYPE_IBSS;
2992 else
2993 wl->set_bss_type = BSS_TYPE_STA_BSS;
2994 do_join = true;
2995 }
2996
Arik Nemtsove78a2872010-10-16 19:07:21 +02002997 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002998 bool enable = false;
2999 if (bss_conf->cqm_rssi_thold)
3000 enable = true;
3001 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3002 bss_conf->cqm_rssi_thold,
3003 bss_conf->cqm_rssi_hyst);
3004 if (ret < 0)
3005 goto out;
3006 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3007 }
3008
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003009 if ((changed & BSS_CHANGED_BSSID) &&
3010 /*
3011 * Now we know the correct bssid, so we send a new join command
3012 * and enable the BSSID filter
3013 */
3014 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003015 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003016
Eliad Pellerfa287b82010-12-26 09:27:50 +01003017 if (!is_zero_ether_addr(wl->bssid)) {
3018 ret = wl1271_cmd_build_null_data(wl);
3019 if (ret < 0)
3020 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003021
Eliad Pellerfa287b82010-12-26 09:27:50 +01003022 ret = wl1271_build_qos_null_data(wl);
3023 if (ret < 0)
3024 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003025
Eliad Pellerfa287b82010-12-26 09:27:50 +01003026 /* filter out all packets not from this BSSID */
3027 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02003028
Eliad Pellerfa287b82010-12-26 09:27:50 +01003029 /* Need to update the BSSID (for filtering etc) */
3030 do_join = true;
3031 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003032 }
3033
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003034 rcu_read_lock();
3035 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3036 if (sta) {
3037 /* save the supp_rates of the ap */
3038 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3039 if (sta->ht_cap.ht_supported)
3040 sta_rate_set |=
3041 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003042 sta_ht_cap = sta->ht_cap;
3043 sta_exists = true;
3044 }
3045 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003046
Arik Nemtsova1008852011-02-12 23:24:20 +02003047 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003048 /* handle new association with HT and HT information change */
3049 if ((changed & BSS_CHANGED_HT) &&
3050 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003051 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003052 true);
3053 if (ret < 0) {
3054 wl1271_warning("Set ht cap true failed %d",
3055 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003056 goto out;
3057 }
3058 ret = wl1271_acx_set_ht_information(wl,
3059 bss_conf->ht_operation_mode);
3060 if (ret < 0) {
3061 wl1271_warning("Set ht information failed %d",
3062 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003063 goto out;
3064 }
3065 }
3066 /* handle new association without HT and disassociation */
3067 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003068 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003069 false);
3070 if (ret < 0) {
3071 wl1271_warning("Set ht cap false failed %d",
3072 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003073 goto out;
3074 }
3075 }
3076 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003077
Arik Nemtsove78a2872010-10-16 19:07:21 +02003078 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003079 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003080 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003081 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003082 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003083 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003084
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003085 wl->ps_poll_failures = 0;
3086
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003087 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003088 * use basic rates from AP, and determine lowest rate
3089 * to use with control frames.
3090 */
3091 rates = bss_conf->basic_rates;
3092 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3093 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003094 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003095 if (sta_rate_set)
3096 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3097 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003098 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003099 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003100 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003101
3102 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003103 * with wl1271, we don't need to update the
3104 * beacon_int and dtim_period, because the firmware
3105 * updates it by itself when the first beacon is
3106 * received after a join.
3107 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003108 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3109 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003110 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003112 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003113 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003114 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003115 dev_kfree_skb(wl->probereq);
3116 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3117 ieoffset = offsetof(struct ieee80211_mgmt,
3118 u.probe_req.variable);
3119 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003120
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003121 /* enable the connection monitoring feature */
3122 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003124 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003125
3126 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003127 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3128 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003129 enum wl1271_cmd_ps_mode mode;
3130
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003131 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003132 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003133 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003134 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003135 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003136 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003137 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003138 } else {
3139 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003140 bool was_assoc =
3141 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3142 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003143 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003144 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003145
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003146 /* free probe-request template */
3147 dev_kfree_skb(wl->probereq);
3148 wl->probereq = NULL;
3149
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003150 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003151 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003152
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003153 /* revert back to minimum rates for the current band */
3154 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003155 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003156 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003157 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003158 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003159
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003160 /* disable connection monitor features */
3161 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003162
3163 /* Disable the keep-alive feature */
3164 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003165 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003166 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003167
3168 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003169 if (was_assoc) {
3170 wl1271_unjoin(wl);
3171 wl1271_dummy_join(wl);
3172 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003173 }
3174 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003175
Eliad Pellerd192d262011-05-24 14:33:08 +03003176 if (changed & BSS_CHANGED_IBSS) {
3177 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3178 bss_conf->ibss_joined);
3179
3180 if (bss_conf->ibss_joined) {
3181 u32 rates = bss_conf->basic_rates;
3182 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3183 rates);
3184 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3185
3186 /* by default, use 11b rates */
3187 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3188 ret = wl1271_acx_sta_rate_policies(wl);
3189 if (ret < 0)
3190 goto out;
3191 }
3192 }
3193
Arik Nemtsove78a2872010-10-16 19:07:21 +02003194 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3195 if (ret < 0)
3196 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003197
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003198 if (changed & BSS_CHANGED_ARP_FILTER) {
3199 __be32 addr = bss_conf->arp_addr_list[0];
3200 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3201
Eliad Pellerc5312772010-12-09 11:31:27 +02003202 if (bss_conf->arp_addr_cnt == 1 &&
3203 bss_conf->arp_filter_enabled) {
3204 /*
3205 * The template should have been configured only upon
3206 * association. however, it seems that the correct ip
3207 * isn't being set (when sending), so we have to
3208 * reconfigure the template upon every ip change.
3209 */
3210 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3211 if (ret < 0) {
3212 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003213 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003214 }
3215
3216 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003217 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003218 addr);
3219 } else
3220 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003221
3222 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003223 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003224 }
3225
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003226 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003227 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003228 if (ret < 0) {
3229 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003230 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003231 }
Eliad Pelleref4b29e2011-06-06 13:03:12 +03003232 wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003233 }
3234
Arik Nemtsove78a2872010-10-16 19:07:21 +02003235out:
3236 return;
3237}
3238
3239static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3240 struct ieee80211_vif *vif,
3241 struct ieee80211_bss_conf *bss_conf,
3242 u32 changed)
3243{
3244 struct wl1271 *wl = hw->priv;
3245 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3246 int ret;
3247
3248 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3249 (int)changed);
3250
3251 mutex_lock(&wl->mutex);
3252
3253 if (unlikely(wl->state == WL1271_STATE_OFF))
3254 goto out;
3255
Ido Yariva6208652011-03-01 15:14:41 +02003256 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003257 if (ret < 0)
3258 goto out;
3259
3260 if (is_ap)
3261 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3262 else
3263 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265 wl1271_ps_elp_sleep(wl);
3266
3267out:
3268 mutex_unlock(&wl->mutex);
3269}
3270
Kalle Valoc6999d82010-02-18 13:25:41 +02003271static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3272 const struct ieee80211_tx_queue_params *params)
3273{
3274 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003275 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003276 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003277
3278 mutex_lock(&wl->mutex);
3279
3280 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3281
Kalle Valo4695dc92010-03-18 12:26:38 +02003282 if (params->uapsd)
3283 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3284 else
3285 ps_scheme = CONF_PS_SCHEME_LEGACY;
3286
Arik Nemtsov488fc542010-10-16 20:33:45 +02003287 if (wl->state == WL1271_STATE_OFF) {
3288 /*
3289 * If the state is off, the parameters will be recorded and
3290 * configured on init. This happens in AP-mode.
3291 */
3292 struct conf_tx_ac_category *conf_ac =
3293 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3294 struct conf_tx_tid *conf_tid =
3295 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3296
3297 conf_ac->ac = wl1271_tx_get_queue(queue);
3298 conf_ac->cw_min = (u8)params->cw_min;
3299 conf_ac->cw_max = params->cw_max;
3300 conf_ac->aifsn = params->aifs;
3301 conf_ac->tx_op_limit = params->txop << 5;
3302
3303 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3304 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3305 conf_tid->tsid = wl1271_tx_get_queue(queue);
3306 conf_tid->ps_scheme = ps_scheme;
3307 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3308 conf_tid->apsd_conf[0] = 0;
3309 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003310 goto out;
3311 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003312
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003313 ret = wl1271_ps_elp_wakeup(wl);
3314 if (ret < 0)
3315 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003316
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003317 /*
3318 * the txop is confed in units of 32us by the mac80211,
3319 * we need us
3320 */
3321 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3322 params->cw_min, params->cw_max,
3323 params->aifs, params->txop << 5);
3324 if (ret < 0)
3325 goto out_sleep;
3326
3327 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3328 CONF_CHANNEL_TYPE_EDCF,
3329 wl1271_tx_get_queue(queue),
3330 ps_scheme, CONF_ACK_POLICY_LEGACY,
3331 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003332
3333out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003334 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003335
3336out:
3337 mutex_unlock(&wl->mutex);
3338
3339 return ret;
3340}
3341
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003342static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3343{
3344
3345 struct wl1271 *wl = hw->priv;
3346 u64 mactime = ULLONG_MAX;
3347 int ret;
3348
3349 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3350
3351 mutex_lock(&wl->mutex);
3352
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003353 if (unlikely(wl->state == WL1271_STATE_OFF))
3354 goto out;
3355
Ido Yariva6208652011-03-01 15:14:41 +02003356 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003357 if (ret < 0)
3358 goto out;
3359
3360 ret = wl1271_acx_tsf_info(wl, &mactime);
3361 if (ret < 0)
3362 goto out_sleep;
3363
3364out_sleep:
3365 wl1271_ps_elp_sleep(wl);
3366
3367out:
3368 mutex_unlock(&wl->mutex);
3369 return mactime;
3370}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003371
John W. Linvilleece550d2010-07-28 16:41:06 -04003372static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3373 struct survey_info *survey)
3374{
3375 struct wl1271 *wl = hw->priv;
3376 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003377
John W. Linvilleece550d2010-07-28 16:41:06 -04003378 if (idx != 0)
3379 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003380
John W. Linvilleece550d2010-07-28 16:41:06 -04003381 survey->channel = conf->channel;
3382 survey->filled = SURVEY_INFO_NOISE_DBM;
3383 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003384
John W. Linvilleece550d2010-07-28 16:41:06 -04003385 return 0;
3386}
3387
Arik Nemtsov409622e2011-02-23 00:22:29 +02003388static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003389 struct ieee80211_sta *sta,
3390 u8 *hlid)
3391{
3392 struct wl1271_station *wl_sta;
3393 int id;
3394
3395 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3396 if (id >= AP_MAX_STATIONS) {
3397 wl1271_warning("could not allocate HLID - too much stations");
3398 return -EBUSY;
3399 }
3400
3401 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003402 __set_bit(id, wl->ap_hlid_map);
3403 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3404 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003405 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003406 return 0;
3407}
3408
Arik Nemtsov409622e2011-02-23 00:22:29 +02003409static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003410{
3411 int id = hlid - WL1271_AP_STA_HLID_START;
3412
Arik Nemtsov409622e2011-02-23 00:22:29 +02003413 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3414 return;
3415
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003416 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003417 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003418 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003419 __clear_bit(hlid, &wl->ap_ps_map);
3420 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003421}
3422
3423static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3424 struct ieee80211_vif *vif,
3425 struct ieee80211_sta *sta)
3426{
3427 struct wl1271 *wl = hw->priv;
3428 int ret = 0;
3429 u8 hlid;
3430
3431 mutex_lock(&wl->mutex);
3432
3433 if (unlikely(wl->state == WL1271_STATE_OFF))
3434 goto out;
3435
3436 if (wl->bss_type != BSS_TYPE_AP_BSS)
3437 goto out;
3438
3439 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3440
Arik Nemtsov409622e2011-02-23 00:22:29 +02003441 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003442 if (ret < 0)
3443 goto out;
3444
Ido Yariva6208652011-03-01 15:14:41 +02003445 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003446 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003447 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003448
3449 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3450 if (ret < 0)
3451 goto out_sleep;
3452
3453out_sleep:
3454 wl1271_ps_elp_sleep(wl);
3455
Arik Nemtsov409622e2011-02-23 00:22:29 +02003456out_free_sta:
3457 if (ret < 0)
3458 wl1271_free_sta(wl, hlid);
3459
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003460out:
3461 mutex_unlock(&wl->mutex);
3462 return ret;
3463}
3464
3465static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3466 struct ieee80211_vif *vif,
3467 struct ieee80211_sta *sta)
3468{
3469 struct wl1271 *wl = hw->priv;
3470 struct wl1271_station *wl_sta;
3471 int ret = 0, id;
3472
3473 mutex_lock(&wl->mutex);
3474
3475 if (unlikely(wl->state == WL1271_STATE_OFF))
3476 goto out;
3477
3478 if (wl->bss_type != BSS_TYPE_AP_BSS)
3479 goto out;
3480
3481 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3482
3483 wl_sta = (struct wl1271_station *)sta->drv_priv;
3484 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3485 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3486 goto out;
3487
Ido Yariva6208652011-03-01 15:14:41 +02003488 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003489 if (ret < 0)
3490 goto out;
3491
3492 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3493 if (ret < 0)
3494 goto out_sleep;
3495
Arik Nemtsov409622e2011-02-23 00:22:29 +02003496 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003497
3498out_sleep:
3499 wl1271_ps_elp_sleep(wl);
3500
3501out:
3502 mutex_unlock(&wl->mutex);
3503 return ret;
3504}
3505
Luciano Coelho4623ec72011-03-21 19:26:41 +02003506static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3507 struct ieee80211_vif *vif,
3508 enum ieee80211_ampdu_mlme_action action,
3509 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3510 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003511{
3512 struct wl1271 *wl = hw->priv;
3513 int ret;
3514
3515 mutex_lock(&wl->mutex);
3516
3517 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3518 ret = -EAGAIN;
3519 goto out;
3520 }
3521
Ido Yariva6208652011-03-01 15:14:41 +02003522 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003523 if (ret < 0)
3524 goto out;
3525
Shahar Levi70559a02011-05-22 16:10:22 +03003526 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3527 tid, action);
3528
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003529 switch (action) {
3530 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003531 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003532 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3533 true);
3534 if (!ret)
3535 wl->ba_rx_bitmap |= BIT(tid);
3536 } else {
3537 ret = -ENOTSUPP;
3538 }
3539 break;
3540
3541 case IEEE80211_AMPDU_RX_STOP:
3542 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3543 if (!ret)
3544 wl->ba_rx_bitmap &= ~BIT(tid);
3545 break;
3546
3547 /*
3548 * The BA initiator session management in FW independently.
3549 * Falling break here on purpose for all TX APDU commands.
3550 */
3551 case IEEE80211_AMPDU_TX_START:
3552 case IEEE80211_AMPDU_TX_STOP:
3553 case IEEE80211_AMPDU_TX_OPERATIONAL:
3554 ret = -EINVAL;
3555 break;
3556
3557 default:
3558 wl1271_error("Incorrect ampdu action id=%x\n", action);
3559 ret = -EINVAL;
3560 }
3561
3562 wl1271_ps_elp_sleep(wl);
3563
3564out:
3565 mutex_unlock(&wl->mutex);
3566
3567 return ret;
3568}
3569
Arik Nemtsov33437892011-04-26 23:35:39 +03003570static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3571{
3572 struct wl1271 *wl = hw->priv;
3573 bool ret = false;
3574
3575 mutex_lock(&wl->mutex);
3576
3577 if (unlikely(wl->state == WL1271_STATE_OFF))
3578 goto out;
3579
3580 /* packets are considered pending if in the TX queue or the FW */
3581 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3582
3583 /* the above is appropriate for STA mode for PS purposes */
3584 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3585
3586out:
3587 mutex_unlock(&wl->mutex);
3588
3589 return ret;
3590}
3591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592/* can't be const, mac80211 writes to this */
3593static struct ieee80211_rate wl1271_rates[] = {
3594 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003595 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3596 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003598 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3599 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003600 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3601 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003602 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3603 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003604 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3605 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003606 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3607 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003608 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3609 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003610 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3611 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003612 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003613 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3614 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003615 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003616 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3617 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003618 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003619 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3620 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003621 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003622 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3623 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003624 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003625 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3626 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003627 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003628 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3629 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003630 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003631 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3632 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003633};
3634
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003635/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003636static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003637 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003638 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003639 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3640 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3641 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003642 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003643 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3644 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3645 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003646 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003647 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3648 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3649 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003650 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003651};
3652
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003653/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003654static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003655 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003656 7, /* CONF_HW_RXTX_RATE_MCS7 */
3657 6, /* CONF_HW_RXTX_RATE_MCS6 */
3658 5, /* CONF_HW_RXTX_RATE_MCS5 */
3659 4, /* CONF_HW_RXTX_RATE_MCS4 */
3660 3, /* CONF_HW_RXTX_RATE_MCS3 */
3661 2, /* CONF_HW_RXTX_RATE_MCS2 */
3662 1, /* CONF_HW_RXTX_RATE_MCS1 */
3663 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003664
3665 11, /* CONF_HW_RXTX_RATE_54 */
3666 10, /* CONF_HW_RXTX_RATE_48 */
3667 9, /* CONF_HW_RXTX_RATE_36 */
3668 8, /* CONF_HW_RXTX_RATE_24 */
3669
3670 /* TI-specific rate */
3671 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3672
3673 7, /* CONF_HW_RXTX_RATE_18 */
3674 6, /* CONF_HW_RXTX_RATE_12 */
3675 3, /* CONF_HW_RXTX_RATE_11 */
3676 5, /* CONF_HW_RXTX_RATE_9 */
3677 4, /* CONF_HW_RXTX_RATE_6 */
3678 2, /* CONF_HW_RXTX_RATE_5_5 */
3679 1, /* CONF_HW_RXTX_RATE_2 */
3680 0 /* CONF_HW_RXTX_RATE_1 */
3681};
3682
Shahar Levie8b03a22010-10-13 16:09:39 +02003683/* 11n STA capabilities */
3684#define HW_RX_HIGHEST_RATE 72
3685
Shahar Levi00d20102010-11-08 11:20:10 +00003686#ifdef CONFIG_WL12XX_HT
3687#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003688 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3689 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003690 .ht_supported = true, \
3691 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3692 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3693 .mcs = { \
3694 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3695 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3696 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3697 }, \
3698}
Shahar Levi18357852010-10-13 16:09:41 +02003699#else
Shahar Levi00d20102010-11-08 11:20:10 +00003700#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003701 .ht_supported = false, \
3702}
3703#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003704
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705/* can't be const, mac80211 writes to this */
3706static struct ieee80211_supported_band wl1271_band_2ghz = {
3707 .channels = wl1271_channels,
3708 .n_channels = ARRAY_SIZE(wl1271_channels),
3709 .bitrates = wl1271_rates,
3710 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003711 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003712};
3713
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003714/* 5 GHz data rates for WL1273 */
3715static struct ieee80211_rate wl1271_rates_5ghz[] = {
3716 { .bitrate = 60,
3717 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3718 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3719 { .bitrate = 90,
3720 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3721 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3722 { .bitrate = 120,
3723 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3724 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3725 { .bitrate = 180,
3726 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3727 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3728 { .bitrate = 240,
3729 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3730 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3731 { .bitrate = 360,
3732 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3733 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3734 { .bitrate = 480,
3735 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3736 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3737 { .bitrate = 540,
3738 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3739 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3740};
3741
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003742/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003743static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003744 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003745 { .hw_value = 8, .center_freq = 5040},
3746 { .hw_value = 9, .center_freq = 5045},
3747 { .hw_value = 11, .center_freq = 5055},
3748 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003749 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003750 { .hw_value = 34, .center_freq = 5170},
3751 { .hw_value = 36, .center_freq = 5180},
3752 { .hw_value = 38, .center_freq = 5190},
3753 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003754 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003755 { .hw_value = 44, .center_freq = 5220},
3756 { .hw_value = 46, .center_freq = 5230},
3757 { .hw_value = 48, .center_freq = 5240},
3758 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003759 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003760 { .hw_value = 60, .center_freq = 5300},
3761 { .hw_value = 64, .center_freq = 5320},
3762 { .hw_value = 100, .center_freq = 5500},
3763 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003764 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003765 { .hw_value = 112, .center_freq = 5560},
3766 { .hw_value = 116, .center_freq = 5580},
3767 { .hw_value = 120, .center_freq = 5600},
3768 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003769 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003770 { .hw_value = 132, .center_freq = 5660},
3771 { .hw_value = 136, .center_freq = 5680},
3772 { .hw_value = 140, .center_freq = 5700},
3773 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003774 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003775 { .hw_value = 157, .center_freq = 5785},
3776 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003777 { .hw_value = 165, .center_freq = 5825},
3778};
3779
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003780/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003781static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003782 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003783 7, /* CONF_HW_RXTX_RATE_MCS7 */
3784 6, /* CONF_HW_RXTX_RATE_MCS6 */
3785 5, /* CONF_HW_RXTX_RATE_MCS5 */
3786 4, /* CONF_HW_RXTX_RATE_MCS4 */
3787 3, /* CONF_HW_RXTX_RATE_MCS3 */
3788 2, /* CONF_HW_RXTX_RATE_MCS2 */
3789 1, /* CONF_HW_RXTX_RATE_MCS1 */
3790 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003791
3792 7, /* CONF_HW_RXTX_RATE_54 */
3793 6, /* CONF_HW_RXTX_RATE_48 */
3794 5, /* CONF_HW_RXTX_RATE_36 */
3795 4, /* CONF_HW_RXTX_RATE_24 */
3796
3797 /* TI-specific rate */
3798 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3799
3800 3, /* CONF_HW_RXTX_RATE_18 */
3801 2, /* CONF_HW_RXTX_RATE_12 */
3802 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3803 1, /* CONF_HW_RXTX_RATE_9 */
3804 0, /* CONF_HW_RXTX_RATE_6 */
3805 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3806 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3807 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3808};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003809
3810static struct ieee80211_supported_band wl1271_band_5ghz = {
3811 .channels = wl1271_channels_5ghz,
3812 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3813 .bitrates = wl1271_rates_5ghz,
3814 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003815 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003816};
3817
Tobias Klausera0ea9492010-05-20 10:38:11 +02003818static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003819 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3820 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3821};
3822
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003823static const struct ieee80211_ops wl1271_ops = {
3824 .start = wl1271_op_start,
3825 .stop = wl1271_op_stop,
3826 .add_interface = wl1271_op_add_interface,
3827 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003828#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003829 .suspend = wl1271_op_suspend,
3830 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003831#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003832 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003833 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003834 .configure_filter = wl1271_op_configure_filter,
3835 .tx = wl1271_op_tx,
3836 .set_key = wl1271_op_set_key,
3837 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003838 .sched_scan_start = wl1271_op_sched_scan_start,
3839 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003840 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003841 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003842 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003843 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003844 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003845 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003846 .sta_add = wl1271_op_sta_add,
3847 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003848 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003849 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003850 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003851};
3852
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003853
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003854u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003855{
3856 u8 idx;
3857
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003858 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003859
3860 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3861 wl1271_error("Illegal RX rate from HW: %d", rate);
3862 return 0;
3863 }
3864
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003865 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003866 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3867 wl1271_error("Unsupported RX rate from HW: %d", rate);
3868 return 0;
3869 }
3870
3871 return idx;
3872}
3873
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003874static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3875 struct device_attribute *attr,
3876 char *buf)
3877{
3878 struct wl1271 *wl = dev_get_drvdata(dev);
3879 ssize_t len;
3880
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003881 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003882
3883 mutex_lock(&wl->mutex);
3884 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3885 wl->sg_enabled);
3886 mutex_unlock(&wl->mutex);
3887
3888 return len;
3889
3890}
3891
3892static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3893 struct device_attribute *attr,
3894 const char *buf, size_t count)
3895{
3896 struct wl1271 *wl = dev_get_drvdata(dev);
3897 unsigned long res;
3898 int ret;
3899
Luciano Coelho6277ed62011-04-01 17:49:54 +03003900 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003901 if (ret < 0) {
3902 wl1271_warning("incorrect value written to bt_coex_mode");
3903 return count;
3904 }
3905
3906 mutex_lock(&wl->mutex);
3907
3908 res = !!res;
3909
3910 if (res == wl->sg_enabled)
3911 goto out;
3912
3913 wl->sg_enabled = res;
3914
3915 if (wl->state == WL1271_STATE_OFF)
3916 goto out;
3917
Ido Yariva6208652011-03-01 15:14:41 +02003918 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003919 if (ret < 0)
3920 goto out;
3921
3922 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3923 wl1271_ps_elp_sleep(wl);
3924
3925 out:
3926 mutex_unlock(&wl->mutex);
3927 return count;
3928}
3929
3930static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3931 wl1271_sysfs_show_bt_coex_state,
3932 wl1271_sysfs_store_bt_coex_state);
3933
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003934static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3935 struct device_attribute *attr,
3936 char *buf)
3937{
3938 struct wl1271 *wl = dev_get_drvdata(dev);
3939 ssize_t len;
3940
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003941 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003942
3943 mutex_lock(&wl->mutex);
3944 if (wl->hw_pg_ver >= 0)
3945 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3946 else
3947 len = snprintf(buf, len, "n/a\n");
3948 mutex_unlock(&wl->mutex);
3949
3950 return len;
3951}
3952
3953static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3954 wl1271_sysfs_show_hw_pg_ver, NULL);
3955
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003956int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003957{
3958 int ret;
3959
3960 if (wl->mac80211_registered)
3961 return 0;
3962
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003963 ret = wl1271_fetch_nvs(wl);
3964 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003965 /* NOTE: The wl->nvs->nvs element must be first, in
3966 * order to simplify the casting, we assume it is at
3967 * the beginning of the wl->nvs structure.
3968 */
3969 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003970
3971 wl->mac_addr[0] = nvs_ptr[11];
3972 wl->mac_addr[1] = nvs_ptr[10];
3973 wl->mac_addr[2] = nvs_ptr[6];
3974 wl->mac_addr[3] = nvs_ptr[5];
3975 wl->mac_addr[4] = nvs_ptr[4];
3976 wl->mac_addr[5] = nvs_ptr[3];
3977 }
3978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003979 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3980
3981 ret = ieee80211_register_hw(wl->hw);
3982 if (ret < 0) {
3983 wl1271_error("unable to register mac80211 hw: %d", ret);
3984 return ret;
3985 }
3986
3987 wl->mac80211_registered = true;
3988
Eliad Pellerd60080a2010-11-24 12:53:16 +02003989 wl1271_debugfs_init(wl);
3990
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003991 register_netdevice_notifier(&wl1271_dev_notifier);
3992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003993 wl1271_notice("loaded");
3994
3995 return 0;
3996}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003997EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003998
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003999void wl1271_unregister_hw(struct wl1271 *wl)
4000{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004001 if (wl->state == WL1271_STATE_PLT)
4002 __wl1271_plt_stop(wl);
4003
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004004 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004005 ieee80211_unregister_hw(wl->hw);
4006 wl->mac80211_registered = false;
4007
4008}
4009EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4010
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004011int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004012{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004013 static const u32 cipher_suites[] = {
4014 WLAN_CIPHER_SUITE_WEP40,
4015 WLAN_CIPHER_SUITE_WEP104,
4016 WLAN_CIPHER_SUITE_TKIP,
4017 WLAN_CIPHER_SUITE_CCMP,
4018 WL1271_CIPHER_SUITE_GEM,
4019 };
4020
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004021 /* The tx descriptor buffer and the TKIP space. */
4022 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4023 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004024
4025 /* unit us */
4026 /* FIXME: find a proper value */
4027 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004028 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004029
4030 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004031 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004032 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004033 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004034 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004035 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004036 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004037 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004038 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004039 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004040
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004041 wl->hw->wiphy->cipher_suites = cipher_suites;
4042 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4043
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004044 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004045 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004046 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004047 /*
4048 * Maximum length of elements in scanning probe request templates
4049 * should be the maximum length possible for a template, without
4050 * the IEEE80211 header of the template
4051 */
4052 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
4053 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004054
Luciano Coelho4a31c112011-03-21 23:16:14 +02004055 /* make sure all our channels fit in the scanned_ch bitmask */
4056 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4057 ARRAY_SIZE(wl1271_channels_5ghz) >
4058 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004059 /*
4060 * We keep local copies of the band structs because we need to
4061 * modify them on a per-device basis.
4062 */
4063 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4064 sizeof(wl1271_band_2ghz));
4065 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4066 sizeof(wl1271_band_5ghz));
4067
4068 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4069 &wl->bands[IEEE80211_BAND_2GHZ];
4070 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4071 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004072
Kalle Valo12bd8942010-03-18 12:26:33 +02004073 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004074 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004075
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004076 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4077
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004078 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004079
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004080 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4081
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004082 wl->hw->max_rx_aggregation_subframes = 8;
4083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004084 return 0;
4085}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004086EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004087
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004088#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004089
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004090struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004091{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004092 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004093 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004094 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004095 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004096 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004097
4098 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4099 if (!hw) {
4100 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004101 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004102 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004103 }
4104
Julia Lawall929ebd32010-05-15 23:16:39 +02004105 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004106 if (!plat_dev) {
4107 wl1271_error("could not allocate platform_device");
4108 ret = -ENOMEM;
4109 goto err_plat_alloc;
4110 }
4111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004112 wl = hw->priv;
4113 memset(wl, 0, sizeof(*wl));
4114
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004115 INIT_LIST_HEAD(&wl->list);
4116
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004117 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004118 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004119
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004120 for (i = 0; i < NUM_TX_QUEUES; i++)
4121 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004122
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004123 for (i = 0; i < NUM_TX_QUEUES; i++)
4124 for (j = 0; j < AP_MAX_LINKS; j++)
4125 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4126
Ido Yariva6208652011-03-01 15:14:41 +02004127 skb_queue_head_init(&wl->deferred_rx_queue);
4128 skb_queue_head_init(&wl->deferred_tx_queue);
4129
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004130 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004131 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004132 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004133 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4134 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4135 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004136 INIT_WORK(&wl->rx_streaming_enable_work,
4137 wl1271_rx_streaming_enable_work);
4138 INIT_WORK(&wl->rx_streaming_disable_work,
4139 wl1271_rx_streaming_disable_work);
4140
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004141 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004142 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004143 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004144 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02004145 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
4146 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004147 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004148 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004149 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004150 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004151 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004152 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004153 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004154 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004155 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004156 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004157 wl->bss_type = MAX_BSS_TYPE;
4158 wl->set_bss_type = MAX_BSS_TYPE;
4159 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004160 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004161 wl->ap_ps_map = 0;
4162 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004163 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004164 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004165 wl->sched_scanning = false;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004166 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4167 (unsigned long) wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004168
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004169 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004170 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004171 wl->tx_frames[i] = NULL;
4172
4173 spin_lock_init(&wl->wl_lock);
4174
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004175 wl->state = WL1271_STATE_OFF;
4176 mutex_init(&wl->mutex);
4177
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004178 /* Apply default driver configuration. */
4179 wl1271_conf_init(wl);
4180
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004181 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4182 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4183 if (!wl->aggr_buf) {
4184 ret = -ENOMEM;
4185 goto err_hw;
4186 }
4187
Ido Yariv990f5de2011-03-31 10:06:59 +02004188 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4189 if (!wl->dummy_packet) {
4190 ret = -ENOMEM;
4191 goto err_aggr;
4192 }
4193
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004194 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004195 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004196 if (ret) {
4197 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004198 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004199 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004200 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004201
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004202 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004203 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004204 if (ret < 0) {
4205 wl1271_error("failed to create sysfs file bt_coex_state");
4206 goto err_platform;
4207 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004208
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004209 /* Create sysfs file to get HW PG version */
4210 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4211 if (ret < 0) {
4212 wl1271_error("failed to create sysfs file hw_pg_ver");
4213 goto err_bt_coex_state;
4214 }
4215
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004216 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004217
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004218err_bt_coex_state:
4219 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4220
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004221err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004222 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004223
Ido Yariv990f5de2011-03-31 10:06:59 +02004224err_dummy_packet:
4225 dev_kfree_skb(wl->dummy_packet);
4226
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004227err_aggr:
4228 free_pages((unsigned long)wl->aggr_buf, order);
4229
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004230err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004231 wl1271_debugfs_exit(wl);
4232 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004233
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004234err_plat_alloc:
4235 ieee80211_free_hw(hw);
4236
4237err_hw_alloc:
4238
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004239 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004240}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004241EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004242
4243int wl1271_free_hw(struct wl1271 *wl)
4244{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004245 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004246 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004247 free_pages((unsigned long)wl->aggr_buf,
4248 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004249 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004250
4251 wl1271_debugfs_exit(wl);
4252
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004253 vfree(wl->fw);
4254 wl->fw = NULL;
4255 kfree(wl->nvs);
4256 wl->nvs = NULL;
4257
4258 kfree(wl->fw_status);
4259 kfree(wl->tx_res_if);
4260
4261 ieee80211_free_hw(wl->hw);
4262
4263 return 0;
4264}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004265EXPORT_SYMBOL_GPL(wl1271_free_hw);
4266
Guy Eilam491bbd62011-01-12 10:33:29 +01004267u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004268EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004269module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004270MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4271
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004272MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004273MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004274MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");