blob: 5f8bb35c64750e2da5bc1761a952618025ce7197 [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,
166 .rts_threshold = 2347,
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 },
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200212 .ap_rc_conf = {
213 [0] = {
214 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
215 .short_retry_limit = 10,
216 .long_retry_limit = 10,
217 .aflags = 0,
218 },
219 [1] = {
220 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
221 .short_retry_limit = 10,
222 .long_retry_limit = 10,
223 .aflags = 0,
224 },
225 [2] = {
226 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
227 .short_retry_limit = 10,
228 .long_retry_limit = 10,
229 .aflags = 0,
230 },
231 [3] = {
232 .enabled_rates = CONF_TX_AP_ENABLED_RATES,
233 .short_retry_limit = 10,
234 .long_retry_limit = 10,
235 .aflags = 0,
236 },
237 },
238 .ap_mgmt_conf = {
239 .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
240 .short_retry_limit = 10,
241 .long_retry_limit = 10,
242 .aflags = 0,
243 },
244 .ap_bcst_conf = {
245 .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
246 .short_retry_limit = 10,
247 .long_retry_limit = 10,
248 .aflags = 0,
249 },
Arik Nemtsov47684802011-04-26 23:21:51 +0300250 .max_tx_retries = 100,
251 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200252 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200254 [CONF_TX_AC_BE] = {
255 .queue_id = CONF_TX_AC_BE,
256 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300257 .tsid = CONF_TX_AC_BE,
258 .ps_scheme = CONF_PS_SCHEME_LEGACY,
259 .ack_policy = CONF_ACK_POLICY_LEGACY,
260 .apsd_conf = {0, 0},
261 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200262 [CONF_TX_AC_BK] = {
263 .queue_id = CONF_TX_AC_BK,
264 .channel_type = CONF_CHANNEL_TYPE_EDCF,
265 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300266 .ps_scheme = CONF_PS_SCHEME_LEGACY,
267 .ack_policy = CONF_ACK_POLICY_LEGACY,
268 .apsd_conf = {0, 0},
269 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200270 [CONF_TX_AC_VI] = {
271 .queue_id = CONF_TX_AC_VI,
272 .channel_type = CONF_CHANNEL_TYPE_EDCF,
273 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300274 .ps_scheme = CONF_PS_SCHEME_LEGACY,
275 .ack_policy = CONF_ACK_POLICY_LEGACY,
276 .apsd_conf = {0, 0},
277 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200278 [CONF_TX_AC_VO] = {
279 .queue_id = CONF_TX_AC_VO,
280 .channel_type = CONF_CHANNEL_TYPE_EDCF,
281 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300282 .ps_scheme = CONF_PS_SCHEME_LEGACY,
283 .ack_policy = CONF_ACK_POLICY_LEGACY,
284 .apsd_conf = {0, 0},
285 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
287 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200288 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300289 .tx_compl_threshold = 4,
290 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
291 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200292 .tmpl_short_retry_limit = 10,
293 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300294 },
295 .conn = {
296 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300297 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300298 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
299 .bcn_filt_ie_count = 1,
300 .bcn_filt_ie = {
301 [0] = {
302 .ie = WLAN_EID_CHANNEL_SWITCH,
303 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
304 }
305 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200306 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300307 .bss_lose_timeout = 100,
308 .beacon_rx_timeout = 10000,
309 .broadcast_timeout = 20000,
310 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300311 .ps_poll_threshold = 10,
312 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300313 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200314 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200315 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300316 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200317 .psm_entry_nullfunc_retries = 3,
318 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300319 .keep_alive_interval = 55000,
320 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300321 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200322 .itrim = {
323 .enable = false,
324 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200325 },
326 .pm_config = {
327 .host_clk_settling_time = 5000,
328 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300329 },
330 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300331 .trigger_pacing = 1,
332 .avg_weight_rssi_beacon = 20,
333 .avg_weight_rssi_data = 10,
334 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100335 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200336 },
337 .scan = {
338 .min_dwell_time_active = 7500,
339 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100340 .min_dwell_time_passive = 100000,
341 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200342 .num_probe_reqs = 2,
343 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200344 .rf = {
345 .tx_per_channel_power_compensation_2 = {
346 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347 },
348 .tx_per_channel_power_compensation_5 = {
349 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
352 },
353 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100354 .ht = {
355 .tx_ba_win_size = 64,
356 .inactivity_timeout = 10000,
357 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200358 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200359 .num_stations = 1,
360 .ssid_profiles = 1,
361 .rx_block_num = 70,
362 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300363 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200364 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200365 .min_req_rx_blocks = 22,
366 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200367 },
368 .mem_wl128x = {
369 .num_stations = 1,
370 .ssid_profiles = 1,
371 .rx_block_num = 40,
372 .tx_min_block_num = 40,
373 .dynamic_memory = 1,
374 .min_req_tx_blocks = 45,
375 .min_req_rx_blocks = 22,
376 .tx_min = 27,
377 },
Shahar Leviff868432011-04-11 15:41:46 +0300378 .fm_coex = {
379 .enable = true,
380 .swallow_period = 5,
381 .n_divider_fref_set_1 = 0xff, /* default */
382 .n_divider_fref_set_2 = 12,
383 .m_divider_fref_set_1 = 148,
384 .m_divider_fref_set_2 = 0xffff, /* default */
385 .coex_pll_stabilization_time = 0xffffffff, /* default */
386 .ldo_stabilization_time = 0xffff, /* default */
387 .fm_disturbed_band_margin = 0xff, /* default */
388 .swallow_clk_diff = 0xff, /* default */
389 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300390 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300391};
392
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200393static void __wl1271_op_remove_interface(struct wl1271 *wl);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200394static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200395
396
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200397static void wl1271_device_release(struct device *dev)
398{
399
400}
401
402static struct platform_device wl1271_device = {
403 .name = "wl1271",
404 .id = -1,
405
406 /* device model insists to have a release function */
407 .dev = {
408 .release = wl1271_device_release,
409 },
410};
411
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200412static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300413static LIST_HEAD(wl_list);
414
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300415static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
416 void *arg)
417{
418 struct net_device *dev = arg;
419 struct wireless_dev *wdev;
420 struct wiphy *wiphy;
421 struct ieee80211_hw *hw;
422 struct wl1271 *wl;
423 struct wl1271 *wl_temp;
424 int ret = 0;
425
426 /* Check that this notification is for us. */
427 if (what != NETDEV_CHANGE)
428 return NOTIFY_DONE;
429
430 wdev = dev->ieee80211_ptr;
431 if (wdev == NULL)
432 return NOTIFY_DONE;
433
434 wiphy = wdev->wiphy;
435 if (wiphy == NULL)
436 return NOTIFY_DONE;
437
438 hw = wiphy_priv(wiphy);
439 if (hw == NULL)
440 return NOTIFY_DONE;
441
442 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200443 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300444 list_for_each_entry(wl, &wl_list, list) {
445 if (wl == wl_temp)
446 break;
447 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200448 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300449 if (wl != wl_temp)
450 return NOTIFY_DONE;
451
452 mutex_lock(&wl->mutex);
453
454 if (wl->state == WL1271_STATE_OFF)
455 goto out;
456
457 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
458 goto out;
459
Ido Yariva6208652011-03-01 15:14:41 +0200460 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300461 if (ret < 0)
462 goto out;
463
464 if ((dev->operstate == IF_OPER_UP) &&
465 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
466 wl1271_cmd_set_sta_state(wl);
467 wl1271_info("Association completed.");
468 }
469
470 wl1271_ps_elp_sleep(wl);
471
472out:
473 mutex_unlock(&wl->mutex);
474
475 return NOTIFY_OK;
476}
477
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100478static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200479 struct regulatory_request *request)
480{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481 struct ieee80211_supported_band *band;
482 struct ieee80211_channel *ch;
483 int i;
484
485 band = wiphy->bands[IEEE80211_BAND_5GHZ];
486 for (i = 0; i < band->n_channels; i++) {
487 ch = &band->channels[i];
488 if (ch->flags & IEEE80211_CHAN_DISABLED)
489 continue;
490
491 if (ch->flags & IEEE80211_CHAN_RADAR)
492 ch->flags |= IEEE80211_CHAN_NO_IBSS |
493 IEEE80211_CHAN_PASSIVE_SCAN;
494
495 }
496
497 return 0;
498}
499
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300500static void wl1271_conf_init(struct wl1271 *wl)
501{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300502
503 /*
504 * This function applies the default configuration to the driver. This
505 * function is invoked upon driver load (spi probe.)
506 *
507 * The configuration is stored in a run-time structure in order to
508 * facilitate for run-time adjustment of any of the parameters. Making
509 * changes to the configuration structure will apply the new values on
510 * the next interface up (wl1271_op_start.)
511 */
512
513 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300514 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300515}
516
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518static int wl1271_plt_init(struct wl1271 *wl)
519{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200520 struct conf_tx_ac_category *conf_ac;
521 struct conf_tx_tid *conf_tid;
522 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300523
Shahar Levi49d750ca2011-03-06 16:32:09 +0200524 if (wl->chip.id == CHIP_ID_1283_PG20)
525 ret = wl128x_cmd_general_parms(wl);
526 else
527 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200528 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200529 return ret;
530
Shahar Levi49d750ca2011-03-06 16:32:09 +0200531 if (wl->chip.id == CHIP_ID_1283_PG20)
532 ret = wl128x_cmd_radio_parms(wl);
533 else
534 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200535 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200536 return ret;
537
Shahar Levi49d750ca2011-03-06 16:32:09 +0200538 if (wl->chip.id != CHIP_ID_1283_PG20) {
539 ret = wl1271_cmd_ext_radio_parms(wl);
540 if (ret < 0)
541 return ret;
542 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200543 if (ret < 0)
544 return ret;
545
Shahar Levi48a61472011-03-06 16:32:08 +0200546 /* Chip-specific initializations */
547 ret = wl1271_chip_specific_init(wl);
548 if (ret < 0)
549 return ret;
550
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200551 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200552 if (ret < 0)
553 return ret;
554
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300555 ret = wl1271_acx_init_mem_config(wl);
556 if (ret < 0)
557 return ret;
558
Luciano Coelho12419cce2010-02-18 13:25:44 +0200559 /* PHY layer config */
560 ret = wl1271_init_phy_config(wl);
561 if (ret < 0)
562 goto out_free_memmap;
563
564 ret = wl1271_acx_dco_itrim_params(wl);
565 if (ret < 0)
566 goto out_free_memmap;
567
568 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200569 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200570 if (ret < 0)
571 goto out_free_memmap;
572
573 /* Bluetooth WLAN coexistence */
574 ret = wl1271_init_pta(wl);
575 if (ret < 0)
576 goto out_free_memmap;
577
Shahar Leviff868432011-04-11 15:41:46 +0300578 /* FM WLAN coexistence */
579 ret = wl1271_acx_fm_coex(wl);
580 if (ret < 0)
581 goto out_free_memmap;
582
Luciano Coelho12419cce2010-02-18 13:25:44 +0200583 /* Energy detection */
584 ret = wl1271_init_energy_detection(wl);
585 if (ret < 0)
586 goto out_free_memmap;
587
Gery Kahn1ec610e2011-02-01 03:03:08 -0600588 ret = wl1271_acx_sta_mem_cfg(wl);
589 if (ret < 0)
590 goto out_free_memmap;
591
Luciano Coelho12419cce2010-02-18 13:25:44 +0200592 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100593 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200594 if (ret < 0)
595 goto out_free_memmap;
596
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200597 /* Default TID/AC configuration */
598 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200599 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200600 conf_ac = &wl->conf.tx.ac_conf[i];
601 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
602 conf_ac->cw_max, conf_ac->aifsn,
603 conf_ac->tx_op_limit);
604 if (ret < 0)
605 goto out_free_memmap;
606
Luciano Coelho12419cce2010-02-18 13:25:44 +0200607 conf_tid = &wl->conf.tx.tid_conf[i];
608 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
609 conf_tid->channel_type,
610 conf_tid->tsid,
611 conf_tid->ps_scheme,
612 conf_tid->ack_policy,
613 conf_tid->apsd_conf[0],
614 conf_tid->apsd_conf[1]);
615 if (ret < 0)
616 goto out_free_memmap;
617 }
618
Luciano Coelho12419cce2010-02-18 13:25:44 +0200619 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200620 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300621 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200622 goto out_free_memmap;
623
624 /* Configure for CAM power saving (ie. always active) */
625 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
626 if (ret < 0)
627 goto out_free_memmap;
628
629 /* configure PM */
630 ret = wl1271_acx_pm_config(wl);
631 if (ret < 0)
632 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300633
634 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200635
636 out_free_memmap:
637 kfree(wl->target_mem_map);
638 wl->target_mem_map = NULL;
639
640 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300641}
642
Arik Nemtsovb622d992011-02-23 00:22:31 +0200643static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
644{
645 bool fw_ps;
646
647 /* only regulate station links */
648 if (hlid < WL1271_AP_STA_HLID_START)
649 return;
650
651 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
652
653 /*
654 * Wake up from high level PS if the STA is asleep with too little
655 * blocks in FW or if the STA is awake.
656 */
657 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
658 wl1271_ps_link_end(wl, hlid);
659
660 /* Start high-level PS if the STA is asleep with enough blocks in FW */
661 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
662 wl1271_ps_link_start(wl, hlid, true);
663}
664
665static void wl1271_irq_update_links_status(struct wl1271 *wl,
666 struct wl1271_fw_ap_status *status)
667{
668 u32 cur_fw_ps_map;
669 u8 hlid;
670
671 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
672 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
673 wl1271_debug(DEBUG_PSM,
674 "link ps prev 0x%x cur 0x%x changed 0x%x",
675 wl->ap_fw_ps_map, cur_fw_ps_map,
676 wl->ap_fw_ps_map ^ cur_fw_ps_map);
677
678 wl->ap_fw_ps_map = cur_fw_ps_map;
679 }
680
681 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
682 u8 cnt = status->tx_lnk_free_blks[hlid] -
683 wl->links[hlid].prev_freed_blks;
684
685 wl->links[hlid].prev_freed_blks =
686 status->tx_lnk_free_blks[hlid];
687 wl->links[hlid].allocated_blks -= cnt;
688
689 wl1271_irq_ps_regulate_link(wl, hlid,
690 wl->links[hlid].allocated_blks);
691 }
692}
693
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300694static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200695 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300696{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200697 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200698 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200699 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200700 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701 int i;
702
Shahar Levi13b107d2011-03-06 16:32:12 +0200703 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200704 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
705 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200706 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200707 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
708 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200709 }
710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
712 "drv_rx_counter = %d, tx_results_counter = %d)",
713 status->intr,
714 status->fw_rx_counter,
715 status->drv_rx_counter,
716 status->tx_results_counter);
717
718 /* update number of available TX blocks */
719 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200720 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
721 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300722
723 wl->tx_blocks_freed[i] =
724 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200725 }
726
Ido Yarivd2f4d472011-03-31 10:07:00 +0200727 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200728
Ido Yarivd2f4d472011-03-31 10:07:00 +0200729 if (wl->bss_type == BSS_TYPE_AP_BSS) {
730 /* Update num of allocated TX blocks per link and ps status */
731 wl1271_irq_update_links_status(wl, &full_status->ap);
732 wl->tx_blocks_available += freed_blocks;
733 } else {
734 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
735
736 /*
737 * The FW might change the total number of TX memblocks before
738 * we get a notification about blocks being released. Thus, the
739 * available blocks calculation might yield a temporary result
740 * which is lower than the actual available blocks. Keeping in
741 * mind that only blocks that were allocated can be moved from
742 * TX to RX, tx_blocks_available should never decrease here.
743 */
744 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
745 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300746 }
747
Ido Yariva5225502010-10-12 14:49:10 +0200748 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200749 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200750 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300751
752 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200753 getnstimeofday(&ts);
754 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
755 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300756}
757
Ido Yariva6208652011-03-01 15:14:41 +0200758static void wl1271_flush_deferred_work(struct wl1271 *wl)
759{
760 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200761
Ido Yariva6208652011-03-01 15:14:41 +0200762 /* Pass all received frames to the network stack */
763 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
764 ieee80211_rx_ni(wl->hw, skb);
765
766 /* Return sent skbs to the network stack */
767 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
768 ieee80211_tx_status(wl->hw, skb);
769}
770
771static void wl1271_netstack_work(struct work_struct *work)
772{
773 struct wl1271 *wl =
774 container_of(work, struct wl1271, netstack_work);
775
776 do {
777 wl1271_flush_deferred_work(wl);
778 } while (skb_queue_len(&wl->deferred_rx_queue));
779}
780
781#define WL1271_IRQ_MAX_LOOPS 256
782
783irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300786 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200787 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200788 struct wl1271 *wl = (struct wl1271 *)cookie;
789 bool done = false;
790 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200791 unsigned long flags;
792
793 /* TX might be handled here, avoid redundant work */
794 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
795 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300796
Ido Yariv341b7cd2011-03-31 10:07:01 +0200797 /*
798 * In case edge triggered interrupt must be used, we cannot iterate
799 * more than once without introducing race conditions with the hardirq.
800 */
801 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
802 loopcount = 1;
803
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804 mutex_lock(&wl->mutex);
805
806 wl1271_debug(DEBUG_IRQ, "IRQ work");
807
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200808 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300809 goto out;
810
Ido Yariva6208652011-03-01 15:14:41 +0200811 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300812 if (ret < 0)
813 goto out;
814
Ido Yariva6208652011-03-01 15:14:41 +0200815 while (!done && loopcount--) {
816 /*
817 * In order to avoid a race with the hardirq, clear the flag
818 * before acknowledging the chip. Since the mutex is held,
819 * wl1271_ps_elp_wakeup cannot be called concurrently.
820 */
821 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
822 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200823
824 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200825 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200826 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200827 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200828 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200829 continue;
830 }
831
Eliad Pellerccc83b02010-10-27 14:09:57 +0200832 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
833 wl1271_error("watchdog interrupt received! "
834 "starting recovery.");
835 ieee80211_queue_work(wl->hw, &wl->recovery_work);
836
837 /* restarting the chip. ignore any other interrupt. */
838 goto out;
839 }
840
Ido Yariva6208652011-03-01 15:14:41 +0200841 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200842 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
843
Ido Yariv8aad2462011-03-01 15:14:38 +0200844 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200845
Ido Yariva5225502010-10-12 14:49:10 +0200846 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200847 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200848 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200849 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200850 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200851 /*
852 * In order to avoid starvation of the TX path,
853 * call the work function directly.
854 */
855 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200856 } else {
857 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200858 }
859
Ido Yariv8aad2462011-03-01 15:14:38 +0200860 /* check for tx results */
861 if (wl->fw_status->common.tx_results_counter !=
862 (wl->tx_results_count & 0xff))
863 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200864
865 /* Make sure the deferred queues don't get too long */
866 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
867 skb_queue_len(&wl->deferred_rx_queue);
868 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
869 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200870 }
871
872 if (intr & WL1271_ACX_INTR_EVENT_A) {
873 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
874 wl1271_event_handle(wl, 0);
875 }
876
877 if (intr & WL1271_ACX_INTR_EVENT_B) {
878 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
879 wl1271_event_handle(wl, 1);
880 }
881
882 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
883 wl1271_debug(DEBUG_IRQ,
884 "WL1271_ACX_INTR_INIT_COMPLETE");
885
886 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
887 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888 }
889
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890 wl1271_ps_elp_sleep(wl);
891
892out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200893 spin_lock_irqsave(&wl->wl_lock, flags);
894 /* In case TX was not handled here, queue TX work */
895 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
896 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
897 wl->tx_queue_count)
898 ieee80211_queue_work(wl->hw, &wl->tx_work);
899 spin_unlock_irqrestore(&wl->wl_lock, flags);
900
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200902
903 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300904}
Ido Yariva6208652011-03-01 15:14:41 +0200905EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300906
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300907static int wl1271_fetch_firmware(struct wl1271 *wl)
908{
909 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200910 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911 int ret;
912
Arik Nemtsov166d5042010-10-16 21:44:57 +0200913 switch (wl->bss_type) {
914 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200915 if (wl->chip.id == CHIP_ID_1283_PG20)
916 fw_name = WL128X_AP_FW_NAME;
917 else
918 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200919 break;
920 case BSS_TYPE_IBSS:
921 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200922 if (wl->chip.id == CHIP_ID_1283_PG20)
923 fw_name = WL128X_FW_NAME;
924 else
925 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200926 break;
927 default:
928 wl1271_error("no compatible firmware for bss_type %d",
929 wl->bss_type);
930 return -EINVAL;
931 }
932
933 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
934
935 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936
937 if (ret < 0) {
938 wl1271_error("could not get firmware: %d", ret);
939 return ret;
940 }
941
942 if (fw->size % 4) {
943 wl1271_error("firmware size is not multiple of 32 bits: %zu",
944 fw->size);
945 ret = -EILSEQ;
946 goto out;
947 }
948
Arik Nemtsov166d5042010-10-16 21:44:57 +0200949 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300951 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300952
953 if (!wl->fw) {
954 wl1271_error("could not allocate memory for the firmware");
955 ret = -ENOMEM;
956 goto out;
957 }
958
959 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200960 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300961 ret = 0;
962
963out:
964 release_firmware(fw);
965
966 return ret;
967}
968
969static int wl1271_fetch_nvs(struct wl1271 *wl)
970{
971 const struct firmware *fw;
972 int ret;
973
Shahar Levi5aa42342011-03-06 16:32:07 +0200974 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300975
976 if (ret < 0) {
977 wl1271_error("could not get nvs file: %d", ret);
978 return ret;
979 }
980
Shahar Levibc765bf2011-03-06 16:32:10 +0200981 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300982
983 if (!wl->nvs) {
984 wl1271_error("could not allocate memory for the nvs file");
985 ret = -ENOMEM;
986 goto out;
987 }
988
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200989 wl->nvs_len = fw->size;
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991out:
992 release_firmware(fw);
993
994 return ret;
995}
996
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200997static void wl1271_recovery_work(struct work_struct *work)
998{
999 struct wl1271 *wl =
1000 container_of(work, struct wl1271, recovery_work);
1001
1002 mutex_lock(&wl->mutex);
1003
1004 if (wl->state != WL1271_STATE_ON)
1005 goto out;
1006
1007 wl1271_info("Hardware recovery in progress.");
1008
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001009 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1010 ieee80211_connection_loss(wl->vif);
1011
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001012 /* reboot the chipset */
1013 __wl1271_op_remove_interface(wl);
1014 ieee80211_restart_hw(wl->hw);
1015
1016out:
1017 mutex_unlock(&wl->mutex);
1018}
1019
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001020static void wl1271_fw_wakeup(struct wl1271 *wl)
1021{
1022 u32 elp_reg;
1023
1024 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001025 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026}
1027
1028static int wl1271_setup(struct wl1271 *wl)
1029{
1030 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1031 if (!wl->fw_status)
1032 return -ENOMEM;
1033
1034 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1035 if (!wl->tx_res_if) {
1036 kfree(wl->fw_status);
1037 return -ENOMEM;
1038 }
1039
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040 return 0;
1041}
1042
1043static int wl1271_chip_wakeup(struct wl1271 *wl)
1044{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001045 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046 int ret = 0;
1047
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001048 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001049 ret = wl1271_power_on(wl);
1050 if (ret < 0)
1051 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001053 wl1271_io_reset(wl);
1054 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 /* We don't need a real memory partition here, because we only want
1057 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001058 memset(&partition, 0, sizeof(partition));
1059 partition.reg.start = REGISTERS_BASE;
1060 partition.reg.size = REGISTERS_DOWN_SIZE;
1061 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001062
1063 /* ELP module wake up */
1064 wl1271_fw_wakeup(wl);
1065
1066 /* whal_FwCtrl_BootSm() */
1067
1068 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001069 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001070
1071 /* 1. check if chip id is valid */
1072
1073 switch (wl->chip.id) {
1074 case CHIP_ID_1271_PG10:
1075 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1076 wl->chip.id);
1077
1078 ret = wl1271_setup(wl);
1079 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001080 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 break;
1082 case CHIP_ID_1271_PG20:
1083 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1084 wl->chip.id);
1085
Shahar Levi564f5952011-04-04 10:20:39 +03001086 /* end-of-transaction flag should be set in wl127x AP mode */
1087 if (wl->bss_type == BSS_TYPE_AP_BSS)
1088 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 ret = wl1271_setup(wl);
1091 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001092 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001093 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001094 case CHIP_ID_1283_PG20:
1095 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1096 wl->chip.id);
1097
1098 ret = wl1271_setup(wl);
1099 if (ret < 0)
1100 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001101 if (wl1271_set_block_size(wl))
1102 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001103 break;
1104 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001106 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001108 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 }
1110
Arik Nemtsov166d5042010-10-16 21:44:57 +02001111 /* Make sure the firmware type matches the BSS type */
1112 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 ret = wl1271_fetch_firmware(wl);
1114 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001115 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001116 }
1117
1118 /* No NVS from netlink, try to get it from the filesystem */
1119 if (wl->nvs == NULL) {
1120 ret = wl1271_fetch_nvs(wl);
1121 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001122 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 }
1124
1125out:
1126 return ret;
1127}
1128
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001129static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1130{
1131 unsigned int quirks = 0;
1132 unsigned int *fw_ver = wl->chip.fw_ver;
1133
1134 /* Only for wl127x */
1135 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1136 /* Check STA version */
1137 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1138 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1139 /* Check AP version */
1140 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1141 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1142 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1143
1144 return quirks;
1145}
1146
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001147int wl1271_plt_start(struct wl1271 *wl)
1148{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001149 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001150 int ret;
1151
1152 mutex_lock(&wl->mutex);
1153
1154 wl1271_notice("power up");
1155
1156 if (wl->state != WL1271_STATE_OFF) {
1157 wl1271_error("cannot go into PLT state because not "
1158 "in off state: %d", wl->state);
1159 ret = -EBUSY;
1160 goto out;
1161 }
1162
Arik Nemtsov166d5042010-10-16 21:44:57 +02001163 wl->bss_type = BSS_TYPE_STA_BSS;
1164
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001165 while (retries) {
1166 retries--;
1167 ret = wl1271_chip_wakeup(wl);
1168 if (ret < 0)
1169 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001171 ret = wl1271_boot(wl);
1172 if (ret < 0)
1173 goto power_off;
1174
1175 ret = wl1271_plt_init(wl);
1176 if (ret < 0)
1177 goto irq_disable;
1178
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001179 wl->state = WL1271_STATE_PLT;
1180 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001181 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001182
1183 /* Check if any quirks are needed with older fw versions */
1184 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001185 goto out;
1186
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001187irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001188 mutex_unlock(&wl->mutex);
1189 /* Unlocking the mutex in the middle of handling is
1190 inherently unsafe. In this case we deem it safe to do,
1191 because we need to let any possibly pending IRQ out of
1192 the system (and while we are WL1271_STATE_OFF the IRQ
1193 work function will not do anything.) Also, any other
1194 possible concurrent operations will fail due to the
1195 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001196 wl1271_disable_interrupts(wl);
1197 wl1271_flush_deferred_work(wl);
1198 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001199 mutex_lock(&wl->mutex);
1200power_off:
1201 wl1271_power_off(wl);
1202 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001204 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1205 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206out:
1207 mutex_unlock(&wl->mutex);
1208
1209 return ret;
1210}
1211
Luciano Coelho4623ec72011-03-21 19:26:41 +02001212static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001213{
1214 int ret = 0;
1215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216 wl1271_notice("power down");
1217
1218 if (wl->state != WL1271_STATE_PLT) {
1219 wl1271_error("cannot power down because not in PLT "
1220 "state: %d", wl->state);
1221 ret = -EBUSY;
1222 goto out;
1223 }
1224
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225 wl1271_power_off(wl);
1226
1227 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001228 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001230 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001231 wl1271_disable_interrupts(wl);
1232 wl1271_flush_deferred_work(wl);
1233 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001234 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001235 mutex_lock(&wl->mutex);
1236out:
1237 return ret;
1238}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001239
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001240int wl1271_plt_stop(struct wl1271 *wl)
1241{
1242 int ret;
1243
1244 mutex_lock(&wl->mutex);
1245 ret = __wl1271_plt_stop(wl);
1246 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247 return ret;
1248}
1249
Johannes Berg7bb45682011-02-24 14:42:06 +01001250static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251{
1252 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001253 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001254 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001255 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
Ido Yarivb07d4032011-03-01 15:14:43 +02001257 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1258
1259 if (wl->bss_type == BSS_TYPE_AP_BSS)
1260 hlid = wl1271_tx_get_hlid(skb);
1261
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001262 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001263
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001264 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001265
1266 /*
1267 * The workqueue is slow to process the tx_queue and we need stop
1268 * the queue here, otherwise the queue will get too long.
1269 */
1270 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1271 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1272 ieee80211_stop_queues(wl->hw);
1273 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1274 }
1275
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001276 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001277 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001278 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1279 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1280 } else {
1281 skb_queue_tail(&wl->tx_queue[q], skb);
1282 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
1284 /*
1285 * The chip specific setup must run before the first TX packet -
1286 * before that, the tx_work will not be initialized!
1287 */
1288
Ido Yarivb07d4032011-03-01 15:14:43 +02001289 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1290 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001291 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001292
1293 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294}
1295
Shahar Leviae47c452011-03-06 16:32:14 +02001296int wl1271_tx_dummy_packet(struct wl1271 *wl)
1297{
Ido Yariv990f5de2011-03-31 10:06:59 +02001298 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001299
Ido Yariv990f5de2011-03-31 10:06:59 +02001300 spin_lock_irqsave(&wl->wl_lock, flags);
1301 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1302 wl->tx_queue_count++;
1303 spin_unlock_irqrestore(&wl->wl_lock, flags);
1304
1305 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1306 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1307 wl1271_tx_work_locked(wl);
1308
1309 /*
1310 * If the FW TX is busy, TX work will be scheduled by the threaded
1311 * interrupt handler function
1312 */
1313 return 0;
1314}
1315
1316/*
1317 * The size of the dummy packet should be at least 1400 bytes. However, in
1318 * order to minimize the number of bus transactions, aligning it to 512 bytes
1319 * boundaries could be beneficial, performance wise
1320 */
1321#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1322
Luciano Coelhocf27d862011-04-01 21:08:23 +03001323static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001324{
1325 struct sk_buff *skb;
1326 struct ieee80211_hdr_3addr *hdr;
1327 unsigned int dummy_packet_size;
1328
1329 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1330 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1331
1332 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001333 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001334 wl1271_warning("Failed to allocate a dummy packet skb");
1335 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001336 }
1337
1338 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1339
1340 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1341 memset(hdr, 0, sizeof(*hdr));
1342 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001343 IEEE80211_STYPE_NULLFUNC |
1344 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001345
Ido Yariv990f5de2011-03-31 10:06:59 +02001346 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001347
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001348 /* Dummy packets require the TID to be management */
1349 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001350
1351 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001352 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001353 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001354
Ido Yariv990f5de2011-03-31 10:06:59 +02001355 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001356}
1357
Ido Yariv990f5de2011-03-31 10:06:59 +02001358
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001359static struct notifier_block wl1271_dev_notifier = {
1360 .notifier_call = wl1271_dev_notify,
1361};
1362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363static int wl1271_op_start(struct ieee80211_hw *hw)
1364{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001365 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1366
1367 /*
1368 * We have to delay the booting of the hardware because
1369 * we need to know the local MAC address before downloading and
1370 * initializing the firmware. The MAC address cannot be changed
1371 * after boot, and without the proper MAC address, the firmware
1372 * will not function properly.
1373 *
1374 * The MAC address is first known when the corresponding interface
1375 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001376 *
1377 * In addition, we currently have different firmwares for AP and managed
1378 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001379 */
1380
1381 return 0;
1382}
1383
1384static void wl1271_op_stop(struct ieee80211_hw *hw)
1385{
1386 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1387}
1388
1389static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1390 struct ieee80211_vif *vif)
1391{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001393 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001396 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001398 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1399 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
1401 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001402 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001403 wl1271_debug(DEBUG_MAC80211,
1404 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001405 ret = -EBUSY;
1406 goto out;
1407 }
1408
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001409 /*
1410 * in some very corner case HW recovery scenarios its possible to
1411 * get here before __wl1271_op_remove_interface is complete, so
1412 * opt out if that is the case.
1413 */
1414 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1415 ret = -EBUSY;
1416 goto out;
1417 }
1418
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001419 switch (vif->type) {
1420 case NL80211_IFTYPE_STATION:
1421 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001422 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001423 break;
1424 case NL80211_IFTYPE_ADHOC:
1425 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001426 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001427 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001428 case NL80211_IFTYPE_AP:
1429 wl->bss_type = BSS_TYPE_AP_BSS;
1430 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001431 default:
1432 ret = -EOPNOTSUPP;
1433 goto out;
1434 }
1435
1436 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437
1438 if (wl->state != WL1271_STATE_OFF) {
1439 wl1271_error("cannot start because not in off state: %d",
1440 wl->state);
1441 ret = -EBUSY;
1442 goto out;
1443 }
1444
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001445 while (retries) {
1446 retries--;
1447 ret = wl1271_chip_wakeup(wl);
1448 if (ret < 0)
1449 goto power_off;
1450
1451 ret = wl1271_boot(wl);
1452 if (ret < 0)
1453 goto power_off;
1454
1455 ret = wl1271_hw_init(wl);
1456 if (ret < 0)
1457 goto irq_disable;
1458
Eliad Peller71125ab2010-10-28 21:46:43 +02001459 booted = true;
1460 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001462irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001463 mutex_unlock(&wl->mutex);
1464 /* Unlocking the mutex in the middle of handling is
1465 inherently unsafe. In this case we deem it safe to do,
1466 because we need to let any possibly pending IRQ out of
1467 the system (and while we are WL1271_STATE_OFF the IRQ
1468 work function will not do anything.) Also, any other
1469 possible concurrent operations will fail due to the
1470 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001471 wl1271_disable_interrupts(wl);
1472 wl1271_flush_deferred_work(wl);
1473 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001474 mutex_lock(&wl->mutex);
1475power_off:
1476 wl1271_power_off(wl);
1477 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001478
Eliad Peller71125ab2010-10-28 21:46:43 +02001479 if (!booted) {
1480 wl1271_error("firmware boot failed despite %d retries",
1481 WL1271_BOOT_RETRIES);
1482 goto out;
1483 }
1484
1485 wl->vif = vif;
1486 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001487 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001488 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001489
1490 /* update hw/fw version info in wiphy struct */
1491 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001492 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001493 sizeof(wiphy->fw_version));
1494
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001495 /* Check if any quirks are needed with older fw versions */
1496 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1497
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001498 /*
1499 * Now we know if 11a is supported (info from the NVS), so disable
1500 * 11a channels if not supported
1501 */
1502 if (!wl->enable_11a)
1503 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1504
1505 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1506 wl->enable_11a ? "" : "not ");
1507
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001508out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001509 mutex_unlock(&wl->mutex);
1510
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001511 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001512 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001513 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001514 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001515
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 return ret;
1517}
1518
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001519static void __wl1271_op_remove_interface(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001520{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521 int i;
1522
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001523 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001525 /* because of hardware recovery, we may get here twice */
1526 if (wl->state != WL1271_STATE_ON)
1527 return;
1528
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001529 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001531 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001532 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001533 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001534
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001535 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001536 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001537 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001538
Luciano Coelho08688d62010-07-08 17:50:07 +03001539 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001540 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001541 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001542 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001543 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 }
1545
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001546 /*
1547 * this must be before the cancel_work calls below, so that the work
1548 * functions don't perform further work.
1549 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001550 wl->state = WL1271_STATE_OFF;
1551
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 mutex_unlock(&wl->mutex);
1553
Ido Yariva6208652011-03-01 15:14:41 +02001554 wl1271_disable_interrupts(wl);
1555 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001556 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001557 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001559 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001560 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001561
1562 mutex_lock(&wl->mutex);
1563
1564 /* let's notify MAC80211 about the remaining pending TX frames */
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001565 wl1271_tx_reset(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 wl1271_power_off(wl);
1567
1568 memset(wl->bssid, 0, ETH_ALEN);
1569 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1570 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001572 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001573 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
1575 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001576 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001577 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1578 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001579 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001580 wl->tx_results_count = 0;
1581 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001582 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001583 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001584 wl->time_offset = 0;
1585 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001586 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001587 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001588 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001589 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001590 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001591 wl->ap_fw_ps_map = 0;
1592 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001593
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001594 /*
1595 * this is performed after the cancel_work calls and the associated
1596 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1597 * get executed before all these vars have been reset.
1598 */
1599 wl->flags = 0;
1600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001601 for (i = 0; i < NUM_TX_QUEUES; i++)
1602 wl->tx_blocks_freed[i] = 0;
1603
1604 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001605
1606 kfree(wl->fw_status);
1607 wl->fw_status = NULL;
1608 kfree(wl->tx_res_if);
1609 wl->tx_res_if = NULL;
1610 kfree(wl->target_mem_map);
1611 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001612}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001613
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001614static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1615 struct ieee80211_vif *vif)
1616{
1617 struct wl1271 *wl = hw->priv;
1618
1619 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001620 /*
1621 * wl->vif can be null here if someone shuts down the interface
1622 * just when hardware recovery has been started.
1623 */
1624 if (wl->vif) {
1625 WARN_ON(wl->vif != vif);
1626 __wl1271_op_remove_interface(wl);
1627 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001628
Juuso Oikarinen67353292010-11-18 15:19:02 +02001629 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001630 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001631}
1632
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001633void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001634{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001635 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001636
1637 /* combine requested filters with current filter config */
1638 filters = wl->filters | filters;
1639
1640 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1641
1642 if (filters & FIF_PROMISC_IN_BSS) {
1643 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1644 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1645 wl->rx_config |= CFG_BSSID_FILTER_EN;
1646 }
1647 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1648 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1649 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1650 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1651 }
1652 if (filters & FIF_OTHER_BSS) {
1653 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1654 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1655 }
1656 if (filters & FIF_CONTROL) {
1657 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1658 wl->rx_filter |= CFG_RX_CTL_EN;
1659 }
1660 if (filters & FIF_FCSFAIL) {
1661 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1662 wl->rx_filter |= CFG_RX_FCS_ERROR;
1663 }
1664}
1665
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001666static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001667{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001668 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001669 /* we need to use a dummy BSSID for now */
1670 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1671 0xad, 0xbe, 0xef };
1672
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001673 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1674
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001675 /* pass through frames from all BSS */
1676 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1677
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001678 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001679 if (ret < 0)
1680 goto out;
1681
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001682 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001683
1684out:
1685 return ret;
1686}
1687
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001688static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001689{
1690 int ret;
1691
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001692 /*
1693 * One of the side effects of the JOIN command is that is clears
1694 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1695 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001696 * Currently the only valid scenario for JOIN during association
1697 * is on roaming, in which case we will also be given new keys.
1698 * Keep the below message for now, unless it starts bothering
1699 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001700 */
1701 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1702 wl1271_info("JOIN while associated.");
1703
1704 if (set_assoc)
1705 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1706
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001707 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1708 if (ret < 0)
1709 goto out;
1710
1711 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1712
1713 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1714 goto out;
1715
1716 /*
1717 * The join command disable the keep-alive mode, shut down its process,
1718 * and also clear the template config, so we need to reset it all after
1719 * the join. The acx_aid starts the keep-alive process, and the order
1720 * of the commands below is relevant.
1721 */
1722 ret = wl1271_acx_keep_alive_mode(wl, true);
1723 if (ret < 0)
1724 goto out;
1725
1726 ret = wl1271_acx_aid(wl, wl->aid);
1727 if (ret < 0)
1728 goto out;
1729
1730 ret = wl1271_cmd_build_klv_null_data(wl);
1731 if (ret < 0)
1732 goto out;
1733
1734 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1735 ACX_KEEP_ALIVE_TPL_VALID);
1736 if (ret < 0)
1737 goto out;
1738
1739out:
1740 return ret;
1741}
1742
1743static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001744{
1745 int ret;
1746
1747 /* to stop listening to a channel, we disconnect */
1748 ret = wl1271_cmd_disconnect(wl);
1749 if (ret < 0)
1750 goto out;
1751
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001752 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001753 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001754
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001755 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001756 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001757
1758out:
1759 return ret;
1760}
1761
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001762static void wl1271_set_band_rate(struct wl1271 *wl)
1763{
1764 if (wl->band == IEEE80211_BAND_2GHZ)
1765 wl->basic_rate_set = wl->conf.tx.basic_rate;
1766 else
1767 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1768}
1769
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001770static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001771{
1772 int ret;
1773
1774 if (idle) {
1775 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1776 ret = wl1271_unjoin(wl);
1777 if (ret < 0)
1778 goto out;
1779 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001780 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001781 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001782 if (ret < 0)
1783 goto out;
1784 ret = wl1271_acx_keep_alive_config(
1785 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1786 ACX_KEEP_ALIVE_TPL_INVALID);
1787 if (ret < 0)
1788 goto out;
1789 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1790 } else {
1791 /* increment the session counter */
1792 wl->session_counter++;
1793 if (wl->session_counter >= SESSION_COUNTER_MAX)
1794 wl->session_counter = 0;
1795 ret = wl1271_dummy_join(wl);
1796 if (ret < 0)
1797 goto out;
1798 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1799 }
1800
1801out:
1802 return ret;
1803}
1804
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1806{
1807 struct wl1271 *wl = hw->priv;
1808 struct ieee80211_conf *conf = &hw->conf;
1809 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001810 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811
1812 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1813
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001814 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1815 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001816 channel,
1817 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001818 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001819 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1820 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001822 /*
1823 * mac80211 will go to idle nearly immediately after transmitting some
1824 * frames, such as the deauth. To make sure those frames reach the air,
1825 * wait here until the TX queue is fully flushed.
1826 */
1827 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1828 (conf->flags & IEEE80211_CONF_IDLE))
1829 wl1271_tx_flush(wl);
1830
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001831 mutex_lock(&wl->mutex);
1832
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001833 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001834 /* we support configuring the channel and band while off */
1835 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1836 wl->band = conf->channel->band;
1837 wl->channel = channel;
1838 }
1839
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001840 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001841 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001842
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001843 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1844
Ido Yariva6208652011-03-01 15:14:41 +02001845 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001846 if (ret < 0)
1847 goto out;
1848
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001849 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001850 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1851 ((wl->band != conf->channel->band) ||
1852 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001853 wl->band = conf->channel->band;
1854 wl->channel = channel;
1855
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001856 if (!is_ap) {
1857 /*
1858 * FIXME: the mac80211 should really provide a fixed
1859 * rate to use here. for now, just use the smallest
1860 * possible rate for the band as a fixed rate for
1861 * association frames and other control messages.
1862 */
1863 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1864 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001865
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001866 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1867 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001868 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001869 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001870 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001871
1872 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1873 ret = wl1271_join(wl, false);
1874 if (ret < 0)
1875 wl1271_warning("cmd join on channel "
1876 "failed %d", ret);
1877 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001878 }
1879 }
1880
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001881 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1882 ret = wl1271_sta_handle_idle(wl,
1883 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001884 if (ret < 0)
1885 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001886 }
1887
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001888 /*
1889 * if mac80211 changes the PSM mode, make sure the mode is not
1890 * incorrectly changed after the pspoll failure active window.
1891 */
1892 if (changed & IEEE80211_CONF_CHANGE_PS)
1893 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1894
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001895 if (conf->flags & IEEE80211_CONF_PS &&
1896 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1897 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001898
1899 /*
1900 * We enter PSM only if we're already associated.
1901 * If we're not, we'll enter it when joining an SSID,
1902 * through the bss_info_changed() hook.
1903 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001904 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001905 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001906 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001907 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001908 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001909 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001910 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001911 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001912
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001913 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001915 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001916 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001917 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001918 }
1919
1920 if (conf->power_level != wl->power_level) {
1921 ret = wl1271_acx_tx_power(wl, conf->power_level);
1922 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001923 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001924
1925 wl->power_level = conf->power_level;
1926 }
1927
1928out_sleep:
1929 wl1271_ps_elp_sleep(wl);
1930
1931out:
1932 mutex_unlock(&wl->mutex);
1933
1934 return ret;
1935}
1936
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001937struct wl1271_filter_params {
1938 bool enabled;
1939 int mc_list_length;
1940 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1941};
1942
Jiri Pirko22bedad32010-04-01 21:22:57 +00001943static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1944 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001945{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001946 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001947 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001948 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001949
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001950 if (unlikely(wl->state == WL1271_STATE_OFF))
1951 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001952
Juuso Oikarinen74441132009-10-13 12:47:53 +03001953 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001954 if (!fp) {
1955 wl1271_error("Out of memory setting filters.");
1956 return 0;
1957 }
1958
1959 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001960 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001961 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1962 fp->enabled = false;
1963 } else {
1964 fp->enabled = true;
1965 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001966 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001967 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001968 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001969 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001970 }
1971
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001972 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001973}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001975#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1976 FIF_ALLMULTI | \
1977 FIF_FCSFAIL | \
1978 FIF_BCN_PRBRESP_PROMISC | \
1979 FIF_CONTROL | \
1980 FIF_OTHER_BSS)
1981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1983 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001984 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001986 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001987 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001988 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
Arik Nemtsov7d057862010-10-16 19:25:35 +02001990 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1991 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001993 mutex_lock(&wl->mutex);
1994
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001995 *total &= WL1271_SUPPORTED_FILTERS;
1996 changed &= WL1271_SUPPORTED_FILTERS;
1997
1998 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001999 goto out;
2000
Ido Yariva6208652011-03-01 15:14:41 +02002001 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002002 if (ret < 0)
2003 goto out;
2004
Arik Nemtsov7d057862010-10-16 19:25:35 +02002005 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2006 if (*total & FIF_ALLMULTI)
2007 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2008 else if (fp)
2009 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2010 fp->mc_list,
2011 fp->mc_list_length);
2012 if (ret < 0)
2013 goto out_sleep;
2014 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002015
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002016 /* determine, whether supported filter values have changed */
2017 if (changed == 0)
2018 goto out_sleep;
2019
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002020 /* configure filters */
2021 wl->filters = *total;
2022 wl1271_configure_filters(wl, 0);
2023
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002024 /* apply configured filters */
2025 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2026 if (ret < 0)
2027 goto out_sleep;
2028
2029out_sleep:
2030 wl1271_ps_elp_sleep(wl);
2031
2032out:
2033 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002034 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002035}
2036
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002037static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2038 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2039 u16 tx_seq_16)
2040{
2041 struct wl1271_ap_key *ap_key;
2042 int i;
2043
2044 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2045
2046 if (key_size > MAX_KEY_SIZE)
2047 return -EINVAL;
2048
2049 /*
2050 * Find next free entry in ap_keys. Also check we are not replacing
2051 * an existing key.
2052 */
2053 for (i = 0; i < MAX_NUM_KEYS; i++) {
2054 if (wl->recorded_ap_keys[i] == NULL)
2055 break;
2056
2057 if (wl->recorded_ap_keys[i]->id == id) {
2058 wl1271_warning("trying to record key replacement");
2059 return -EINVAL;
2060 }
2061 }
2062
2063 if (i == MAX_NUM_KEYS)
2064 return -EBUSY;
2065
2066 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2067 if (!ap_key)
2068 return -ENOMEM;
2069
2070 ap_key->id = id;
2071 ap_key->key_type = key_type;
2072 ap_key->key_size = key_size;
2073 memcpy(ap_key->key, key, key_size);
2074 ap_key->hlid = hlid;
2075 ap_key->tx_seq_32 = tx_seq_32;
2076 ap_key->tx_seq_16 = tx_seq_16;
2077
2078 wl->recorded_ap_keys[i] = ap_key;
2079 return 0;
2080}
2081
2082static void wl1271_free_ap_keys(struct wl1271 *wl)
2083{
2084 int i;
2085
2086 for (i = 0; i < MAX_NUM_KEYS; i++) {
2087 kfree(wl->recorded_ap_keys[i]);
2088 wl->recorded_ap_keys[i] = NULL;
2089 }
2090}
2091
2092static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2093{
2094 int i, ret = 0;
2095 struct wl1271_ap_key *key;
2096 bool wep_key_added = false;
2097
2098 for (i = 0; i < MAX_NUM_KEYS; i++) {
2099 if (wl->recorded_ap_keys[i] == NULL)
2100 break;
2101
2102 key = wl->recorded_ap_keys[i];
2103 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2104 key->id, key->key_type,
2105 key->key_size, key->key,
2106 key->hlid, key->tx_seq_32,
2107 key->tx_seq_16);
2108 if (ret < 0)
2109 goto out;
2110
2111 if (key->key_type == KEY_WEP)
2112 wep_key_added = true;
2113 }
2114
2115 if (wep_key_added) {
2116 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2117 if (ret < 0)
2118 goto out;
2119 }
2120
2121out:
2122 wl1271_free_ap_keys(wl);
2123 return ret;
2124}
2125
2126static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2127 u8 key_size, const u8 *key, u32 tx_seq_32,
2128 u16 tx_seq_16, struct ieee80211_sta *sta)
2129{
2130 int ret;
2131 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2132
2133 if (is_ap) {
2134 struct wl1271_station *wl_sta;
2135 u8 hlid;
2136
2137 if (sta) {
2138 wl_sta = (struct wl1271_station *)sta->drv_priv;
2139 hlid = wl_sta->hlid;
2140 } else {
2141 hlid = WL1271_AP_BROADCAST_HLID;
2142 }
2143
2144 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2145 /*
2146 * We do not support removing keys after AP shutdown.
2147 * Pretend we do to make mac80211 happy.
2148 */
2149 if (action != KEY_ADD_OR_REPLACE)
2150 return 0;
2151
2152 ret = wl1271_record_ap_key(wl, id,
2153 key_type, key_size,
2154 key, hlid, tx_seq_32,
2155 tx_seq_16);
2156 } else {
2157 ret = wl1271_cmd_set_ap_key(wl, action,
2158 id, key_type, key_size,
2159 key, hlid, tx_seq_32,
2160 tx_seq_16);
2161 }
2162
2163 if (ret < 0)
2164 return ret;
2165 } else {
2166 const u8 *addr;
2167 static const u8 bcast_addr[ETH_ALEN] = {
2168 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2169 };
2170
2171 addr = sta ? sta->addr : bcast_addr;
2172
2173 if (is_zero_ether_addr(addr)) {
2174 /* We dont support TX only encryption */
2175 return -EOPNOTSUPP;
2176 }
2177
2178 /* The wl1271 does not allow to remove unicast keys - they
2179 will be cleared automatically on next CMD_JOIN. Ignore the
2180 request silently, as we dont want the mac80211 to emit
2181 an error message. */
2182 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2183 return 0;
2184
2185 ret = wl1271_cmd_set_sta_key(wl, action,
2186 id, key_type, key_size,
2187 key, addr, tx_seq_32,
2188 tx_seq_16);
2189 if (ret < 0)
2190 return ret;
2191
2192 /* the default WEP key needs to be configured at least once */
2193 if (key_type == KEY_WEP) {
2194 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2195 wl->default_key);
2196 if (ret < 0)
2197 return ret;
2198 }
2199 }
2200
2201 return 0;
2202}
2203
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2205 struct ieee80211_vif *vif,
2206 struct ieee80211_sta *sta,
2207 struct ieee80211_key_conf *key_conf)
2208{
2209 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002211 u32 tx_seq_32 = 0;
2212 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002213 u8 key_type;
2214
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002215 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2216
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002217 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002218 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002219 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220 key_conf->keylen, key_conf->flags);
2221 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2222
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223 mutex_lock(&wl->mutex);
2224
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002225 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2226 ret = -EAGAIN;
2227 goto out_unlock;
2228 }
2229
Ido Yariva6208652011-03-01 15:14:41 +02002230 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 if (ret < 0)
2232 goto out_unlock;
2233
Johannes Berg97359d12010-08-10 09:46:38 +02002234 switch (key_conf->cipher) {
2235 case WLAN_CIPHER_SUITE_WEP40:
2236 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002237 key_type = KEY_WEP;
2238
2239 key_conf->hw_key_idx = key_conf->keyidx;
2240 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002241 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002242 key_type = KEY_TKIP;
2243
2244 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002245 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2246 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002248 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002249 key_type = KEY_AES;
2250
2251 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002252 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2253 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002254 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002255 case WL1271_CIPHER_SUITE_GEM:
2256 key_type = KEY_GEM;
2257 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2258 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2259 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002260 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002261 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002262
2263 ret = -EOPNOTSUPP;
2264 goto out_sleep;
2265 }
2266
2267 switch (cmd) {
2268 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002269 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2270 key_conf->keyidx, key_type,
2271 key_conf->keylen, key_conf->key,
2272 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002273 if (ret < 0) {
2274 wl1271_error("Could not add or replace key");
2275 goto out_sleep;
2276 }
2277 break;
2278
2279 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002280 ret = wl1271_set_key(wl, KEY_REMOVE,
2281 key_conf->keyidx, key_type,
2282 key_conf->keylen, key_conf->key,
2283 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284 if (ret < 0) {
2285 wl1271_error("Could not remove key");
2286 goto out_sleep;
2287 }
2288 break;
2289
2290 default:
2291 wl1271_error("Unsupported key cmd 0x%x", cmd);
2292 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293 break;
2294 }
2295
2296out_sleep:
2297 wl1271_ps_elp_sleep(wl);
2298
2299out_unlock:
2300 mutex_unlock(&wl->mutex);
2301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302 return ret;
2303}
2304
2305static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002306 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002307 struct cfg80211_scan_request *req)
2308{
2309 struct wl1271 *wl = hw->priv;
2310 int ret;
2311 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002312 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002313
2314 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2315
2316 if (req->n_ssids) {
2317 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002318 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002319 }
2320
2321 mutex_lock(&wl->mutex);
2322
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002323 if (wl->state == WL1271_STATE_OFF) {
2324 /*
2325 * We cannot return -EBUSY here because cfg80211 will expect
2326 * a call to ieee80211_scan_completed if we do - in this case
2327 * there won't be any call.
2328 */
2329 ret = -EAGAIN;
2330 goto out;
2331 }
2332
Ido Yariva6208652011-03-01 15:14:41 +02002333 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002334 if (ret < 0)
2335 goto out;
2336
Luciano Coelho5924f892010-08-04 03:46:22 +03002337 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338
2339 wl1271_ps_elp_sleep(wl);
2340
2341out:
2342 mutex_unlock(&wl->mutex);
2343
2344 return ret;
2345}
2346
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002347static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2348{
2349 struct wl1271 *wl = hw->priv;
2350 int ret = 0;
2351
2352 mutex_lock(&wl->mutex);
2353
2354 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2355 ret = -EAGAIN;
2356 goto out;
2357 }
2358
Ido Yariva6208652011-03-01 15:14:41 +02002359 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002360 if (ret < 0)
2361 goto out;
2362
2363 ret = wl1271_acx_frag_threshold(wl, (u16)value);
2364 if (ret < 0)
2365 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2366
2367 wl1271_ps_elp_sleep(wl);
2368
2369out:
2370 mutex_unlock(&wl->mutex);
2371
2372 return ret;
2373}
2374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002375static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2376{
2377 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002378 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379
2380 mutex_lock(&wl->mutex);
2381
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002382 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2383 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002384 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002385 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002386
Ido Yariva6208652011-03-01 15:14:41 +02002387 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 if (ret < 0)
2389 goto out;
2390
2391 ret = wl1271_acx_rts_threshold(wl, (u16) value);
2392 if (ret < 0)
2393 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2394
2395 wl1271_ps_elp_sleep(wl);
2396
2397out:
2398 mutex_unlock(&wl->mutex);
2399
2400 return ret;
2401}
2402
Arik Nemtsove78a2872010-10-16 19:07:21 +02002403static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002404 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002405{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002406 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002407
2408 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002409 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002410 if (ptr[0] == WLAN_EID_SSID) {
2411 wl->ssid_len = ptr[1];
2412 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002413 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002414 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002415 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002416 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002417
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002418 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002419 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002420}
2421
Arik Nemtsove78a2872010-10-16 19:07:21 +02002422static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2423 struct ieee80211_bss_conf *bss_conf,
2424 u32 changed)
2425{
2426 int ret = 0;
2427
2428 if (changed & BSS_CHANGED_ERP_SLOT) {
2429 if (bss_conf->use_short_slot)
2430 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2431 else
2432 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2433 if (ret < 0) {
2434 wl1271_warning("Set slot time failed %d", ret);
2435 goto out;
2436 }
2437 }
2438
2439 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2440 if (bss_conf->use_short_preamble)
2441 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2442 else
2443 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2444 }
2445
2446 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2447 if (bss_conf->use_cts_prot)
2448 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2449 else
2450 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2451 if (ret < 0) {
2452 wl1271_warning("Set ctsprotect failed %d", ret);
2453 goto out;
2454 }
2455 }
2456
2457out:
2458 return ret;
2459}
2460
2461static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2462 struct ieee80211_vif *vif,
2463 struct ieee80211_bss_conf *bss_conf,
2464 u32 changed)
2465{
2466 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2467 int ret = 0;
2468
2469 if ((changed & BSS_CHANGED_BEACON_INT)) {
2470 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2471 bss_conf->beacon_int);
2472
2473 wl->beacon_int = bss_conf->beacon_int;
2474 }
2475
2476 if ((changed & BSS_CHANGED_BEACON)) {
2477 struct ieee80211_hdr *hdr;
2478 int ieoffset = offsetof(struct ieee80211_mgmt,
2479 u.beacon.variable);
2480 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2481 u16 tmpl_id;
2482
2483 if (!beacon)
2484 goto out;
2485
2486 wl1271_debug(DEBUG_MASTER, "beacon updated");
2487
2488 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2489 if (ret < 0) {
2490 dev_kfree_skb(beacon);
2491 goto out;
2492 }
2493 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2494 CMD_TEMPL_BEACON;
2495 ret = wl1271_cmd_template_set(wl, tmpl_id,
2496 beacon->data,
2497 beacon->len, 0,
2498 wl1271_tx_min_rate_get(wl));
2499 if (ret < 0) {
2500 dev_kfree_skb(beacon);
2501 goto out;
2502 }
2503
2504 hdr = (struct ieee80211_hdr *) beacon->data;
2505 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2506 IEEE80211_STYPE_PROBE_RESP);
2507
2508 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2509 CMD_TEMPL_PROBE_RESPONSE;
2510 ret = wl1271_cmd_template_set(wl,
2511 tmpl_id,
2512 beacon->data,
2513 beacon->len, 0,
2514 wl1271_tx_min_rate_get(wl));
2515 dev_kfree_skb(beacon);
2516 if (ret < 0)
2517 goto out;
2518 }
2519
2520out:
2521 return ret;
2522}
2523
2524/* AP mode changes */
2525static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002526 struct ieee80211_vif *vif,
2527 struct ieee80211_bss_conf *bss_conf,
2528 u32 changed)
2529{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002530 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002531
Arik Nemtsove78a2872010-10-16 19:07:21 +02002532 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2533 u32 rates = bss_conf->basic_rates;
2534 struct conf_tx_rate_class mgmt_rc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002535
Arik Nemtsove78a2872010-10-16 19:07:21 +02002536 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2537 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2538 wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
2539 wl->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540
Arik Nemtsove78a2872010-10-16 19:07:21 +02002541 /* update the AP management rate policy with the new rates */
2542 mgmt_rc.enabled_rates = wl->basic_rate_set;
2543 mgmt_rc.long_retry_limit = 10;
2544 mgmt_rc.short_retry_limit = 10;
2545 mgmt_rc.aflags = 0;
2546 ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
2547 ACX_TX_AP_MODE_MGMT_RATE);
2548 if (ret < 0) {
2549 wl1271_error("AP mgmt policy change failed %d", ret);
2550 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002551 }
2552 }
2553
Arik Nemtsove78a2872010-10-16 19:07:21 +02002554 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2555 if (ret < 0)
2556 goto out;
2557
2558 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2559 if (bss_conf->enable_beacon) {
2560 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2561 ret = wl1271_cmd_start_bss(wl);
2562 if (ret < 0)
2563 goto out;
2564
2565 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2566 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002567
2568 ret = wl1271_ap_init_hwenc(wl);
2569 if (ret < 0)
2570 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002571 }
2572 } else {
2573 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2574 ret = wl1271_cmd_stop_bss(wl);
2575 if (ret < 0)
2576 goto out;
2577
2578 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2579 wl1271_debug(DEBUG_AP, "stopped AP");
2580 }
2581 }
2582 }
2583
Eliad Pellercb5ae052011-04-07 15:52:05 +03002584 if (changed & BSS_CHANGED_IBSS) {
2585 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2586 bss_conf->ibss_joined);
2587
2588 if (bss_conf->ibss_joined) {
2589 u32 rates = bss_conf->basic_rates;
2590 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2591 rates);
2592 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2593
2594 /* by default, use 11b rates */
2595 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2596 ret = wl1271_acx_sta_rate_policies(wl);
2597 if (ret < 0)
2598 goto out;
2599 }
2600 }
2601
Arik Nemtsove78a2872010-10-16 19:07:21 +02002602 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2603 if (ret < 0)
2604 goto out;
2605out:
2606 return;
2607}
2608
2609/* STA/IBSS mode changes */
2610static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2611 struct ieee80211_vif *vif,
2612 struct ieee80211_bss_conf *bss_conf,
2613 u32 changed)
2614{
2615 bool do_join = false, set_assoc = false;
2616 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002617 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002618 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002619 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002620 bool sta_exists = false;
2621 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002622
2623 if (is_ibss) {
2624 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2625 changed);
2626 if (ret < 0)
2627 goto out;
2628 }
2629
2630 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2631 do_join = true;
2632
2633 /* Need to update the SSID (for filtering etc) */
2634 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2635 do_join = true;
2636
2637 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002638 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2639 bss_conf->enable_beacon ? "enabled" : "disabled");
2640
2641 if (bss_conf->enable_beacon)
2642 wl->set_bss_type = BSS_TYPE_IBSS;
2643 else
2644 wl->set_bss_type = BSS_TYPE_STA_BSS;
2645 do_join = true;
2646 }
2647
Arik Nemtsove78a2872010-10-16 19:07:21 +02002648 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002649 bool enable = false;
2650 if (bss_conf->cqm_rssi_thold)
2651 enable = true;
2652 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2653 bss_conf->cqm_rssi_thold,
2654 bss_conf->cqm_rssi_hyst);
2655 if (ret < 0)
2656 goto out;
2657 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2658 }
2659
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002660 if ((changed & BSS_CHANGED_BSSID) &&
2661 /*
2662 * Now we know the correct bssid, so we send a new join command
2663 * and enable the BSSID filter
2664 */
2665 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002666 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002667
Eliad Pellerfa287b82010-12-26 09:27:50 +01002668 if (!is_zero_ether_addr(wl->bssid)) {
2669 ret = wl1271_cmd_build_null_data(wl);
2670 if (ret < 0)
2671 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002672
Eliad Pellerfa287b82010-12-26 09:27:50 +01002673 ret = wl1271_build_qos_null_data(wl);
2674 if (ret < 0)
2675 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002676
Eliad Pellerfa287b82010-12-26 09:27:50 +01002677 /* filter out all packets not from this BSSID */
2678 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002679
Eliad Pellerfa287b82010-12-26 09:27:50 +01002680 /* Need to update the BSSID (for filtering etc) */
2681 do_join = true;
2682 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002683 }
2684
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002685 rcu_read_lock();
2686 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2687 if (sta) {
2688 /* save the supp_rates of the ap */
2689 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2690 if (sta->ht_cap.ht_supported)
2691 sta_rate_set |=
2692 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002693 sta_ht_cap = sta->ht_cap;
2694 sta_exists = true;
2695 }
2696 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002697
Arik Nemtsova1008852011-02-12 23:24:20 +02002698 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002699 /* handle new association with HT and HT information change */
2700 if ((changed & BSS_CHANGED_HT) &&
2701 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002702 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002703 true);
2704 if (ret < 0) {
2705 wl1271_warning("Set ht cap true failed %d",
2706 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002707 goto out;
2708 }
2709 ret = wl1271_acx_set_ht_information(wl,
2710 bss_conf->ht_operation_mode);
2711 if (ret < 0) {
2712 wl1271_warning("Set ht information failed %d",
2713 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002714 goto out;
2715 }
2716 }
2717 /* handle new association without HT and disassociation */
2718 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002719 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002720 false);
2721 if (ret < 0) {
2722 wl1271_warning("Set ht cap false failed %d",
2723 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002724 goto out;
2725 }
2726 }
2727 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002728
Arik Nemtsove78a2872010-10-16 19:07:21 +02002729 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002731 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002732 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002733 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002734 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002736 wl->ps_poll_failures = 0;
2737
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002738 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002739 * use basic rates from AP, and determine lowest rate
2740 * to use with control frames.
2741 */
2742 rates = bss_conf->basic_rates;
2743 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2744 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002745 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002746 if (sta_rate_set)
2747 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2748 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002749 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002750 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002751 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002752
2753 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002754 * with wl1271, we don't need to update the
2755 * beacon_int and dtim_period, because the firmware
2756 * updates it by itself when the first beacon is
2757 * received after a join.
2758 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002759 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2760 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002761 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002762
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002763 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002764 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002765 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002766 dev_kfree_skb(wl->probereq);
2767 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2768 ieoffset = offsetof(struct ieee80211_mgmt,
2769 u.probe_req.variable);
2770 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002771
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002772 /* enable the connection monitoring feature */
2773 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002774 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002775 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002776
2777 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002778 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2779 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002780 enum wl1271_cmd_ps_mode mode;
2781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002782 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002783 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002784 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002785 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002786 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002787 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002788 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002789 } else {
2790 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002791 bool was_assoc =
2792 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2793 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002794 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002795 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002796
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002797 /* free probe-request template */
2798 dev_kfree_skb(wl->probereq);
2799 wl->probereq = NULL;
2800
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002801 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002802 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002803
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002804 /* revert back to minimum rates for the current band */
2805 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002806 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002807 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002808 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002809 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002810
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002811 /* disable connection monitor features */
2812 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002813
2814 /* Disable the keep-alive feature */
2815 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002816 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002817 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002818
2819 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002820 if (was_assoc) {
2821 wl1271_unjoin(wl);
2822 wl1271_dummy_join(wl);
2823 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824 }
2825 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002826
Arik Nemtsove78a2872010-10-16 19:07:21 +02002827 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2828 if (ret < 0)
2829 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002830
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002831 if (changed & BSS_CHANGED_ARP_FILTER) {
2832 __be32 addr = bss_conf->arp_addr_list[0];
2833 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2834
Eliad Pellerc5312772010-12-09 11:31:27 +02002835 if (bss_conf->arp_addr_cnt == 1 &&
2836 bss_conf->arp_filter_enabled) {
2837 /*
2838 * The template should have been configured only upon
2839 * association. however, it seems that the correct ip
2840 * isn't being set (when sending), so we have to
2841 * reconfigure the template upon every ip change.
2842 */
2843 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2844 if (ret < 0) {
2845 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002846 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002847 }
2848
2849 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002850 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002851 addr);
2852 } else
2853 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002854
2855 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002856 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002857 }
2858
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002859 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002860 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002861 if (ret < 0) {
2862 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002863 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002864 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002865 }
2866
Arik Nemtsove78a2872010-10-16 19:07:21 +02002867out:
2868 return;
2869}
2870
2871static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2872 struct ieee80211_vif *vif,
2873 struct ieee80211_bss_conf *bss_conf,
2874 u32 changed)
2875{
2876 struct wl1271 *wl = hw->priv;
2877 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2878 int ret;
2879
2880 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2881 (int)changed);
2882
2883 mutex_lock(&wl->mutex);
2884
2885 if (unlikely(wl->state == WL1271_STATE_OFF))
2886 goto out;
2887
Ido Yariva6208652011-03-01 15:14:41 +02002888 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002889 if (ret < 0)
2890 goto out;
2891
2892 if (is_ap)
2893 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2894 else
2895 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897 wl1271_ps_elp_sleep(wl);
2898
2899out:
2900 mutex_unlock(&wl->mutex);
2901}
2902
Kalle Valoc6999d82010-02-18 13:25:41 +02002903static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2904 const struct ieee80211_tx_queue_params *params)
2905{
2906 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002907 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002908 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002909
2910 mutex_lock(&wl->mutex);
2911
2912 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2913
Kalle Valo4695dc92010-03-18 12:26:38 +02002914 if (params->uapsd)
2915 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2916 else
2917 ps_scheme = CONF_PS_SCHEME_LEGACY;
2918
Arik Nemtsov488fc542010-10-16 20:33:45 +02002919 if (wl->state == WL1271_STATE_OFF) {
2920 /*
2921 * If the state is off, the parameters will be recorded and
2922 * configured on init. This happens in AP-mode.
2923 */
2924 struct conf_tx_ac_category *conf_ac =
2925 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2926 struct conf_tx_tid *conf_tid =
2927 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2928
2929 conf_ac->ac = wl1271_tx_get_queue(queue);
2930 conf_ac->cw_min = (u8)params->cw_min;
2931 conf_ac->cw_max = params->cw_max;
2932 conf_ac->aifsn = params->aifs;
2933 conf_ac->tx_op_limit = params->txop << 5;
2934
2935 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2936 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2937 conf_tid->tsid = wl1271_tx_get_queue(queue);
2938 conf_tid->ps_scheme = ps_scheme;
2939 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2940 conf_tid->apsd_conf[0] = 0;
2941 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002942 goto out;
2943 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002944
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002945 ret = wl1271_ps_elp_wakeup(wl);
2946 if (ret < 0)
2947 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002948
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002949 /*
2950 * the txop is confed in units of 32us by the mac80211,
2951 * we need us
2952 */
2953 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2954 params->cw_min, params->cw_max,
2955 params->aifs, params->txop << 5);
2956 if (ret < 0)
2957 goto out_sleep;
2958
2959 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2960 CONF_CHANNEL_TYPE_EDCF,
2961 wl1271_tx_get_queue(queue),
2962 ps_scheme, CONF_ACK_POLICY_LEGACY,
2963 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002964
2965out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002966 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002967
2968out:
2969 mutex_unlock(&wl->mutex);
2970
2971 return ret;
2972}
2973
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002974static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2975{
2976
2977 struct wl1271 *wl = hw->priv;
2978 u64 mactime = ULLONG_MAX;
2979 int ret;
2980
2981 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2982
2983 mutex_lock(&wl->mutex);
2984
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002985 if (unlikely(wl->state == WL1271_STATE_OFF))
2986 goto out;
2987
Ido Yariva6208652011-03-01 15:14:41 +02002988 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002989 if (ret < 0)
2990 goto out;
2991
2992 ret = wl1271_acx_tsf_info(wl, &mactime);
2993 if (ret < 0)
2994 goto out_sleep;
2995
2996out_sleep:
2997 wl1271_ps_elp_sleep(wl);
2998
2999out:
3000 mutex_unlock(&wl->mutex);
3001 return mactime;
3002}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003
John W. Linvilleece550d2010-07-28 16:41:06 -04003004static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3005 struct survey_info *survey)
3006{
3007 struct wl1271 *wl = hw->priv;
3008 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003009
John W. Linvilleece550d2010-07-28 16:41:06 -04003010 if (idx != 0)
3011 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003012
John W. Linvilleece550d2010-07-28 16:41:06 -04003013 survey->channel = conf->channel;
3014 survey->filled = SURVEY_INFO_NOISE_DBM;
3015 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003016
John W. Linvilleece550d2010-07-28 16:41:06 -04003017 return 0;
3018}
3019
Arik Nemtsov409622e2011-02-23 00:22:29 +02003020static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003021 struct ieee80211_sta *sta,
3022 u8 *hlid)
3023{
3024 struct wl1271_station *wl_sta;
3025 int id;
3026
3027 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3028 if (id >= AP_MAX_STATIONS) {
3029 wl1271_warning("could not allocate HLID - too much stations");
3030 return -EBUSY;
3031 }
3032
3033 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003034 __set_bit(id, wl->ap_hlid_map);
3035 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3036 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003037 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003038 return 0;
3039}
3040
Arik Nemtsov409622e2011-02-23 00:22:29 +02003041static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003042{
3043 int id = hlid - WL1271_AP_STA_HLID_START;
3044
Arik Nemtsov409622e2011-02-23 00:22:29 +02003045 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3046 return;
3047
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003048 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003049 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003050 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003051 __clear_bit(hlid, &wl->ap_ps_map);
3052 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003053}
3054
Arik Nemtsov47684802011-04-26 23:21:51 +03003055bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3056{
3057 int id = hlid - WL1271_AP_STA_HLID_START;
3058 return test_bit(id, wl->ap_hlid_map);
3059}
3060
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003061static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3062 struct ieee80211_vif *vif,
3063 struct ieee80211_sta *sta)
3064{
3065 struct wl1271 *wl = hw->priv;
3066 int ret = 0;
3067 u8 hlid;
3068
3069 mutex_lock(&wl->mutex);
3070
3071 if (unlikely(wl->state == WL1271_STATE_OFF))
3072 goto out;
3073
3074 if (wl->bss_type != BSS_TYPE_AP_BSS)
3075 goto out;
3076
3077 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3078
Arik Nemtsov409622e2011-02-23 00:22:29 +02003079 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003080 if (ret < 0)
3081 goto out;
3082
Ido Yariva6208652011-03-01 15:14:41 +02003083 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003084 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003085 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003086
3087 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3088 if (ret < 0)
3089 goto out_sleep;
3090
3091out_sleep:
3092 wl1271_ps_elp_sleep(wl);
3093
Arik Nemtsov409622e2011-02-23 00:22:29 +02003094out_free_sta:
3095 if (ret < 0)
3096 wl1271_free_sta(wl, hlid);
3097
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003098out:
3099 mutex_unlock(&wl->mutex);
3100 return ret;
3101}
3102
3103static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3104 struct ieee80211_vif *vif,
3105 struct ieee80211_sta *sta)
3106{
3107 struct wl1271 *wl = hw->priv;
3108 struct wl1271_station *wl_sta;
3109 int ret = 0, id;
3110
3111 mutex_lock(&wl->mutex);
3112
3113 if (unlikely(wl->state == WL1271_STATE_OFF))
3114 goto out;
3115
3116 if (wl->bss_type != BSS_TYPE_AP_BSS)
3117 goto out;
3118
3119 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3120
3121 wl_sta = (struct wl1271_station *)sta->drv_priv;
3122 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3123 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3124 goto out;
3125
Ido Yariva6208652011-03-01 15:14:41 +02003126 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003127 if (ret < 0)
3128 goto out;
3129
3130 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3131 if (ret < 0)
3132 goto out_sleep;
3133
Arik Nemtsov409622e2011-02-23 00:22:29 +02003134 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003135
3136out_sleep:
3137 wl1271_ps_elp_sleep(wl);
3138
3139out:
3140 mutex_unlock(&wl->mutex);
3141 return ret;
3142}
3143
Luciano Coelho4623ec72011-03-21 19:26:41 +02003144static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3145 struct ieee80211_vif *vif,
3146 enum ieee80211_ampdu_mlme_action action,
3147 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3148 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003149{
3150 struct wl1271 *wl = hw->priv;
3151 int ret;
3152
3153 mutex_lock(&wl->mutex);
3154
3155 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3156 ret = -EAGAIN;
3157 goto out;
3158 }
3159
Ido Yariva6208652011-03-01 15:14:41 +02003160 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003161 if (ret < 0)
3162 goto out;
3163
3164 switch (action) {
3165 case IEEE80211_AMPDU_RX_START:
3166 if (wl->ba_support) {
3167 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3168 true);
3169 if (!ret)
3170 wl->ba_rx_bitmap |= BIT(tid);
3171 } else {
3172 ret = -ENOTSUPP;
3173 }
3174 break;
3175
3176 case IEEE80211_AMPDU_RX_STOP:
3177 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3178 if (!ret)
3179 wl->ba_rx_bitmap &= ~BIT(tid);
3180 break;
3181
3182 /*
3183 * The BA initiator session management in FW independently.
3184 * Falling break here on purpose for all TX APDU commands.
3185 */
3186 case IEEE80211_AMPDU_TX_START:
3187 case IEEE80211_AMPDU_TX_STOP:
3188 case IEEE80211_AMPDU_TX_OPERATIONAL:
3189 ret = -EINVAL;
3190 break;
3191
3192 default:
3193 wl1271_error("Incorrect ampdu action id=%x\n", action);
3194 ret = -EINVAL;
3195 }
3196
3197 wl1271_ps_elp_sleep(wl);
3198
3199out:
3200 mutex_unlock(&wl->mutex);
3201
3202 return ret;
3203}
3204
Arik Nemtsov33437892011-04-26 23:35:39 +03003205static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3206{
3207 struct wl1271 *wl = hw->priv;
3208 bool ret = false;
3209
3210 mutex_lock(&wl->mutex);
3211
3212 if (unlikely(wl->state == WL1271_STATE_OFF))
3213 goto out;
3214
3215 /* packets are considered pending if in the TX queue or the FW */
3216 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3217
3218 /* the above is appropriate for STA mode for PS purposes */
3219 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3220
3221out:
3222 mutex_unlock(&wl->mutex);
3223
3224 return ret;
3225}
3226
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003227/* can't be const, mac80211 writes to this */
3228static struct ieee80211_rate wl1271_rates[] = {
3229 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003230 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3231 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003233 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3234 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3236 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003237 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3238 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003239 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3240 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003241 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3242 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003243 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3244 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003245 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3246 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003247 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003248 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3249 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003250 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003251 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3252 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003253 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003254 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3255 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003256 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003257 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3258 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003259 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003260 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3261 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003262 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003263 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3264 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003266 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3267 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268};
3269
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003270/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003271static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003272 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003273 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003274 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3275 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3276 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003277 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003278 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3279 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3280 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003281 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003282 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3283 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3284 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003285 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003286};
3287
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003288/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003289static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003290 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003291 7, /* CONF_HW_RXTX_RATE_MCS7 */
3292 6, /* CONF_HW_RXTX_RATE_MCS6 */
3293 5, /* CONF_HW_RXTX_RATE_MCS5 */
3294 4, /* CONF_HW_RXTX_RATE_MCS4 */
3295 3, /* CONF_HW_RXTX_RATE_MCS3 */
3296 2, /* CONF_HW_RXTX_RATE_MCS2 */
3297 1, /* CONF_HW_RXTX_RATE_MCS1 */
3298 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003299
3300 11, /* CONF_HW_RXTX_RATE_54 */
3301 10, /* CONF_HW_RXTX_RATE_48 */
3302 9, /* CONF_HW_RXTX_RATE_36 */
3303 8, /* CONF_HW_RXTX_RATE_24 */
3304
3305 /* TI-specific rate */
3306 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3307
3308 7, /* CONF_HW_RXTX_RATE_18 */
3309 6, /* CONF_HW_RXTX_RATE_12 */
3310 3, /* CONF_HW_RXTX_RATE_11 */
3311 5, /* CONF_HW_RXTX_RATE_9 */
3312 4, /* CONF_HW_RXTX_RATE_6 */
3313 2, /* CONF_HW_RXTX_RATE_5_5 */
3314 1, /* CONF_HW_RXTX_RATE_2 */
3315 0 /* CONF_HW_RXTX_RATE_1 */
3316};
3317
Shahar Levie8b03a22010-10-13 16:09:39 +02003318/* 11n STA capabilities */
3319#define HW_RX_HIGHEST_RATE 72
3320
Shahar Levi00d20102010-11-08 11:20:10 +00003321#ifdef CONFIG_WL12XX_HT
3322#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003323 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3324 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003325 .ht_supported = true, \
3326 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3327 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3328 .mcs = { \
3329 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3330 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3331 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3332 }, \
3333}
Shahar Levi18357852010-10-13 16:09:41 +02003334#else
Shahar Levi00d20102010-11-08 11:20:10 +00003335#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003336 .ht_supported = false, \
3337}
3338#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003339
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340/* can't be const, mac80211 writes to this */
3341static struct ieee80211_supported_band wl1271_band_2ghz = {
3342 .channels = wl1271_channels,
3343 .n_channels = ARRAY_SIZE(wl1271_channels),
3344 .bitrates = wl1271_rates,
3345 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003346 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003347};
3348
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003349/* 5 GHz data rates for WL1273 */
3350static struct ieee80211_rate wl1271_rates_5ghz[] = {
3351 { .bitrate = 60,
3352 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3353 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3354 { .bitrate = 90,
3355 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3356 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3357 { .bitrate = 120,
3358 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3359 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3360 { .bitrate = 180,
3361 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3362 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3363 { .bitrate = 240,
3364 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3365 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3366 { .bitrate = 360,
3367 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3368 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3369 { .bitrate = 480,
3370 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3371 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3372 { .bitrate = 540,
3373 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3374 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3375};
3376
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003377/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003378static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003379 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003380 { .hw_value = 8, .center_freq = 5040},
3381 { .hw_value = 9, .center_freq = 5045},
3382 { .hw_value = 11, .center_freq = 5055},
3383 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003384 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003385 { .hw_value = 34, .center_freq = 5170},
3386 { .hw_value = 36, .center_freq = 5180},
3387 { .hw_value = 38, .center_freq = 5190},
3388 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003389 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003390 { .hw_value = 44, .center_freq = 5220},
3391 { .hw_value = 46, .center_freq = 5230},
3392 { .hw_value = 48, .center_freq = 5240},
3393 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003394 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003395 { .hw_value = 60, .center_freq = 5300},
3396 { .hw_value = 64, .center_freq = 5320},
3397 { .hw_value = 100, .center_freq = 5500},
3398 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003399 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003400 { .hw_value = 112, .center_freq = 5560},
3401 { .hw_value = 116, .center_freq = 5580},
3402 { .hw_value = 120, .center_freq = 5600},
3403 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003404 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003405 { .hw_value = 132, .center_freq = 5660},
3406 { .hw_value = 136, .center_freq = 5680},
3407 { .hw_value = 140, .center_freq = 5700},
3408 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003409 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003410 { .hw_value = 157, .center_freq = 5785},
3411 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003412 { .hw_value = 165, .center_freq = 5825},
3413};
3414
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003415/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003416static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003417 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003418 7, /* CONF_HW_RXTX_RATE_MCS7 */
3419 6, /* CONF_HW_RXTX_RATE_MCS6 */
3420 5, /* CONF_HW_RXTX_RATE_MCS5 */
3421 4, /* CONF_HW_RXTX_RATE_MCS4 */
3422 3, /* CONF_HW_RXTX_RATE_MCS3 */
3423 2, /* CONF_HW_RXTX_RATE_MCS2 */
3424 1, /* CONF_HW_RXTX_RATE_MCS1 */
3425 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003426
3427 7, /* CONF_HW_RXTX_RATE_54 */
3428 6, /* CONF_HW_RXTX_RATE_48 */
3429 5, /* CONF_HW_RXTX_RATE_36 */
3430 4, /* CONF_HW_RXTX_RATE_24 */
3431
3432 /* TI-specific rate */
3433 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3434
3435 3, /* CONF_HW_RXTX_RATE_18 */
3436 2, /* CONF_HW_RXTX_RATE_12 */
3437 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3438 1, /* CONF_HW_RXTX_RATE_9 */
3439 0, /* CONF_HW_RXTX_RATE_6 */
3440 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3441 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3442 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3443};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003444
3445static struct ieee80211_supported_band wl1271_band_5ghz = {
3446 .channels = wl1271_channels_5ghz,
3447 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3448 .bitrates = wl1271_rates_5ghz,
3449 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003450 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003451};
3452
Tobias Klausera0ea9492010-05-20 10:38:11 +02003453static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003454 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3455 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3456};
3457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003458static const struct ieee80211_ops wl1271_ops = {
3459 .start = wl1271_op_start,
3460 .stop = wl1271_op_stop,
3461 .add_interface = wl1271_op_add_interface,
3462 .remove_interface = wl1271_op_remove_interface,
3463 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003464 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003465 .configure_filter = wl1271_op_configure_filter,
3466 .tx = wl1271_op_tx,
3467 .set_key = wl1271_op_set_key,
3468 .hw_scan = wl1271_op_hw_scan,
3469 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003470 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003471 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003472 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003473 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003474 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003475 .sta_add = wl1271_op_sta_add,
3476 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003477 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003478 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003479 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003480};
3481
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003482
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003483u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003484{
3485 u8 idx;
3486
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003487 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003488
3489 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3490 wl1271_error("Illegal RX rate from HW: %d", rate);
3491 return 0;
3492 }
3493
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003494 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003495 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3496 wl1271_error("Unsupported RX rate from HW: %d", rate);
3497 return 0;
3498 }
3499
3500 return idx;
3501}
3502
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003503static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3504 struct device_attribute *attr,
3505 char *buf)
3506{
3507 struct wl1271 *wl = dev_get_drvdata(dev);
3508 ssize_t len;
3509
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003510 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003511
3512 mutex_lock(&wl->mutex);
3513 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3514 wl->sg_enabled);
3515 mutex_unlock(&wl->mutex);
3516
3517 return len;
3518
3519}
3520
3521static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3522 struct device_attribute *attr,
3523 const char *buf, size_t count)
3524{
3525 struct wl1271 *wl = dev_get_drvdata(dev);
3526 unsigned long res;
3527 int ret;
3528
Luciano Coelho6277ed62011-04-01 17:49:54 +03003529 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003530 if (ret < 0) {
3531 wl1271_warning("incorrect value written to bt_coex_mode");
3532 return count;
3533 }
3534
3535 mutex_lock(&wl->mutex);
3536
3537 res = !!res;
3538
3539 if (res == wl->sg_enabled)
3540 goto out;
3541
3542 wl->sg_enabled = res;
3543
3544 if (wl->state == WL1271_STATE_OFF)
3545 goto out;
3546
Ido Yariva6208652011-03-01 15:14:41 +02003547 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003548 if (ret < 0)
3549 goto out;
3550
3551 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3552 wl1271_ps_elp_sleep(wl);
3553
3554 out:
3555 mutex_unlock(&wl->mutex);
3556 return count;
3557}
3558
3559static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3560 wl1271_sysfs_show_bt_coex_state,
3561 wl1271_sysfs_store_bt_coex_state);
3562
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003563static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3564 struct device_attribute *attr,
3565 char *buf)
3566{
3567 struct wl1271 *wl = dev_get_drvdata(dev);
3568 ssize_t len;
3569
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003570 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003571
3572 mutex_lock(&wl->mutex);
3573 if (wl->hw_pg_ver >= 0)
3574 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3575 else
3576 len = snprintf(buf, len, "n/a\n");
3577 mutex_unlock(&wl->mutex);
3578
3579 return len;
3580}
3581
3582static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3583 wl1271_sysfs_show_hw_pg_ver, NULL);
3584
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003585int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003586{
3587 int ret;
3588
3589 if (wl->mac80211_registered)
3590 return 0;
3591
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003592 ret = wl1271_fetch_nvs(wl);
3593 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003594 /* NOTE: The wl->nvs->nvs element must be first, in
3595 * order to simplify the casting, we assume it is at
3596 * the beginning of the wl->nvs structure.
3597 */
3598 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003599
3600 wl->mac_addr[0] = nvs_ptr[11];
3601 wl->mac_addr[1] = nvs_ptr[10];
3602 wl->mac_addr[2] = nvs_ptr[6];
3603 wl->mac_addr[3] = nvs_ptr[5];
3604 wl->mac_addr[4] = nvs_ptr[4];
3605 wl->mac_addr[5] = nvs_ptr[3];
3606 }
3607
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003608 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3609
3610 ret = ieee80211_register_hw(wl->hw);
3611 if (ret < 0) {
3612 wl1271_error("unable to register mac80211 hw: %d", ret);
3613 return ret;
3614 }
3615
3616 wl->mac80211_registered = true;
3617
Eliad Pellerd60080a2010-11-24 12:53:16 +02003618 wl1271_debugfs_init(wl);
3619
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003620 register_netdevice_notifier(&wl1271_dev_notifier);
3621
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003622 wl1271_notice("loaded");
3623
3624 return 0;
3625}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003626EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003627
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003628void wl1271_unregister_hw(struct wl1271 *wl)
3629{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003630 if (wl->state == WL1271_STATE_PLT)
3631 __wl1271_plt_stop(wl);
3632
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003633 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003634 ieee80211_unregister_hw(wl->hw);
3635 wl->mac80211_registered = false;
3636
3637}
3638EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3639
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003640int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003641{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003642 static const u32 cipher_suites[] = {
3643 WLAN_CIPHER_SUITE_WEP40,
3644 WLAN_CIPHER_SUITE_WEP104,
3645 WLAN_CIPHER_SUITE_TKIP,
3646 WLAN_CIPHER_SUITE_CCMP,
3647 WL1271_CIPHER_SUITE_GEM,
3648 };
3649
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003650 /* The tx descriptor buffer and the TKIP space. */
3651 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3652 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653
3654 /* unit us */
3655 /* FIXME: find a proper value */
3656 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003657 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003658
3659 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003660 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003661 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003662 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003663 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003664 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003665 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003666 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003668 wl->hw->wiphy->cipher_suites = cipher_suites;
3669 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3670
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003671 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003672 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003673 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003674 /*
3675 * Maximum length of elements in scanning probe request templates
3676 * should be the maximum length possible for a template, without
3677 * the IEEE80211 header of the template
3678 */
3679 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3680 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003681
Luciano Coelho4a31c112011-03-21 23:16:14 +02003682 /* make sure all our channels fit in the scanned_ch bitmask */
3683 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3684 ARRAY_SIZE(wl1271_channels_5ghz) >
3685 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003686 /*
3687 * We keep local copies of the band structs because we need to
3688 * modify them on a per-device basis.
3689 */
3690 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3691 sizeof(wl1271_band_2ghz));
3692 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3693 sizeof(wl1271_band_5ghz));
3694
3695 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3696 &wl->bands[IEEE80211_BAND_2GHZ];
3697 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3698 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003699
Kalle Valo12bd8942010-03-18 12:26:33 +02003700 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003701 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003702
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003703 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3704
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003705 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003707 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3708
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003709 wl->hw->max_rx_aggregation_subframes = 8;
3710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003711 return 0;
3712}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003713EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003714
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003716
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003717struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003718{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003719 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003720 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003721 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003722 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003723 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003724
3725 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3726 if (!hw) {
3727 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003728 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003729 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003730 }
3731
Julia Lawall929ebd32010-05-15 23:16:39 +02003732 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003733 if (!plat_dev) {
3734 wl1271_error("could not allocate platform_device");
3735 ret = -ENOMEM;
3736 goto err_plat_alloc;
3737 }
3738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003739 wl = hw->priv;
3740 memset(wl, 0, sizeof(*wl));
3741
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003742 INIT_LIST_HEAD(&wl->list);
3743
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003744 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003745 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003746
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003747 for (i = 0; i < NUM_TX_QUEUES; i++)
3748 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003749
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003750 for (i = 0; i < NUM_TX_QUEUES; i++)
3751 for (j = 0; j < AP_MAX_LINKS; j++)
3752 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3753
Ido Yariva6208652011-03-01 15:14:41 +02003754 skb_queue_head_init(&wl->deferred_rx_queue);
3755 skb_queue_head_init(&wl->deferred_tx_queue);
3756
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003757 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003758 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003759 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003760 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3761 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3762 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003763 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003764 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003765 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003766 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003767 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3768 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003769 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003770 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003771 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003772 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003773 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003774 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003775 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003776 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003777 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003778 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003779 wl->bss_type = MAX_BSS_TYPE;
3780 wl->set_bss_type = MAX_BSS_TYPE;
3781 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003782 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003783 wl->ap_ps_map = 0;
3784 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003785 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003786 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003787
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003788 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003789 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003790 wl->tx_frames[i] = NULL;
3791
3792 spin_lock_init(&wl->wl_lock);
3793
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003794 wl->state = WL1271_STATE_OFF;
3795 mutex_init(&wl->mutex);
3796
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003797 /* Apply default driver configuration. */
3798 wl1271_conf_init(wl);
3799
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003800 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3801 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3802 if (!wl->aggr_buf) {
3803 ret = -ENOMEM;
3804 goto err_hw;
3805 }
3806
Ido Yariv990f5de2011-03-31 10:06:59 +02003807 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3808 if (!wl->dummy_packet) {
3809 ret = -ENOMEM;
3810 goto err_aggr;
3811 }
3812
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003813 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003814 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003815 if (ret) {
3816 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003817 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003818 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003819 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003820
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003821 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003822 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003823 if (ret < 0) {
3824 wl1271_error("failed to create sysfs file bt_coex_state");
3825 goto err_platform;
3826 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003827
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003828 /* Create sysfs file to get HW PG version */
3829 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3830 if (ret < 0) {
3831 wl1271_error("failed to create sysfs file hw_pg_ver");
3832 goto err_bt_coex_state;
3833 }
3834
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003835 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003836
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003837err_bt_coex_state:
3838 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3839
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003840err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003841 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003842
Ido Yariv990f5de2011-03-31 10:06:59 +02003843err_dummy_packet:
3844 dev_kfree_skb(wl->dummy_packet);
3845
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003846err_aggr:
3847 free_pages((unsigned long)wl->aggr_buf, order);
3848
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003849err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003850 wl1271_debugfs_exit(wl);
3851 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003852
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003853err_plat_alloc:
3854 ieee80211_free_hw(hw);
3855
3856err_hw_alloc:
3857
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003858 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003859}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003860EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003861
3862int wl1271_free_hw(struct wl1271 *wl)
3863{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003864 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003865 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003866 free_pages((unsigned long)wl->aggr_buf,
3867 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003868 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003869
3870 wl1271_debugfs_exit(wl);
3871
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003872 vfree(wl->fw);
3873 wl->fw = NULL;
3874 kfree(wl->nvs);
3875 wl->nvs = NULL;
3876
3877 kfree(wl->fw_status);
3878 kfree(wl->tx_res_if);
3879
3880 ieee80211_free_hw(wl->hw);
3881
3882 return 0;
3883}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003884EXPORT_SYMBOL_GPL(wl1271_free_hw);
3885
Guy Eilam491bbd62011-01-12 10:33:29 +01003886u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003887EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003888module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003889MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3890
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003891MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003892MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003893MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");