blob: 6dd42c9876634221d0bf4921dd1664a0f8ac6e96 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Arik Nemtsov47684802011-04-26 23:21:51 +0300212 .max_tx_retries = 100,
213 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200214 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300215 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200216 [CONF_TX_AC_BE] = {
217 .queue_id = CONF_TX_AC_BE,
218 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300219 .tsid = CONF_TX_AC_BE,
220 .ps_scheme = CONF_PS_SCHEME_LEGACY,
221 .ack_policy = CONF_ACK_POLICY_LEGACY,
222 .apsd_conf = {0, 0},
223 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200224 [CONF_TX_AC_BK] = {
225 .queue_id = CONF_TX_AC_BK,
226 .channel_type = CONF_CHANNEL_TYPE_EDCF,
227 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 .ps_scheme = CONF_PS_SCHEME_LEGACY,
229 .ack_policy = CONF_ACK_POLICY_LEGACY,
230 .apsd_conf = {0, 0},
231 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200232 [CONF_TX_AC_VI] = {
233 .queue_id = CONF_TX_AC_VI,
234 .channel_type = CONF_CHANNEL_TYPE_EDCF,
235 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300236 .ps_scheme = CONF_PS_SCHEME_LEGACY,
237 .ack_policy = CONF_ACK_POLICY_LEGACY,
238 .apsd_conf = {0, 0},
239 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200240 [CONF_TX_AC_VO] = {
241 .queue_id = CONF_TX_AC_VO,
242 .channel_type = CONF_CHANNEL_TYPE_EDCF,
243 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300244 .ps_scheme = CONF_PS_SCHEME_LEGACY,
245 .ack_policy = CONF_ACK_POLICY_LEGACY,
246 .apsd_conf = {0, 0},
247 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300248 },
249 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200250 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300251 .tx_compl_threshold = 4,
252 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
253 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200254 .tmpl_short_retry_limit = 10,
255 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300256 },
257 .conn = {
258 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300259 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300260 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
261 .bcn_filt_ie_count = 1,
262 .bcn_filt_ie = {
263 [0] = {
264 .ie = WLAN_EID_CHANNEL_SWITCH,
265 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
266 }
267 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200268 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300269 .bss_lose_timeout = 100,
270 .beacon_rx_timeout = 10000,
271 .broadcast_timeout = 20000,
272 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300273 .ps_poll_threshold = 10,
274 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300275 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200276 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200277 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300278 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200279 .psm_entry_nullfunc_retries = 3,
280 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300281 .keep_alive_interval = 55000,
282 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300283 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200284 .itrim = {
285 .enable = false,
286 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200287 },
288 .pm_config = {
289 .host_clk_settling_time = 5000,
290 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300291 },
292 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300293 .trigger_pacing = 1,
294 .avg_weight_rssi_beacon = 20,
295 .avg_weight_rssi_data = 10,
296 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200298 },
299 .scan = {
300 .min_dwell_time_active = 7500,
301 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100302 .min_dwell_time_passive = 100000,
303 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200304 .num_probe_reqs = 2,
305 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200306 .rf = {
307 .tx_per_channel_power_compensation_2 = {
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 },
310 .tx_per_channel_power_compensation_5 = {
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 },
315 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100316 .ht = {
317 .tx_ba_win_size = 64,
318 .inactivity_timeout = 10000,
319 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200320 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200321 .num_stations = 1,
322 .ssid_profiles = 1,
323 .rx_block_num = 70,
324 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300325 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200326 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200327 .min_req_rx_blocks = 22,
328 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200329 },
330 .mem_wl128x = {
331 .num_stations = 1,
332 .ssid_profiles = 1,
333 .rx_block_num = 40,
334 .tx_min_block_num = 40,
335 .dynamic_memory = 1,
336 .min_req_tx_blocks = 45,
337 .min_req_rx_blocks = 22,
338 .tx_min = 27,
339 },
Shahar Leviff868432011-04-11 15:41:46 +0300340 .fm_coex = {
341 .enable = true,
342 .swallow_period = 5,
343 .n_divider_fref_set_1 = 0xff, /* default */
344 .n_divider_fref_set_2 = 12,
345 .m_divider_fref_set_1 = 148,
346 .m_divider_fref_set_2 = 0xffff, /* default */
347 .coex_pll_stabilization_time = 0xffffffff, /* default */
348 .ldo_stabilization_time = 0xffff, /* default */
349 .fm_disturbed_band_margin = 0xff, /* default */
350 .swallow_clk_diff = 0xff, /* default */
351 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300352 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300353};
354
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300355static void __wl1271_op_remove_interface(struct wl1271 *wl,
356 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200357static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200358
359
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200360static void wl1271_device_release(struct device *dev)
361{
362
363}
364
365static struct platform_device wl1271_device = {
366 .name = "wl1271",
367 .id = -1,
368
369 /* device model insists to have a release function */
370 .dev = {
371 .release = wl1271_device_release,
372 },
373};
374
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200375static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300376static LIST_HEAD(wl_list);
377
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300378static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
379 void *arg)
380{
381 struct net_device *dev = arg;
382 struct wireless_dev *wdev;
383 struct wiphy *wiphy;
384 struct ieee80211_hw *hw;
385 struct wl1271 *wl;
386 struct wl1271 *wl_temp;
387 int ret = 0;
388
389 /* Check that this notification is for us. */
390 if (what != NETDEV_CHANGE)
391 return NOTIFY_DONE;
392
393 wdev = dev->ieee80211_ptr;
394 if (wdev == NULL)
395 return NOTIFY_DONE;
396
397 wiphy = wdev->wiphy;
398 if (wiphy == NULL)
399 return NOTIFY_DONE;
400
401 hw = wiphy_priv(wiphy);
402 if (hw == NULL)
403 return NOTIFY_DONE;
404
405 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200406 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300407 list_for_each_entry(wl, &wl_list, list) {
408 if (wl == wl_temp)
409 break;
410 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200411 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300412 if (wl != wl_temp)
413 return NOTIFY_DONE;
414
415 mutex_lock(&wl->mutex);
416
417 if (wl->state == WL1271_STATE_OFF)
418 goto out;
419
420 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
421 goto out;
422
Ido Yariva6208652011-03-01 15:14:41 +0200423 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300424 if (ret < 0)
425 goto out;
426
427 if ((dev->operstate == IF_OPER_UP) &&
428 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
429 wl1271_cmd_set_sta_state(wl);
430 wl1271_info("Association completed.");
431 }
432
433 wl1271_ps_elp_sleep(wl);
434
435out:
436 mutex_unlock(&wl->mutex);
437
438 return NOTIFY_OK;
439}
440
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100441static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200442 struct regulatory_request *request)
443{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100444 struct ieee80211_supported_band *band;
445 struct ieee80211_channel *ch;
446 int i;
447
448 band = wiphy->bands[IEEE80211_BAND_5GHZ];
449 for (i = 0; i < band->n_channels; i++) {
450 ch = &band->channels[i];
451 if (ch->flags & IEEE80211_CHAN_DISABLED)
452 continue;
453
454 if (ch->flags & IEEE80211_CHAN_RADAR)
455 ch->flags |= IEEE80211_CHAN_NO_IBSS |
456 IEEE80211_CHAN_PASSIVE_SCAN;
457
458 }
459
460 return 0;
461}
462
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300463static void wl1271_conf_init(struct wl1271 *wl)
464{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300465
466 /*
467 * This function applies the default configuration to the driver. This
468 * function is invoked upon driver load (spi probe.)
469 *
470 * The configuration is stored in a run-time structure in order to
471 * facilitate for run-time adjustment of any of the parameters. Making
472 * changes to the configuration structure will apply the new values on
473 * the next interface up (wl1271_op_start.)
474 */
475
476 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300477 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300478}
479
480
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300481static int wl1271_plt_init(struct wl1271 *wl)
482{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200483 struct conf_tx_ac_category *conf_ac;
484 struct conf_tx_tid *conf_tid;
485 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300486
Shahar Levi49d750ca2011-03-06 16:32:09 +0200487 if (wl->chip.id == CHIP_ID_1283_PG20)
488 ret = wl128x_cmd_general_parms(wl);
489 else
490 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200491 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200492 return ret;
493
Shahar Levi49d750ca2011-03-06 16:32:09 +0200494 if (wl->chip.id == CHIP_ID_1283_PG20)
495 ret = wl128x_cmd_radio_parms(wl);
496 else
497 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200498 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200499 return ret;
500
Shahar Levi49d750ca2011-03-06 16:32:09 +0200501 if (wl->chip.id != CHIP_ID_1283_PG20) {
502 ret = wl1271_cmd_ext_radio_parms(wl);
503 if (ret < 0)
504 return ret;
505 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200506 if (ret < 0)
507 return ret;
508
Shahar Levi48a61472011-03-06 16:32:08 +0200509 /* Chip-specific initializations */
510 ret = wl1271_chip_specific_init(wl);
511 if (ret < 0)
512 return ret;
513
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200514 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200515 if (ret < 0)
516 return ret;
517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300518 ret = wl1271_acx_init_mem_config(wl);
519 if (ret < 0)
520 return ret;
521
Luciano Coelho12419cc2010-02-18 13:25:44 +0200522 /* PHY layer config */
523 ret = wl1271_init_phy_config(wl);
524 if (ret < 0)
525 goto out_free_memmap;
526
527 ret = wl1271_acx_dco_itrim_params(wl);
528 if (ret < 0)
529 goto out_free_memmap;
530
531 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200532 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200533 if (ret < 0)
534 goto out_free_memmap;
535
536 /* Bluetooth WLAN coexistence */
537 ret = wl1271_init_pta(wl);
538 if (ret < 0)
539 goto out_free_memmap;
540
Shahar Leviff868432011-04-11 15:41:46 +0300541 /* FM WLAN coexistence */
542 ret = wl1271_acx_fm_coex(wl);
543 if (ret < 0)
544 goto out_free_memmap;
545
Luciano Coelho12419cc2010-02-18 13:25:44 +0200546 /* Energy detection */
547 ret = wl1271_init_energy_detection(wl);
548 if (ret < 0)
549 goto out_free_memmap;
550
Gery Kahn1ec610e2011-02-01 03:03:08 -0600551 ret = wl1271_acx_sta_mem_cfg(wl);
552 if (ret < 0)
553 goto out_free_memmap;
554
Luciano Coelho12419cc2010-02-18 13:25:44 +0200555 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100556 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200557 if (ret < 0)
558 goto out_free_memmap;
559
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200560 /* Default TID/AC configuration */
561 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200562 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200563 conf_ac = &wl->conf.tx.ac_conf[i];
564 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
565 conf_ac->cw_max, conf_ac->aifsn,
566 conf_ac->tx_op_limit);
567 if (ret < 0)
568 goto out_free_memmap;
569
Luciano Coelho12419cc2010-02-18 13:25:44 +0200570 conf_tid = &wl->conf.tx.tid_conf[i];
571 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
572 conf_tid->channel_type,
573 conf_tid->tsid,
574 conf_tid->ps_scheme,
575 conf_tid->ack_policy,
576 conf_tid->apsd_conf[0],
577 conf_tid->apsd_conf[1]);
578 if (ret < 0)
579 goto out_free_memmap;
580 }
581
Luciano Coelho12419cc2010-02-18 13:25:44 +0200582 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200583 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300584 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200585 goto out_free_memmap;
586
587 /* Configure for CAM power saving (ie. always active) */
588 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
589 if (ret < 0)
590 goto out_free_memmap;
591
592 /* configure PM */
593 ret = wl1271_acx_pm_config(wl);
594 if (ret < 0)
595 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596
597 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200598
599 out_free_memmap:
600 kfree(wl->target_mem_map);
601 wl->target_mem_map = NULL;
602
603 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300604}
605
Arik Nemtsovb622d992011-02-23 00:22:31 +0200606static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
607{
608 bool fw_ps;
609
610 /* only regulate station links */
611 if (hlid < WL1271_AP_STA_HLID_START)
612 return;
613
614 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
615
616 /*
617 * Wake up from high level PS if the STA is asleep with too little
618 * blocks in FW or if the STA is awake.
619 */
620 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
621 wl1271_ps_link_end(wl, hlid);
622
623 /* Start high-level PS if the STA is asleep with enough blocks in FW */
624 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
625 wl1271_ps_link_start(wl, hlid, true);
626}
627
628static void wl1271_irq_update_links_status(struct wl1271 *wl,
629 struct wl1271_fw_ap_status *status)
630{
631 u32 cur_fw_ps_map;
632 u8 hlid;
633
634 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
635 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
636 wl1271_debug(DEBUG_PSM,
637 "link ps prev 0x%x cur 0x%x changed 0x%x",
638 wl->ap_fw_ps_map, cur_fw_ps_map,
639 wl->ap_fw_ps_map ^ cur_fw_ps_map);
640
641 wl->ap_fw_ps_map = cur_fw_ps_map;
642 }
643
644 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
645 u8 cnt = status->tx_lnk_free_blks[hlid] -
646 wl->links[hlid].prev_freed_blks;
647
648 wl->links[hlid].prev_freed_blks =
649 status->tx_lnk_free_blks[hlid];
650 wl->links[hlid].allocated_blks -= cnt;
651
652 wl1271_irq_ps_regulate_link(wl, hlid,
653 wl->links[hlid].allocated_blks);
654 }
655}
656
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300657static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200658 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200660 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200661 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200662 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200663 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300664 int i;
665
Shahar Levi13b107d2011-03-06 16:32:12 +0200666 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200667 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
668 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200669 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200670 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
671 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200672 }
673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
675 "drv_rx_counter = %d, tx_results_counter = %d)",
676 status->intr,
677 status->fw_rx_counter,
678 status->drv_rx_counter,
679 status->tx_results_counter);
680
681 /* update number of available TX blocks */
682 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200683 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
684 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300685
686 wl->tx_blocks_freed[i] =
687 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200688 }
689
Ido Yarivd2f4d472011-03-31 10:07:00 +0200690 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200691
Ido Yarivd2f4d472011-03-31 10:07:00 +0200692 if (wl->bss_type == BSS_TYPE_AP_BSS) {
693 /* Update num of allocated TX blocks per link and ps status */
694 wl1271_irq_update_links_status(wl, &full_status->ap);
695 wl->tx_blocks_available += freed_blocks;
696 } else {
697 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
698
699 /*
700 * The FW might change the total number of TX memblocks before
701 * we get a notification about blocks being released. Thus, the
702 * available blocks calculation might yield a temporary result
703 * which is lower than the actual available blocks. Keeping in
704 * mind that only blocks that were allocated can be moved from
705 * TX to RX, tx_blocks_available should never decrease here.
706 */
707 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
708 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709 }
710
Ido Yariva5225502010-10-12 14:49:10 +0200711 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200712 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200713 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714
715 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200716 getnstimeofday(&ts);
717 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
718 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300719}
720
Ido Yariva6208652011-03-01 15:14:41 +0200721static void wl1271_flush_deferred_work(struct wl1271 *wl)
722{
723 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200724
Ido Yariva6208652011-03-01 15:14:41 +0200725 /* Pass all received frames to the network stack */
726 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
727 ieee80211_rx_ni(wl->hw, skb);
728
729 /* Return sent skbs to the network stack */
730 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
731 ieee80211_tx_status(wl->hw, skb);
732}
733
734static void wl1271_netstack_work(struct work_struct *work)
735{
736 struct wl1271 *wl =
737 container_of(work, struct wl1271, netstack_work);
738
739 do {
740 wl1271_flush_deferred_work(wl);
741 } while (skb_queue_len(&wl->deferred_rx_queue));
742}
743
744#define WL1271_IRQ_MAX_LOOPS 256
745
746irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300747{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300748 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300749 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200750 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200751 struct wl1271 *wl = (struct wl1271 *)cookie;
752 bool done = false;
753 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200754 unsigned long flags;
755
756 /* TX might be handled here, avoid redundant work */
757 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
758 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759
Ido Yariv341b7cd2011-03-31 10:07:01 +0200760 /*
761 * In case edge triggered interrupt must be used, we cannot iterate
762 * more than once without introducing race conditions with the hardirq.
763 */
764 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
765 loopcount = 1;
766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300767 mutex_lock(&wl->mutex);
768
769 wl1271_debug(DEBUG_IRQ, "IRQ work");
770
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200771 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772 goto out;
773
Ido Yariva6208652011-03-01 15:14:41 +0200774 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775 if (ret < 0)
776 goto out;
777
Ido Yariva6208652011-03-01 15:14:41 +0200778 while (!done && loopcount--) {
779 /*
780 * In order to avoid a race with the hardirq, clear the flag
781 * before acknowledging the chip. Since the mutex is held,
782 * wl1271_ps_elp_wakeup cannot be called concurrently.
783 */
784 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
785 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200786
787 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200788 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200789 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200790 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200791 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200792 continue;
793 }
794
Eliad Pellerccc83b02010-10-27 14:09:57 +0200795 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
796 wl1271_error("watchdog interrupt received! "
797 "starting recovery.");
798 ieee80211_queue_work(wl->hw, &wl->recovery_work);
799
800 /* restarting the chip. ignore any other interrupt. */
801 goto out;
802 }
803
Ido Yariva6208652011-03-01 15:14:41 +0200804 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200805 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
806
Ido Yariv8aad2462011-03-01 15:14:38 +0200807 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200808
Ido Yariva5225502010-10-12 14:49:10 +0200809 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200810 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200811 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200812 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200813 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200814 /*
815 * In order to avoid starvation of the TX path,
816 * call the work function directly.
817 */
818 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200819 } else {
820 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200821 }
822
Ido Yariv8aad2462011-03-01 15:14:38 +0200823 /* check for tx results */
824 if (wl->fw_status->common.tx_results_counter !=
825 (wl->tx_results_count & 0xff))
826 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200827
828 /* Make sure the deferred queues don't get too long */
829 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
830 skb_queue_len(&wl->deferred_rx_queue);
831 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
832 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200833 }
834
835 if (intr & WL1271_ACX_INTR_EVENT_A) {
836 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
837 wl1271_event_handle(wl, 0);
838 }
839
840 if (intr & WL1271_ACX_INTR_EVENT_B) {
841 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
842 wl1271_event_handle(wl, 1);
843 }
844
845 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
846 wl1271_debug(DEBUG_IRQ,
847 "WL1271_ACX_INTR_INIT_COMPLETE");
848
849 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
850 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300851 }
852
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300853 wl1271_ps_elp_sleep(wl);
854
855out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200856 spin_lock_irqsave(&wl->wl_lock, flags);
857 /* In case TX was not handled here, queue TX work */
858 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
859 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
860 wl->tx_queue_count)
861 ieee80211_queue_work(wl->hw, &wl->tx_work);
862 spin_unlock_irqrestore(&wl->wl_lock, flags);
863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200865
866 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867}
Ido Yariva6208652011-03-01 15:14:41 +0200868EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300870static int wl1271_fetch_firmware(struct wl1271 *wl)
871{
872 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200873 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 int ret;
875
Arik Nemtsov166d5042010-10-16 21:44:57 +0200876 switch (wl->bss_type) {
877 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200878 if (wl->chip.id == CHIP_ID_1283_PG20)
879 fw_name = WL128X_AP_FW_NAME;
880 else
881 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200882 break;
883 case BSS_TYPE_IBSS:
884 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200885 if (wl->chip.id == CHIP_ID_1283_PG20)
886 fw_name = WL128X_FW_NAME;
887 else
888 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200889 break;
890 default:
891 wl1271_error("no compatible firmware for bss_type %d",
892 wl->bss_type);
893 return -EINVAL;
894 }
895
896 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
897
898 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899
900 if (ret < 0) {
901 wl1271_error("could not get firmware: %d", ret);
902 return ret;
903 }
904
905 if (fw->size % 4) {
906 wl1271_error("firmware size is not multiple of 32 bits: %zu",
907 fw->size);
908 ret = -EILSEQ;
909 goto out;
910 }
911
Arik Nemtsov166d5042010-10-16 21:44:57 +0200912 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300913 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300914 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300915
916 if (!wl->fw) {
917 wl1271_error("could not allocate memory for the firmware");
918 ret = -ENOMEM;
919 goto out;
920 }
921
922 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200923 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300924 ret = 0;
925
926out:
927 release_firmware(fw);
928
929 return ret;
930}
931
932static int wl1271_fetch_nvs(struct wl1271 *wl)
933{
934 const struct firmware *fw;
935 int ret;
936
Shahar Levi5aa42342011-03-06 16:32:07 +0200937 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300938
939 if (ret < 0) {
940 wl1271_error("could not get nvs file: %d", ret);
941 return ret;
942 }
943
Shahar Levibc765bf2011-03-06 16:32:10 +0200944 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300945
946 if (!wl->nvs) {
947 wl1271_error("could not allocate memory for the nvs file");
948 ret = -ENOMEM;
949 goto out;
950 }
951
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200952 wl->nvs_len = fw->size;
953
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300954out:
955 release_firmware(fw);
956
957 return ret;
958}
959
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200960static void wl1271_recovery_work(struct work_struct *work)
961{
962 struct wl1271 *wl =
963 container_of(work, struct wl1271, recovery_work);
964
965 mutex_lock(&wl->mutex);
966
967 if (wl->state != WL1271_STATE_ON)
968 goto out;
969
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300970 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
971 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200972
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200973 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
974 ieee80211_connection_loss(wl->vif);
975
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300976 /* Prevent spurious TX during FW restart */
977 ieee80211_stop_queues(wl->hw);
978
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200979 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300980 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200981 ieee80211_restart_hw(wl->hw);
982
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300983 /*
984 * Its safe to enable TX now - the queues are stopped after a request
985 * to restart the HW.
986 */
987 ieee80211_wake_queues(wl->hw);
988
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200989out:
990 mutex_unlock(&wl->mutex);
991}
992
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993static void wl1271_fw_wakeup(struct wl1271 *wl)
994{
995 u32 elp_reg;
996
997 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +0300998 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999}
1000
1001static int wl1271_setup(struct wl1271 *wl)
1002{
1003 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1004 if (!wl->fw_status)
1005 return -ENOMEM;
1006
1007 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1008 if (!wl->tx_res_if) {
1009 kfree(wl->fw_status);
1010 return -ENOMEM;
1011 }
1012
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 return 0;
1014}
1015
1016static int wl1271_chip_wakeup(struct wl1271 *wl)
1017{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001018 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001019 int ret = 0;
1020
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001021 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001022 ret = wl1271_power_on(wl);
1023 if (ret < 0)
1024 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001026 wl1271_io_reset(wl);
1027 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028
1029 /* We don't need a real memory partition here, because we only want
1030 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001031 memset(&partition, 0, sizeof(partition));
1032 partition.reg.start = REGISTERS_BASE;
1033 partition.reg.size = REGISTERS_DOWN_SIZE;
1034 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001035
1036 /* ELP module wake up */
1037 wl1271_fw_wakeup(wl);
1038
1039 /* whal_FwCtrl_BootSm() */
1040
1041 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001042 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
1044 /* 1. check if chip id is valid */
1045
1046 switch (wl->chip.id) {
1047 case CHIP_ID_1271_PG10:
1048 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1049 wl->chip.id);
1050
1051 ret = wl1271_setup(wl);
1052 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001053 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 break;
1055 case CHIP_ID_1271_PG20:
1056 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1057 wl->chip.id);
1058
Shahar Levi564f5952011-04-04 10:20:39 +03001059 /* end-of-transaction flag should be set in wl127x AP mode */
1060 if (wl->bss_type == BSS_TYPE_AP_BSS)
1061 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063 ret = wl1271_setup(wl);
1064 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001065 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001067 case CHIP_ID_1283_PG20:
1068 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1069 wl->chip.id);
1070
1071 ret = wl1271_setup(wl);
1072 if (ret < 0)
1073 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001074 if (wl1271_set_block_size(wl))
1075 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001076 break;
1077 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001079 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001081 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 }
1083
Arik Nemtsov166d5042010-10-16 21:44:57 +02001084 /* Make sure the firmware type matches the BSS type */
1085 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 ret = wl1271_fetch_firmware(wl);
1087 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001088 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089 }
1090
1091 /* No NVS from netlink, try to get it from the filesystem */
1092 if (wl->nvs == NULL) {
1093 ret = wl1271_fetch_nvs(wl);
1094 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001095 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 }
1097
1098out:
1099 return ret;
1100}
1101
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001102static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1103{
1104 unsigned int quirks = 0;
1105 unsigned int *fw_ver = wl->chip.fw_ver;
1106
1107 /* Only for wl127x */
1108 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1109 /* Check STA version */
1110 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1111 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1112 /* Check AP version */
1113 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1114 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1115 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1116
1117 return quirks;
1118}
1119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120int wl1271_plt_start(struct wl1271 *wl)
1121{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001122 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123 int ret;
1124
1125 mutex_lock(&wl->mutex);
1126
1127 wl1271_notice("power up");
1128
1129 if (wl->state != WL1271_STATE_OFF) {
1130 wl1271_error("cannot go into PLT state because not "
1131 "in off state: %d", wl->state);
1132 ret = -EBUSY;
1133 goto out;
1134 }
1135
Arik Nemtsov166d5042010-10-16 21:44:57 +02001136 wl->bss_type = BSS_TYPE_STA_BSS;
1137
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001138 while (retries) {
1139 retries--;
1140 ret = wl1271_chip_wakeup(wl);
1141 if (ret < 0)
1142 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001144 ret = wl1271_boot(wl);
1145 if (ret < 0)
1146 goto power_off;
1147
1148 ret = wl1271_plt_init(wl);
1149 if (ret < 0)
1150 goto irq_disable;
1151
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001152 wl->state = WL1271_STATE_PLT;
1153 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001154 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001155
1156 /* Check if any quirks are needed with older fw versions */
1157 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001158 goto out;
1159
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001160irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001161 mutex_unlock(&wl->mutex);
1162 /* Unlocking the mutex in the middle of handling is
1163 inherently unsafe. In this case we deem it safe to do,
1164 because we need to let any possibly pending IRQ out of
1165 the system (and while we are WL1271_STATE_OFF the IRQ
1166 work function will not do anything.) Also, any other
1167 possible concurrent operations will fail due to the
1168 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001169 wl1271_disable_interrupts(wl);
1170 wl1271_flush_deferred_work(wl);
1171 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001172 mutex_lock(&wl->mutex);
1173power_off:
1174 wl1271_power_off(wl);
1175 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001177 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1178 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179out:
1180 mutex_unlock(&wl->mutex);
1181
1182 return ret;
1183}
1184
Luciano Coelho4623ec72011-03-21 19:26:41 +02001185static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001186{
1187 int ret = 0;
1188
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 wl1271_notice("power down");
1190
1191 if (wl->state != WL1271_STATE_PLT) {
1192 wl1271_error("cannot power down because not in PLT "
1193 "state: %d", wl->state);
1194 ret = -EBUSY;
1195 goto out;
1196 }
1197
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198 wl1271_power_off(wl);
1199
1200 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001201 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001204 wl1271_disable_interrupts(wl);
1205 wl1271_flush_deferred_work(wl);
1206 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001207 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001208 mutex_lock(&wl->mutex);
1209out:
1210 return ret;
1211}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001212
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001213int wl1271_plt_stop(struct wl1271 *wl)
1214{
1215 int ret;
1216
1217 mutex_lock(&wl->mutex);
1218 ret = __wl1271_plt_stop(wl);
1219 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 return ret;
1221}
1222
Johannes Berg7bb45682011-02-24 14:42:06 +01001223static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224{
1225 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001226 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001227 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001228 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229
Ido Yarivb07d4032011-03-01 15:14:43 +02001230 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1231
1232 if (wl->bss_type == BSS_TYPE_AP_BSS)
1233 hlid = wl1271_tx_get_hlid(skb);
1234
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001235 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001236
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001237 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001238
1239 /*
1240 * The workqueue is slow to process the tx_queue and we need stop
1241 * the queue here, otherwise the queue will get too long.
1242 */
1243 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1244 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1245 ieee80211_stop_queues(wl->hw);
1246 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1247 }
1248
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001249 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001250 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001251 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1252 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1253 } else {
1254 skb_queue_tail(&wl->tx_queue[q], skb);
1255 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
1257 /*
1258 * The chip specific setup must run before the first TX packet -
1259 * before that, the tx_work will not be initialized!
1260 */
1261
Ido Yarivb07d4032011-03-01 15:14:43 +02001262 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1263 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001264 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001265
1266 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001267}
1268
Shahar Leviae47c452011-03-06 16:32:14 +02001269int wl1271_tx_dummy_packet(struct wl1271 *wl)
1270{
Ido Yariv990f5de2011-03-31 10:06:59 +02001271 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001272
Ido Yariv990f5de2011-03-31 10:06:59 +02001273 spin_lock_irqsave(&wl->wl_lock, flags);
1274 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1275 wl->tx_queue_count++;
1276 spin_unlock_irqrestore(&wl->wl_lock, flags);
1277
1278 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1279 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1280 wl1271_tx_work_locked(wl);
1281
1282 /*
1283 * If the FW TX is busy, TX work will be scheduled by the threaded
1284 * interrupt handler function
1285 */
1286 return 0;
1287}
1288
1289/*
1290 * The size of the dummy packet should be at least 1400 bytes. However, in
1291 * order to minimize the number of bus transactions, aligning it to 512 bytes
1292 * boundaries could be beneficial, performance wise
1293 */
1294#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1295
Luciano Coelhocf27d862011-04-01 21:08:23 +03001296static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001297{
1298 struct sk_buff *skb;
1299 struct ieee80211_hdr_3addr *hdr;
1300 unsigned int dummy_packet_size;
1301
1302 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1303 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1304
1305 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001306 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001307 wl1271_warning("Failed to allocate a dummy packet skb");
1308 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001309 }
1310
1311 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1312
1313 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1314 memset(hdr, 0, sizeof(*hdr));
1315 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001316 IEEE80211_STYPE_NULLFUNC |
1317 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001318
Ido Yariv990f5de2011-03-31 10:06:59 +02001319 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001320
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001321 /* Dummy packets require the TID to be management */
1322 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001323
1324 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001325 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001326 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001327
Ido Yariv990f5de2011-03-31 10:06:59 +02001328 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001329}
1330
Ido Yariv990f5de2011-03-31 10:06:59 +02001331
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001332static struct notifier_block wl1271_dev_notifier = {
1333 .notifier_call = wl1271_dev_notify,
1334};
1335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336static int wl1271_op_start(struct ieee80211_hw *hw)
1337{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001338 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1339
1340 /*
1341 * We have to delay the booting of the hardware because
1342 * we need to know the local MAC address before downloading and
1343 * initializing the firmware. The MAC address cannot be changed
1344 * after boot, and without the proper MAC address, the firmware
1345 * will not function properly.
1346 *
1347 * The MAC address is first known when the corresponding interface
1348 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001349 *
1350 * In addition, we currently have different firmwares for AP and managed
1351 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001352 */
1353
1354 return 0;
1355}
1356
1357static void wl1271_op_stop(struct ieee80211_hw *hw)
1358{
1359 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1360}
1361
1362static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1363 struct ieee80211_vif *vif)
1364{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001366 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001367 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001369 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001371 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1372 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373
1374 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001375 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001376 wl1271_debug(DEBUG_MAC80211,
1377 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001378 ret = -EBUSY;
1379 goto out;
1380 }
1381
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001382 /*
1383 * in some very corner case HW recovery scenarios its possible to
1384 * get here before __wl1271_op_remove_interface is complete, so
1385 * opt out if that is the case.
1386 */
1387 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1388 ret = -EBUSY;
1389 goto out;
1390 }
1391
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001392 switch (vif->type) {
1393 case NL80211_IFTYPE_STATION:
1394 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001395 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001396 break;
1397 case NL80211_IFTYPE_ADHOC:
1398 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001399 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001400 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001401 case NL80211_IFTYPE_AP:
1402 wl->bss_type = BSS_TYPE_AP_BSS;
1403 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001404 default:
1405 ret = -EOPNOTSUPP;
1406 goto out;
1407 }
1408
1409 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001410
1411 if (wl->state != WL1271_STATE_OFF) {
1412 wl1271_error("cannot start because not in off state: %d",
1413 wl->state);
1414 ret = -EBUSY;
1415 goto out;
1416 }
1417
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001418 while (retries) {
1419 retries--;
1420 ret = wl1271_chip_wakeup(wl);
1421 if (ret < 0)
1422 goto power_off;
1423
1424 ret = wl1271_boot(wl);
1425 if (ret < 0)
1426 goto power_off;
1427
1428 ret = wl1271_hw_init(wl);
1429 if (ret < 0)
1430 goto irq_disable;
1431
Eliad Peller71125ab2010-10-28 21:46:43 +02001432 booted = true;
1433 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001434
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001435irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001436 mutex_unlock(&wl->mutex);
1437 /* Unlocking the mutex in the middle of handling is
1438 inherently unsafe. In this case we deem it safe to do,
1439 because we need to let any possibly pending IRQ out of
1440 the system (and while we are WL1271_STATE_OFF the IRQ
1441 work function will not do anything.) Also, any other
1442 possible concurrent operations will fail due to the
1443 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001444 wl1271_disable_interrupts(wl);
1445 wl1271_flush_deferred_work(wl);
1446 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001447 mutex_lock(&wl->mutex);
1448power_off:
1449 wl1271_power_off(wl);
1450 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451
Eliad Peller71125ab2010-10-28 21:46:43 +02001452 if (!booted) {
1453 wl1271_error("firmware boot failed despite %d retries",
1454 WL1271_BOOT_RETRIES);
1455 goto out;
1456 }
1457
1458 wl->vif = vif;
1459 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001460 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001461 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001462
1463 /* update hw/fw version info in wiphy struct */
1464 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001465 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001466 sizeof(wiphy->fw_version));
1467
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001468 /* Check if any quirks are needed with older fw versions */
1469 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1470
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001471 /*
1472 * Now we know if 11a is supported (info from the NVS), so disable
1473 * 11a channels if not supported
1474 */
1475 if (!wl->enable_11a)
1476 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1477
1478 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1479 wl->enable_11a ? "" : "not ");
1480
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001481out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 mutex_unlock(&wl->mutex);
1483
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001484 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001485 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001486 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001487 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001488
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489 return ret;
1490}
1491
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001492static void __wl1271_op_remove_interface(struct wl1271 *wl,
1493 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001495 int i;
1496
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001497 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001499 /* because of hardware recovery, we may get here twice */
1500 if (wl->state != WL1271_STATE_ON)
1501 return;
1502
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001503 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001505 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001506 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001507 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001508
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001509 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001510 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001511 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001512
Luciano Coelho08688d62010-07-08 17:50:07 +03001513 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001514 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001515 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001516 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001517 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001518 }
1519
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001520 /*
1521 * this must be before the cancel_work calls below, so that the work
1522 * functions don't perform further work.
1523 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001524 wl->state = WL1271_STATE_OFF;
1525
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 mutex_unlock(&wl->mutex);
1527
Ido Yariva6208652011-03-01 15:14:41 +02001528 wl1271_disable_interrupts(wl);
1529 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001530 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001531 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001533 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001534 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535
1536 mutex_lock(&wl->mutex);
1537
1538 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001539 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001540 wl1271_power_off(wl);
1541
1542 memset(wl->bssid, 0, ETH_ALEN);
1543 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1544 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001545 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001546 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001547 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548
1549 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001550 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1552 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001553 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554 wl->tx_results_count = 0;
1555 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001556 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001557 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558 wl->time_offset = 0;
1559 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001560 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001561 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001562 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001563 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001564 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001565 wl->ap_fw_ps_map = 0;
1566 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001567
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001568 /*
1569 * this is performed after the cancel_work calls and the associated
1570 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1571 * get executed before all these vars have been reset.
1572 */
1573 wl->flags = 0;
1574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001575 for (i = 0; i < NUM_TX_QUEUES; i++)
1576 wl->tx_blocks_freed[i] = 0;
1577
1578 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001579
1580 kfree(wl->fw_status);
1581 wl->fw_status = NULL;
1582 kfree(wl->tx_res_if);
1583 wl->tx_res_if = NULL;
1584 kfree(wl->target_mem_map);
1585 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001586}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001587
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001588static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1589 struct ieee80211_vif *vif)
1590{
1591 struct wl1271 *wl = hw->priv;
1592
1593 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001594 /*
1595 * wl->vif can be null here if someone shuts down the interface
1596 * just when hardware recovery has been started.
1597 */
1598 if (wl->vif) {
1599 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001600 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001601 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001602
Juuso Oikarinen67353292010-11-18 15:19:02 +02001603 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001604 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001605}
1606
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001607void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001608{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001609 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001610
1611 /* combine requested filters with current filter config */
1612 filters = wl->filters | filters;
1613
1614 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1615
1616 if (filters & FIF_PROMISC_IN_BSS) {
1617 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1618 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1619 wl->rx_config |= CFG_BSSID_FILTER_EN;
1620 }
1621 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1622 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1623 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1624 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1625 }
1626 if (filters & FIF_OTHER_BSS) {
1627 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1628 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1629 }
1630 if (filters & FIF_CONTROL) {
1631 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1632 wl->rx_filter |= CFG_RX_CTL_EN;
1633 }
1634 if (filters & FIF_FCSFAIL) {
1635 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1636 wl->rx_filter |= CFG_RX_FCS_ERROR;
1637 }
1638}
1639
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001640static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001641{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001642 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001643 /* we need to use a dummy BSSID for now */
1644 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1645 0xad, 0xbe, 0xef };
1646
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001647 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1648
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001649 /* pass through frames from all BSS */
1650 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1651
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001652 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001653 if (ret < 0)
1654 goto out;
1655
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001656 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001657
1658out:
1659 return ret;
1660}
1661
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001662static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001663{
1664 int ret;
1665
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001666 /*
1667 * One of the side effects of the JOIN command is that is clears
1668 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1669 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001670 * Currently the only valid scenario for JOIN during association
1671 * is on roaming, in which case we will also be given new keys.
1672 * Keep the below message for now, unless it starts bothering
1673 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001674 */
1675 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1676 wl1271_info("JOIN while associated.");
1677
1678 if (set_assoc)
1679 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1680
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001681 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1682 if (ret < 0)
1683 goto out;
1684
1685 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1686
1687 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1688 goto out;
1689
1690 /*
1691 * The join command disable the keep-alive mode, shut down its process,
1692 * and also clear the template config, so we need to reset it all after
1693 * the join. The acx_aid starts the keep-alive process, and the order
1694 * of the commands below is relevant.
1695 */
1696 ret = wl1271_acx_keep_alive_mode(wl, true);
1697 if (ret < 0)
1698 goto out;
1699
1700 ret = wl1271_acx_aid(wl, wl->aid);
1701 if (ret < 0)
1702 goto out;
1703
1704 ret = wl1271_cmd_build_klv_null_data(wl);
1705 if (ret < 0)
1706 goto out;
1707
1708 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1709 ACX_KEEP_ALIVE_TPL_VALID);
1710 if (ret < 0)
1711 goto out;
1712
1713out:
1714 return ret;
1715}
1716
1717static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001718{
1719 int ret;
1720
1721 /* to stop listening to a channel, we disconnect */
1722 ret = wl1271_cmd_disconnect(wl);
1723 if (ret < 0)
1724 goto out;
1725
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001726 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001727 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001728
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001729 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001730 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001731
1732out:
1733 return ret;
1734}
1735
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001736static void wl1271_set_band_rate(struct wl1271 *wl)
1737{
1738 if (wl->band == IEEE80211_BAND_2GHZ)
1739 wl->basic_rate_set = wl->conf.tx.basic_rate;
1740 else
1741 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1742}
1743
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001744static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001745{
1746 int ret;
1747
1748 if (idle) {
1749 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1750 ret = wl1271_unjoin(wl);
1751 if (ret < 0)
1752 goto out;
1753 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001754 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001755 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001756 if (ret < 0)
1757 goto out;
1758 ret = wl1271_acx_keep_alive_config(
1759 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1760 ACX_KEEP_ALIVE_TPL_INVALID);
1761 if (ret < 0)
1762 goto out;
1763 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1764 } else {
1765 /* increment the session counter */
1766 wl->session_counter++;
1767 if (wl->session_counter >= SESSION_COUNTER_MAX)
1768 wl->session_counter = 0;
1769 ret = wl1271_dummy_join(wl);
1770 if (ret < 0)
1771 goto out;
1772 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1773 }
1774
1775out:
1776 return ret;
1777}
1778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001779static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1780{
1781 struct wl1271 *wl = hw->priv;
1782 struct ieee80211_conf *conf = &hw->conf;
1783 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001784 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001785
1786 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1787
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001788 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1789 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001790 channel,
1791 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001792 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001793 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1794 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001795
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001796 /*
1797 * mac80211 will go to idle nearly immediately after transmitting some
1798 * frames, such as the deauth. To make sure those frames reach the air,
1799 * wait here until the TX queue is fully flushed.
1800 */
1801 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1802 (conf->flags & IEEE80211_CONF_IDLE))
1803 wl1271_tx_flush(wl);
1804
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001805 mutex_lock(&wl->mutex);
1806
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001807 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001808 /* we support configuring the channel and band while off */
1809 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1810 wl->band = conf->channel->band;
1811 wl->channel = channel;
1812 }
1813
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001814 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001815 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001816
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001817 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1818
Ido Yariva6208652011-03-01 15:14:41 +02001819 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001820 if (ret < 0)
1821 goto out;
1822
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001823 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001824 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1825 ((wl->band != conf->channel->band) ||
1826 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001827 wl->band = conf->channel->band;
1828 wl->channel = channel;
1829
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001830 if (!is_ap) {
1831 /*
1832 * FIXME: the mac80211 should really provide a fixed
1833 * rate to use here. for now, just use the smallest
1834 * possible rate for the band as a fixed rate for
1835 * association frames and other control messages.
1836 */
1837 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1838 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001839
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001840 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1841 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001842 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001843 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001844 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001845
1846 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1847 ret = wl1271_join(wl, false);
1848 if (ret < 0)
1849 wl1271_warning("cmd join on channel "
1850 "failed %d", ret);
1851 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001852 }
1853 }
1854
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001855 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1856 ret = wl1271_sta_handle_idle(wl,
1857 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001858 if (ret < 0)
1859 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 }
1861
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001862 /*
1863 * if mac80211 changes the PSM mode, make sure the mode is not
1864 * incorrectly changed after the pspoll failure active window.
1865 */
1866 if (changed & IEEE80211_CONF_CHANGE_PS)
1867 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1868
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001869 if (conf->flags & IEEE80211_CONF_PS &&
1870 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1871 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872
1873 /*
1874 * We enter PSM only if we're already associated.
1875 * If we're not, we'll enter it when joining an SSID,
1876 * through the bss_info_changed() hook.
1877 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001878 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001879 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001880 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001881 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001882 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001883 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001884 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001885 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001886
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001887 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001888
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001889 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001890 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001891 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001892 }
1893
1894 if (conf->power_level != wl->power_level) {
1895 ret = wl1271_acx_tx_power(wl, conf->power_level);
1896 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001897 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001898
1899 wl->power_level = conf->power_level;
1900 }
1901
1902out_sleep:
1903 wl1271_ps_elp_sleep(wl);
1904
1905out:
1906 mutex_unlock(&wl->mutex);
1907
1908 return ret;
1909}
1910
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001911struct wl1271_filter_params {
1912 bool enabled;
1913 int mc_list_length;
1914 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1915};
1916
Jiri Pirko22bedad2010-04-01 21:22:57 +00001917static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1918 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001919{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001920 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001921 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001922 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001923
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001924 if (unlikely(wl->state == WL1271_STATE_OFF))
1925 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001926
Juuso Oikarinen74441132009-10-13 12:47:53 +03001927 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001928 if (!fp) {
1929 wl1271_error("Out of memory setting filters.");
1930 return 0;
1931 }
1932
1933 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001934 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001935 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1936 fp->enabled = false;
1937 } else {
1938 fp->enabled = true;
1939 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001940 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001941 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001942 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001943 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001944 }
1945
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001946 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001947}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001949#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1950 FIF_ALLMULTI | \
1951 FIF_FCSFAIL | \
1952 FIF_BCN_PRBRESP_PROMISC | \
1953 FIF_CONTROL | \
1954 FIF_OTHER_BSS)
1955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1957 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001958 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001960 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001962 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963
Arik Nemtsov7d057862010-10-16 19:25:35 +02001964 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1965 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001967 mutex_lock(&wl->mutex);
1968
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001969 *total &= WL1271_SUPPORTED_FILTERS;
1970 changed &= WL1271_SUPPORTED_FILTERS;
1971
1972 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001973 goto out;
1974
Ido Yariva6208652011-03-01 15:14:41 +02001975 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001976 if (ret < 0)
1977 goto out;
1978
Arik Nemtsov7d057862010-10-16 19:25:35 +02001979 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1980 if (*total & FIF_ALLMULTI)
1981 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1982 else if (fp)
1983 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1984 fp->mc_list,
1985 fp->mc_list_length);
1986 if (ret < 0)
1987 goto out_sleep;
1988 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001990 /* determine, whether supported filter values have changed */
1991 if (changed == 0)
1992 goto out_sleep;
1993
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001994 /* configure filters */
1995 wl->filters = *total;
1996 wl1271_configure_filters(wl, 0);
1997
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001998 /* apply configured filters */
1999 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2000 if (ret < 0)
2001 goto out_sleep;
2002
2003out_sleep:
2004 wl1271_ps_elp_sleep(wl);
2005
2006out:
2007 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002008 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002009}
2010
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002011static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2012 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2013 u16 tx_seq_16)
2014{
2015 struct wl1271_ap_key *ap_key;
2016 int i;
2017
2018 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2019
2020 if (key_size > MAX_KEY_SIZE)
2021 return -EINVAL;
2022
2023 /*
2024 * Find next free entry in ap_keys. Also check we are not replacing
2025 * an existing key.
2026 */
2027 for (i = 0; i < MAX_NUM_KEYS; i++) {
2028 if (wl->recorded_ap_keys[i] == NULL)
2029 break;
2030
2031 if (wl->recorded_ap_keys[i]->id == id) {
2032 wl1271_warning("trying to record key replacement");
2033 return -EINVAL;
2034 }
2035 }
2036
2037 if (i == MAX_NUM_KEYS)
2038 return -EBUSY;
2039
2040 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2041 if (!ap_key)
2042 return -ENOMEM;
2043
2044 ap_key->id = id;
2045 ap_key->key_type = key_type;
2046 ap_key->key_size = key_size;
2047 memcpy(ap_key->key, key, key_size);
2048 ap_key->hlid = hlid;
2049 ap_key->tx_seq_32 = tx_seq_32;
2050 ap_key->tx_seq_16 = tx_seq_16;
2051
2052 wl->recorded_ap_keys[i] = ap_key;
2053 return 0;
2054}
2055
2056static void wl1271_free_ap_keys(struct wl1271 *wl)
2057{
2058 int i;
2059
2060 for (i = 0; i < MAX_NUM_KEYS; i++) {
2061 kfree(wl->recorded_ap_keys[i]);
2062 wl->recorded_ap_keys[i] = NULL;
2063 }
2064}
2065
2066static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2067{
2068 int i, ret = 0;
2069 struct wl1271_ap_key *key;
2070 bool wep_key_added = false;
2071
2072 for (i = 0; i < MAX_NUM_KEYS; i++) {
2073 if (wl->recorded_ap_keys[i] == NULL)
2074 break;
2075
2076 key = wl->recorded_ap_keys[i];
2077 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2078 key->id, key->key_type,
2079 key->key_size, key->key,
2080 key->hlid, key->tx_seq_32,
2081 key->tx_seq_16);
2082 if (ret < 0)
2083 goto out;
2084
2085 if (key->key_type == KEY_WEP)
2086 wep_key_added = true;
2087 }
2088
2089 if (wep_key_added) {
2090 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2091 if (ret < 0)
2092 goto out;
2093 }
2094
2095out:
2096 wl1271_free_ap_keys(wl);
2097 return ret;
2098}
2099
2100static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2101 u8 key_size, const u8 *key, u32 tx_seq_32,
2102 u16 tx_seq_16, struct ieee80211_sta *sta)
2103{
2104 int ret;
2105 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2106
2107 if (is_ap) {
2108 struct wl1271_station *wl_sta;
2109 u8 hlid;
2110
2111 if (sta) {
2112 wl_sta = (struct wl1271_station *)sta->drv_priv;
2113 hlid = wl_sta->hlid;
2114 } else {
2115 hlid = WL1271_AP_BROADCAST_HLID;
2116 }
2117
2118 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2119 /*
2120 * We do not support removing keys after AP shutdown.
2121 * Pretend we do to make mac80211 happy.
2122 */
2123 if (action != KEY_ADD_OR_REPLACE)
2124 return 0;
2125
2126 ret = wl1271_record_ap_key(wl, id,
2127 key_type, key_size,
2128 key, hlid, tx_seq_32,
2129 tx_seq_16);
2130 } else {
2131 ret = wl1271_cmd_set_ap_key(wl, action,
2132 id, key_type, key_size,
2133 key, hlid, tx_seq_32,
2134 tx_seq_16);
2135 }
2136
2137 if (ret < 0)
2138 return ret;
2139 } else {
2140 const u8 *addr;
2141 static const u8 bcast_addr[ETH_ALEN] = {
2142 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2143 };
2144
2145 addr = sta ? sta->addr : bcast_addr;
2146
2147 if (is_zero_ether_addr(addr)) {
2148 /* We dont support TX only encryption */
2149 return -EOPNOTSUPP;
2150 }
2151
2152 /* The wl1271 does not allow to remove unicast keys - they
2153 will be cleared automatically on next CMD_JOIN. Ignore the
2154 request silently, as we dont want the mac80211 to emit
2155 an error message. */
2156 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2157 return 0;
2158
2159 ret = wl1271_cmd_set_sta_key(wl, action,
2160 id, key_type, key_size,
2161 key, addr, tx_seq_32,
2162 tx_seq_16);
2163 if (ret < 0)
2164 return ret;
2165
2166 /* the default WEP key needs to be configured at least once */
2167 if (key_type == KEY_WEP) {
2168 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2169 wl->default_key);
2170 if (ret < 0)
2171 return ret;
2172 }
2173 }
2174
2175 return 0;
2176}
2177
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2179 struct ieee80211_vif *vif,
2180 struct ieee80211_sta *sta,
2181 struct ieee80211_key_conf *key_conf)
2182{
2183 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002185 u32 tx_seq_32 = 0;
2186 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002187 u8 key_type;
2188
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2190
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002191 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002193 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194 key_conf->keylen, key_conf->flags);
2195 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2196
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197 mutex_lock(&wl->mutex);
2198
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002199 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2200 ret = -EAGAIN;
2201 goto out_unlock;
2202 }
2203
Ido Yariva6208652011-03-01 15:14:41 +02002204 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002205 if (ret < 0)
2206 goto out_unlock;
2207
Johannes Berg97359d12010-08-10 09:46:38 +02002208 switch (key_conf->cipher) {
2209 case WLAN_CIPHER_SUITE_WEP40:
2210 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002211 key_type = KEY_WEP;
2212
2213 key_conf->hw_key_idx = key_conf->keyidx;
2214 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002215 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216 key_type = KEY_TKIP;
2217
2218 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002219 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2220 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002221 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002222 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223 key_type = KEY_AES;
2224
2225 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002226 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2227 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002228 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002229 case WL1271_CIPHER_SUITE_GEM:
2230 key_type = KEY_GEM;
2231 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2232 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2233 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002234 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002235 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236
2237 ret = -EOPNOTSUPP;
2238 goto out_sleep;
2239 }
2240
2241 switch (cmd) {
2242 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002243 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2244 key_conf->keyidx, key_type,
2245 key_conf->keylen, key_conf->key,
2246 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247 if (ret < 0) {
2248 wl1271_error("Could not add or replace key");
2249 goto out_sleep;
2250 }
2251 break;
2252
2253 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002254 ret = wl1271_set_key(wl, KEY_REMOVE,
2255 key_conf->keyidx, key_type,
2256 key_conf->keylen, key_conf->key,
2257 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 if (ret < 0) {
2259 wl1271_error("Could not remove key");
2260 goto out_sleep;
2261 }
2262 break;
2263
2264 default:
2265 wl1271_error("Unsupported key cmd 0x%x", cmd);
2266 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002267 break;
2268 }
2269
2270out_sleep:
2271 wl1271_ps_elp_sleep(wl);
2272
2273out_unlock:
2274 mutex_unlock(&wl->mutex);
2275
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276 return ret;
2277}
2278
2279static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002280 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002281 struct cfg80211_scan_request *req)
2282{
2283 struct wl1271 *wl = hw->priv;
2284 int ret;
2285 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002286 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287
2288 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2289
2290 if (req->n_ssids) {
2291 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002292 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293 }
2294
2295 mutex_lock(&wl->mutex);
2296
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002297 if (wl->state == WL1271_STATE_OFF) {
2298 /*
2299 * We cannot return -EBUSY here because cfg80211 will expect
2300 * a call to ieee80211_scan_completed if we do - in this case
2301 * there won't be any call.
2302 */
2303 ret = -EAGAIN;
2304 goto out;
2305 }
2306
Ido Yariva6208652011-03-01 15:14:41 +02002307 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308 if (ret < 0)
2309 goto out;
2310
Luciano Coelho5924f892010-08-04 03:46:22 +03002311 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002312
2313 wl1271_ps_elp_sleep(wl);
2314
2315out:
2316 mutex_unlock(&wl->mutex);
2317
2318 return ret;
2319}
2320
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002321static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2322{
2323 struct wl1271 *wl = hw->priv;
2324 int ret = 0;
2325
2326 mutex_lock(&wl->mutex);
2327
2328 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2329 ret = -EAGAIN;
2330 goto out;
2331 }
2332
Ido Yariva6208652011-03-01 15:14:41 +02002333 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002334 if (ret < 0)
2335 goto out;
2336
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002337 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002338 if (ret < 0)
2339 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2340
2341 wl1271_ps_elp_sleep(wl);
2342
2343out:
2344 mutex_unlock(&wl->mutex);
2345
2346 return ret;
2347}
2348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2350{
2351 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002352 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002353
2354 mutex_lock(&wl->mutex);
2355
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002356 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2357 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002358 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002359 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002360
Ido Yariva6208652011-03-01 15:14:41 +02002361 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002362 if (ret < 0)
2363 goto out;
2364
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002365 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 if (ret < 0)
2367 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2368
2369 wl1271_ps_elp_sleep(wl);
2370
2371out:
2372 mutex_unlock(&wl->mutex);
2373
2374 return ret;
2375}
2376
Arik Nemtsove78a2872010-10-16 19:07:21 +02002377static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002378 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002379{
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002380 u8 *ptr = skb->data + offset;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002381
2382 /* find the location of the ssid in the beacon */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002383 while (ptr < skb->data + skb->len) {
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002384 if (ptr[0] == WLAN_EID_SSID) {
2385 wl->ssid_len = ptr[1];
2386 memcpy(wl->ssid, ptr+2, wl->ssid_len);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002387 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002388 }
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002389 ptr += (ptr[1] + 2);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002390 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002391
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002392 wl1271_error("No SSID in IEs!\n");
Arik Nemtsove78a2872010-10-16 19:07:21 +02002393 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002394}
2395
Arik Nemtsove78a2872010-10-16 19:07:21 +02002396static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2397 struct ieee80211_bss_conf *bss_conf,
2398 u32 changed)
2399{
2400 int ret = 0;
2401
2402 if (changed & BSS_CHANGED_ERP_SLOT) {
2403 if (bss_conf->use_short_slot)
2404 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2405 else
2406 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2407 if (ret < 0) {
2408 wl1271_warning("Set slot time failed %d", ret);
2409 goto out;
2410 }
2411 }
2412
2413 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2414 if (bss_conf->use_short_preamble)
2415 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2416 else
2417 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2418 }
2419
2420 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2421 if (bss_conf->use_cts_prot)
2422 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2423 else
2424 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2425 if (ret < 0) {
2426 wl1271_warning("Set ctsprotect failed %d", ret);
2427 goto out;
2428 }
2429 }
2430
2431out:
2432 return ret;
2433}
2434
2435static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2436 struct ieee80211_vif *vif,
2437 struct ieee80211_bss_conf *bss_conf,
2438 u32 changed)
2439{
2440 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2441 int ret = 0;
2442
2443 if ((changed & BSS_CHANGED_BEACON_INT)) {
2444 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2445 bss_conf->beacon_int);
2446
2447 wl->beacon_int = bss_conf->beacon_int;
2448 }
2449
2450 if ((changed & BSS_CHANGED_BEACON)) {
2451 struct ieee80211_hdr *hdr;
2452 int ieoffset = offsetof(struct ieee80211_mgmt,
2453 u.beacon.variable);
2454 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2455 u16 tmpl_id;
2456
2457 if (!beacon)
2458 goto out;
2459
2460 wl1271_debug(DEBUG_MASTER, "beacon updated");
2461
2462 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2463 if (ret < 0) {
2464 dev_kfree_skb(beacon);
2465 goto out;
2466 }
2467 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2468 CMD_TEMPL_BEACON;
2469 ret = wl1271_cmd_template_set(wl, tmpl_id,
2470 beacon->data,
2471 beacon->len, 0,
2472 wl1271_tx_min_rate_get(wl));
2473 if (ret < 0) {
2474 dev_kfree_skb(beacon);
2475 goto out;
2476 }
2477
2478 hdr = (struct ieee80211_hdr *) beacon->data;
2479 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2480 IEEE80211_STYPE_PROBE_RESP);
2481
2482 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2483 CMD_TEMPL_PROBE_RESPONSE;
2484 ret = wl1271_cmd_template_set(wl,
2485 tmpl_id,
2486 beacon->data,
2487 beacon->len, 0,
2488 wl1271_tx_min_rate_get(wl));
2489 dev_kfree_skb(beacon);
2490 if (ret < 0)
2491 goto out;
2492 }
2493
2494out:
2495 return ret;
2496}
2497
2498/* AP mode changes */
2499static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002500 struct ieee80211_vif *vif,
2501 struct ieee80211_bss_conf *bss_conf,
2502 u32 changed)
2503{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002504 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002505
Arik Nemtsove78a2872010-10-16 19:07:21 +02002506 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2507 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002508
Arik Nemtsove78a2872010-10-16 19:07:21 +02002509 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2510 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002511
Arik Nemtsov70f47422011-04-18 14:15:25 +03002512 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002513 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002514 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002515 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002516 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002517
2518 ret = wl1271_ap_init_templates(wl);
2519 if (ret < 0)
2520 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002521 }
2522
Arik Nemtsove78a2872010-10-16 19:07:21 +02002523 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2524 if (ret < 0)
2525 goto out;
2526
2527 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2528 if (bss_conf->enable_beacon) {
2529 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2530 ret = wl1271_cmd_start_bss(wl);
2531 if (ret < 0)
2532 goto out;
2533
2534 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2535 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002536
2537 ret = wl1271_ap_init_hwenc(wl);
2538 if (ret < 0)
2539 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002540 }
2541 } else {
2542 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2543 ret = wl1271_cmd_stop_bss(wl);
2544 if (ret < 0)
2545 goto out;
2546
2547 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2548 wl1271_debug(DEBUG_AP, "stopped AP");
2549 }
2550 }
2551 }
2552
Eliad Pellercb5ae052011-04-07 15:52:05 +03002553 if (changed & BSS_CHANGED_IBSS) {
2554 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2555 bss_conf->ibss_joined);
2556
2557 if (bss_conf->ibss_joined) {
2558 u32 rates = bss_conf->basic_rates;
2559 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2560 rates);
2561 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2562
2563 /* by default, use 11b rates */
2564 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2565 ret = wl1271_acx_sta_rate_policies(wl);
2566 if (ret < 0)
2567 goto out;
2568 }
2569 }
2570
Arik Nemtsove78a2872010-10-16 19:07:21 +02002571 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2572 if (ret < 0)
2573 goto out;
2574out:
2575 return;
2576}
2577
2578/* STA/IBSS mode changes */
2579static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2580 struct ieee80211_vif *vif,
2581 struct ieee80211_bss_conf *bss_conf,
2582 u32 changed)
2583{
2584 bool do_join = false, set_assoc = false;
2585 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002586 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002587 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002588 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002589 bool sta_exists = false;
2590 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002591
2592 if (is_ibss) {
2593 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2594 changed);
2595 if (ret < 0)
2596 goto out;
2597 }
2598
2599 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2600 do_join = true;
2601
2602 /* Need to update the SSID (for filtering etc) */
2603 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2604 do_join = true;
2605
2606 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002607 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2608 bss_conf->enable_beacon ? "enabled" : "disabled");
2609
2610 if (bss_conf->enable_beacon)
2611 wl->set_bss_type = BSS_TYPE_IBSS;
2612 else
2613 wl->set_bss_type = BSS_TYPE_STA_BSS;
2614 do_join = true;
2615 }
2616
Arik Nemtsove78a2872010-10-16 19:07:21 +02002617 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002618 bool enable = false;
2619 if (bss_conf->cqm_rssi_thold)
2620 enable = true;
2621 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2622 bss_conf->cqm_rssi_thold,
2623 bss_conf->cqm_rssi_hyst);
2624 if (ret < 0)
2625 goto out;
2626 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2627 }
2628
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002629 if ((changed & BSS_CHANGED_BSSID) &&
2630 /*
2631 * Now we know the correct bssid, so we send a new join command
2632 * and enable the BSSID filter
2633 */
2634 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002635 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002636
Eliad Pellerfa287b82010-12-26 09:27:50 +01002637 if (!is_zero_ether_addr(wl->bssid)) {
2638 ret = wl1271_cmd_build_null_data(wl);
2639 if (ret < 0)
2640 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002641
Eliad Pellerfa287b82010-12-26 09:27:50 +01002642 ret = wl1271_build_qos_null_data(wl);
2643 if (ret < 0)
2644 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002645
Eliad Pellerfa287b82010-12-26 09:27:50 +01002646 /* filter out all packets not from this BSSID */
2647 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002648
Eliad Pellerfa287b82010-12-26 09:27:50 +01002649 /* Need to update the BSSID (for filtering etc) */
2650 do_join = true;
2651 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002652 }
2653
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002654 rcu_read_lock();
2655 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2656 if (sta) {
2657 /* save the supp_rates of the ap */
2658 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2659 if (sta->ht_cap.ht_supported)
2660 sta_rate_set |=
2661 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002662 sta_ht_cap = sta->ht_cap;
2663 sta_exists = true;
2664 }
2665 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002666
Arik Nemtsova1008852011-02-12 23:24:20 +02002667 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002668 /* handle new association with HT and HT information change */
2669 if ((changed & BSS_CHANGED_HT) &&
2670 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002671 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002672 true);
2673 if (ret < 0) {
2674 wl1271_warning("Set ht cap true failed %d",
2675 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002676 goto out;
2677 }
2678 ret = wl1271_acx_set_ht_information(wl,
2679 bss_conf->ht_operation_mode);
2680 if (ret < 0) {
2681 wl1271_warning("Set ht information failed %d",
2682 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002683 goto out;
2684 }
2685 }
2686 /* handle new association without HT and disassociation */
2687 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002688 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002689 false);
2690 if (ret < 0) {
2691 wl1271_warning("Set ht cap false failed %d",
2692 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002693 goto out;
2694 }
2695 }
2696 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002697
Arik Nemtsove78a2872010-10-16 19:07:21 +02002698 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002700 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002701 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002702 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002703 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002705 wl->ps_poll_failures = 0;
2706
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002707 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002708 * use basic rates from AP, and determine lowest rate
2709 * to use with control frames.
2710 */
2711 rates = bss_conf->basic_rates;
2712 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2713 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002714 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002715 if (sta_rate_set)
2716 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2717 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002718 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002719 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002720 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002721
2722 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002723 * with wl1271, we don't need to update the
2724 * beacon_int and dtim_period, because the firmware
2725 * updates it by itself when the first beacon is
2726 * received after a join.
2727 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2729 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002730 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002732 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002733 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002734 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002735 dev_kfree_skb(wl->probereq);
2736 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2737 ieoffset = offsetof(struct ieee80211_mgmt,
2738 u.probe_req.variable);
2739 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002740
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002741 /* enable the connection monitoring feature */
2742 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002744 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002745
2746 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002747 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2748 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002749 enum wl1271_cmd_ps_mode mode;
2750
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002751 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002752 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002753 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002754 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002755 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002756 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002757 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002758 } else {
2759 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002760 bool was_assoc =
2761 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2762 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002763 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002764 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002765
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002766 /* free probe-request template */
2767 dev_kfree_skb(wl->probereq);
2768 wl->probereq = NULL;
2769
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002770 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002771 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002772
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002773 /* revert back to minimum rates for the current band */
2774 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002775 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002776 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002777 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002778 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002779
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002780 /* disable connection monitor features */
2781 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002782
2783 /* Disable the keep-alive feature */
2784 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002785 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002786 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002787
2788 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002789 if (was_assoc) {
2790 wl1271_unjoin(wl);
2791 wl1271_dummy_join(wl);
2792 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 }
2794 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002795
Arik Nemtsove78a2872010-10-16 19:07:21 +02002796 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2797 if (ret < 0)
2798 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002800 if (changed & BSS_CHANGED_ARP_FILTER) {
2801 __be32 addr = bss_conf->arp_addr_list[0];
2802 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2803
Eliad Pellerc5312772010-12-09 11:31:27 +02002804 if (bss_conf->arp_addr_cnt == 1 &&
2805 bss_conf->arp_filter_enabled) {
2806 /*
2807 * The template should have been configured only upon
2808 * association. however, it seems that the correct ip
2809 * isn't being set (when sending), so we have to
2810 * reconfigure the template upon every ip change.
2811 */
2812 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2813 if (ret < 0) {
2814 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002815 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002816 }
2817
2818 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002819 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002820 addr);
2821 } else
2822 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002823
2824 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002825 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002826 }
2827
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002828 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002829 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002830 if (ret < 0) {
2831 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002832 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002833 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002834 }
2835
Arik Nemtsove78a2872010-10-16 19:07:21 +02002836out:
2837 return;
2838}
2839
2840static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2841 struct ieee80211_vif *vif,
2842 struct ieee80211_bss_conf *bss_conf,
2843 u32 changed)
2844{
2845 struct wl1271 *wl = hw->priv;
2846 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2847 int ret;
2848
2849 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2850 (int)changed);
2851
2852 mutex_lock(&wl->mutex);
2853
2854 if (unlikely(wl->state == WL1271_STATE_OFF))
2855 goto out;
2856
Ido Yariva6208652011-03-01 15:14:41 +02002857 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002858 if (ret < 0)
2859 goto out;
2860
2861 if (is_ap)
2862 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2863 else
2864 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002866 wl1271_ps_elp_sleep(wl);
2867
2868out:
2869 mutex_unlock(&wl->mutex);
2870}
2871
Kalle Valoc6999d82010-02-18 13:25:41 +02002872static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2873 const struct ieee80211_tx_queue_params *params)
2874{
2875 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002876 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002877 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002878
2879 mutex_lock(&wl->mutex);
2880
2881 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2882
Kalle Valo4695dc92010-03-18 12:26:38 +02002883 if (params->uapsd)
2884 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2885 else
2886 ps_scheme = CONF_PS_SCHEME_LEGACY;
2887
Arik Nemtsov488fc542010-10-16 20:33:45 +02002888 if (wl->state == WL1271_STATE_OFF) {
2889 /*
2890 * If the state is off, the parameters will be recorded and
2891 * configured on init. This happens in AP-mode.
2892 */
2893 struct conf_tx_ac_category *conf_ac =
2894 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2895 struct conf_tx_tid *conf_tid =
2896 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2897
2898 conf_ac->ac = wl1271_tx_get_queue(queue);
2899 conf_ac->cw_min = (u8)params->cw_min;
2900 conf_ac->cw_max = params->cw_max;
2901 conf_ac->aifsn = params->aifs;
2902 conf_ac->tx_op_limit = params->txop << 5;
2903
2904 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2905 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2906 conf_tid->tsid = wl1271_tx_get_queue(queue);
2907 conf_tid->ps_scheme = ps_scheme;
2908 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2909 conf_tid->apsd_conf[0] = 0;
2910 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002911 goto out;
2912 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002913
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002914 ret = wl1271_ps_elp_wakeup(wl);
2915 if (ret < 0)
2916 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002917
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002918 /*
2919 * the txop is confed in units of 32us by the mac80211,
2920 * we need us
2921 */
2922 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2923 params->cw_min, params->cw_max,
2924 params->aifs, params->txop << 5);
2925 if (ret < 0)
2926 goto out_sleep;
2927
2928 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2929 CONF_CHANNEL_TYPE_EDCF,
2930 wl1271_tx_get_queue(queue),
2931 ps_scheme, CONF_ACK_POLICY_LEGACY,
2932 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002933
2934out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002935 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002936
2937out:
2938 mutex_unlock(&wl->mutex);
2939
2940 return ret;
2941}
2942
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002943static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2944{
2945
2946 struct wl1271 *wl = hw->priv;
2947 u64 mactime = ULLONG_MAX;
2948 int ret;
2949
2950 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2951
2952 mutex_lock(&wl->mutex);
2953
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002954 if (unlikely(wl->state == WL1271_STATE_OFF))
2955 goto out;
2956
Ido Yariva6208652011-03-01 15:14:41 +02002957 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002958 if (ret < 0)
2959 goto out;
2960
2961 ret = wl1271_acx_tsf_info(wl, &mactime);
2962 if (ret < 0)
2963 goto out_sleep;
2964
2965out_sleep:
2966 wl1271_ps_elp_sleep(wl);
2967
2968out:
2969 mutex_unlock(&wl->mutex);
2970 return mactime;
2971}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972
John W. Linvilleece550d2010-07-28 16:41:06 -04002973static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2974 struct survey_info *survey)
2975{
2976 struct wl1271 *wl = hw->priv;
2977 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002978
John W. Linvilleece550d2010-07-28 16:41:06 -04002979 if (idx != 0)
2980 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002981
John W. Linvilleece550d2010-07-28 16:41:06 -04002982 survey->channel = conf->channel;
2983 survey->filled = SURVEY_INFO_NOISE_DBM;
2984 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002985
John W. Linvilleece550d2010-07-28 16:41:06 -04002986 return 0;
2987}
2988
Arik Nemtsov409622e2011-02-23 00:22:29 +02002989static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002990 struct ieee80211_sta *sta,
2991 u8 *hlid)
2992{
2993 struct wl1271_station *wl_sta;
2994 int id;
2995
2996 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
2997 if (id >= AP_MAX_STATIONS) {
2998 wl1271_warning("could not allocate HLID - too much stations");
2999 return -EBUSY;
3000 }
3001
3002 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003003 __set_bit(id, wl->ap_hlid_map);
3004 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3005 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003006 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003007 return 0;
3008}
3009
Arik Nemtsov409622e2011-02-23 00:22:29 +02003010static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003011{
3012 int id = hlid - WL1271_AP_STA_HLID_START;
3013
Arik Nemtsov409622e2011-02-23 00:22:29 +02003014 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3015 return;
3016
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003017 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003018 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003019 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003020 __clear_bit(hlid, &wl->ap_ps_map);
3021 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003022}
3023
Arik Nemtsov47684802011-04-26 23:21:51 +03003024bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3025{
3026 int id = hlid - WL1271_AP_STA_HLID_START;
3027 return test_bit(id, wl->ap_hlid_map);
3028}
3029
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003030static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3031 struct ieee80211_vif *vif,
3032 struct ieee80211_sta *sta)
3033{
3034 struct wl1271 *wl = hw->priv;
3035 int ret = 0;
3036 u8 hlid;
3037
3038 mutex_lock(&wl->mutex);
3039
3040 if (unlikely(wl->state == WL1271_STATE_OFF))
3041 goto out;
3042
3043 if (wl->bss_type != BSS_TYPE_AP_BSS)
3044 goto out;
3045
3046 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3047
Arik Nemtsov409622e2011-02-23 00:22:29 +02003048 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003049 if (ret < 0)
3050 goto out;
3051
Ido Yariva6208652011-03-01 15:14:41 +02003052 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003053 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003054 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003055
3056 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3057 if (ret < 0)
3058 goto out_sleep;
3059
3060out_sleep:
3061 wl1271_ps_elp_sleep(wl);
3062
Arik Nemtsov409622e2011-02-23 00:22:29 +02003063out_free_sta:
3064 if (ret < 0)
3065 wl1271_free_sta(wl, hlid);
3066
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003067out:
3068 mutex_unlock(&wl->mutex);
3069 return ret;
3070}
3071
3072static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3073 struct ieee80211_vif *vif,
3074 struct ieee80211_sta *sta)
3075{
3076 struct wl1271 *wl = hw->priv;
3077 struct wl1271_station *wl_sta;
3078 int ret = 0, id;
3079
3080 mutex_lock(&wl->mutex);
3081
3082 if (unlikely(wl->state == WL1271_STATE_OFF))
3083 goto out;
3084
3085 if (wl->bss_type != BSS_TYPE_AP_BSS)
3086 goto out;
3087
3088 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3089
3090 wl_sta = (struct wl1271_station *)sta->drv_priv;
3091 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3092 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3093 goto out;
3094
Ido Yariva6208652011-03-01 15:14:41 +02003095 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003096 if (ret < 0)
3097 goto out;
3098
3099 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3100 if (ret < 0)
3101 goto out_sleep;
3102
Arik Nemtsov409622e2011-02-23 00:22:29 +02003103 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003104
3105out_sleep:
3106 wl1271_ps_elp_sleep(wl);
3107
3108out:
3109 mutex_unlock(&wl->mutex);
3110 return ret;
3111}
3112
Luciano Coelho4623ec72011-03-21 19:26:41 +02003113static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3114 struct ieee80211_vif *vif,
3115 enum ieee80211_ampdu_mlme_action action,
3116 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3117 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003118{
3119 struct wl1271 *wl = hw->priv;
3120 int ret;
3121
3122 mutex_lock(&wl->mutex);
3123
3124 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3125 ret = -EAGAIN;
3126 goto out;
3127 }
3128
Ido Yariva6208652011-03-01 15:14:41 +02003129 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003130 if (ret < 0)
3131 goto out;
3132
3133 switch (action) {
3134 case IEEE80211_AMPDU_RX_START:
3135 if (wl->ba_support) {
3136 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3137 true);
3138 if (!ret)
3139 wl->ba_rx_bitmap |= BIT(tid);
3140 } else {
3141 ret = -ENOTSUPP;
3142 }
3143 break;
3144
3145 case IEEE80211_AMPDU_RX_STOP:
3146 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3147 if (!ret)
3148 wl->ba_rx_bitmap &= ~BIT(tid);
3149 break;
3150
3151 /*
3152 * The BA initiator session management in FW independently.
3153 * Falling break here on purpose for all TX APDU commands.
3154 */
3155 case IEEE80211_AMPDU_TX_START:
3156 case IEEE80211_AMPDU_TX_STOP:
3157 case IEEE80211_AMPDU_TX_OPERATIONAL:
3158 ret = -EINVAL;
3159 break;
3160
3161 default:
3162 wl1271_error("Incorrect ampdu action id=%x\n", action);
3163 ret = -EINVAL;
3164 }
3165
3166 wl1271_ps_elp_sleep(wl);
3167
3168out:
3169 mutex_unlock(&wl->mutex);
3170
3171 return ret;
3172}
3173
Arik Nemtsov33437892011-04-26 23:35:39 +03003174static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3175{
3176 struct wl1271 *wl = hw->priv;
3177 bool ret = false;
3178
3179 mutex_lock(&wl->mutex);
3180
3181 if (unlikely(wl->state == WL1271_STATE_OFF))
3182 goto out;
3183
3184 /* packets are considered pending if in the TX queue or the FW */
3185 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3186
3187 /* the above is appropriate for STA mode for PS purposes */
3188 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3189
3190out:
3191 mutex_unlock(&wl->mutex);
3192
3193 return ret;
3194}
3195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196/* can't be const, mac80211 writes to this */
3197static struct ieee80211_rate wl1271_rates[] = {
3198 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003199 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3200 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003201 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003202 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3203 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003204 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3205 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003206 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3207 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003208 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3209 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003210 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3211 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003212 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3213 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003214 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3215 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003217 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3218 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003220 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3221 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003223 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3224 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003225 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003226 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3227 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003229 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3230 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003231 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003232 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3233 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003234 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003235 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3236 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003237};
3238
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003239/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003240static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003241 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003242 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003243 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3244 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3245 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003246 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003247 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3248 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3249 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003250 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003251 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3252 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3253 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003254 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255};
3256
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003257/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003258static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003259 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003260 7, /* CONF_HW_RXTX_RATE_MCS7 */
3261 6, /* CONF_HW_RXTX_RATE_MCS6 */
3262 5, /* CONF_HW_RXTX_RATE_MCS5 */
3263 4, /* CONF_HW_RXTX_RATE_MCS4 */
3264 3, /* CONF_HW_RXTX_RATE_MCS3 */
3265 2, /* CONF_HW_RXTX_RATE_MCS2 */
3266 1, /* CONF_HW_RXTX_RATE_MCS1 */
3267 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003268
3269 11, /* CONF_HW_RXTX_RATE_54 */
3270 10, /* CONF_HW_RXTX_RATE_48 */
3271 9, /* CONF_HW_RXTX_RATE_36 */
3272 8, /* CONF_HW_RXTX_RATE_24 */
3273
3274 /* TI-specific rate */
3275 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3276
3277 7, /* CONF_HW_RXTX_RATE_18 */
3278 6, /* CONF_HW_RXTX_RATE_12 */
3279 3, /* CONF_HW_RXTX_RATE_11 */
3280 5, /* CONF_HW_RXTX_RATE_9 */
3281 4, /* CONF_HW_RXTX_RATE_6 */
3282 2, /* CONF_HW_RXTX_RATE_5_5 */
3283 1, /* CONF_HW_RXTX_RATE_2 */
3284 0 /* CONF_HW_RXTX_RATE_1 */
3285};
3286
Shahar Levie8b03a22010-10-13 16:09:39 +02003287/* 11n STA capabilities */
3288#define HW_RX_HIGHEST_RATE 72
3289
Shahar Levi00d20102010-11-08 11:20:10 +00003290#ifdef CONFIG_WL12XX_HT
3291#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003292 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3293 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003294 .ht_supported = true, \
3295 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3296 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3297 .mcs = { \
3298 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3299 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3300 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3301 }, \
3302}
Shahar Levi18357852010-10-13 16:09:41 +02003303#else
Shahar Levi00d20102010-11-08 11:20:10 +00003304#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003305 .ht_supported = false, \
3306}
3307#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003308
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003309/* can't be const, mac80211 writes to this */
3310static struct ieee80211_supported_band wl1271_band_2ghz = {
3311 .channels = wl1271_channels,
3312 .n_channels = ARRAY_SIZE(wl1271_channels),
3313 .bitrates = wl1271_rates,
3314 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003315 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316};
3317
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003318/* 5 GHz data rates for WL1273 */
3319static struct ieee80211_rate wl1271_rates_5ghz[] = {
3320 { .bitrate = 60,
3321 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3322 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3323 { .bitrate = 90,
3324 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3325 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3326 { .bitrate = 120,
3327 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3328 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3329 { .bitrate = 180,
3330 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3331 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3332 { .bitrate = 240,
3333 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3334 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3335 { .bitrate = 360,
3336 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3337 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3338 { .bitrate = 480,
3339 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3340 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3341 { .bitrate = 540,
3342 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3343 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3344};
3345
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003346/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003347static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003348 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003349 { .hw_value = 8, .center_freq = 5040},
3350 { .hw_value = 9, .center_freq = 5045},
3351 { .hw_value = 11, .center_freq = 5055},
3352 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003353 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003354 { .hw_value = 34, .center_freq = 5170},
3355 { .hw_value = 36, .center_freq = 5180},
3356 { .hw_value = 38, .center_freq = 5190},
3357 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003358 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003359 { .hw_value = 44, .center_freq = 5220},
3360 { .hw_value = 46, .center_freq = 5230},
3361 { .hw_value = 48, .center_freq = 5240},
3362 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003363 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003364 { .hw_value = 60, .center_freq = 5300},
3365 { .hw_value = 64, .center_freq = 5320},
3366 { .hw_value = 100, .center_freq = 5500},
3367 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003368 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003369 { .hw_value = 112, .center_freq = 5560},
3370 { .hw_value = 116, .center_freq = 5580},
3371 { .hw_value = 120, .center_freq = 5600},
3372 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003373 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003374 { .hw_value = 132, .center_freq = 5660},
3375 { .hw_value = 136, .center_freq = 5680},
3376 { .hw_value = 140, .center_freq = 5700},
3377 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003378 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003379 { .hw_value = 157, .center_freq = 5785},
3380 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003381 { .hw_value = 165, .center_freq = 5825},
3382};
3383
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003384/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003385static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003386 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003387 7, /* CONF_HW_RXTX_RATE_MCS7 */
3388 6, /* CONF_HW_RXTX_RATE_MCS6 */
3389 5, /* CONF_HW_RXTX_RATE_MCS5 */
3390 4, /* CONF_HW_RXTX_RATE_MCS4 */
3391 3, /* CONF_HW_RXTX_RATE_MCS3 */
3392 2, /* CONF_HW_RXTX_RATE_MCS2 */
3393 1, /* CONF_HW_RXTX_RATE_MCS1 */
3394 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003395
3396 7, /* CONF_HW_RXTX_RATE_54 */
3397 6, /* CONF_HW_RXTX_RATE_48 */
3398 5, /* CONF_HW_RXTX_RATE_36 */
3399 4, /* CONF_HW_RXTX_RATE_24 */
3400
3401 /* TI-specific rate */
3402 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3403
3404 3, /* CONF_HW_RXTX_RATE_18 */
3405 2, /* CONF_HW_RXTX_RATE_12 */
3406 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3407 1, /* CONF_HW_RXTX_RATE_9 */
3408 0, /* CONF_HW_RXTX_RATE_6 */
3409 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3410 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3411 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3412};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003413
3414static struct ieee80211_supported_band wl1271_band_5ghz = {
3415 .channels = wl1271_channels_5ghz,
3416 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3417 .bitrates = wl1271_rates_5ghz,
3418 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003419 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003420};
3421
Tobias Klausera0ea9492010-05-20 10:38:11 +02003422static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003423 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3424 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3425};
3426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003427static const struct ieee80211_ops wl1271_ops = {
3428 .start = wl1271_op_start,
3429 .stop = wl1271_op_stop,
3430 .add_interface = wl1271_op_add_interface,
3431 .remove_interface = wl1271_op_remove_interface,
3432 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003433 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003434 .configure_filter = wl1271_op_configure_filter,
3435 .tx = wl1271_op_tx,
3436 .set_key = wl1271_op_set_key,
3437 .hw_scan = wl1271_op_hw_scan,
3438 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003439 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003441 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003442 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003443 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003444 .sta_add = wl1271_op_sta_add,
3445 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003446 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003447 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003448 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449};
3450
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003451
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003452u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003453{
3454 u8 idx;
3455
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003456 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003457
3458 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3459 wl1271_error("Illegal RX rate from HW: %d", rate);
3460 return 0;
3461 }
3462
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003463 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003464 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3465 wl1271_error("Unsupported RX rate from HW: %d", rate);
3466 return 0;
3467 }
3468
3469 return idx;
3470}
3471
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003472static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3473 struct device_attribute *attr,
3474 char *buf)
3475{
3476 struct wl1271 *wl = dev_get_drvdata(dev);
3477 ssize_t len;
3478
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003479 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003480
3481 mutex_lock(&wl->mutex);
3482 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3483 wl->sg_enabled);
3484 mutex_unlock(&wl->mutex);
3485
3486 return len;
3487
3488}
3489
3490static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3491 struct device_attribute *attr,
3492 const char *buf, size_t count)
3493{
3494 struct wl1271 *wl = dev_get_drvdata(dev);
3495 unsigned long res;
3496 int ret;
3497
Luciano Coelho6277ed62011-04-01 17:49:54 +03003498 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003499 if (ret < 0) {
3500 wl1271_warning("incorrect value written to bt_coex_mode");
3501 return count;
3502 }
3503
3504 mutex_lock(&wl->mutex);
3505
3506 res = !!res;
3507
3508 if (res == wl->sg_enabled)
3509 goto out;
3510
3511 wl->sg_enabled = res;
3512
3513 if (wl->state == WL1271_STATE_OFF)
3514 goto out;
3515
Ido Yariva6208652011-03-01 15:14:41 +02003516 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003517 if (ret < 0)
3518 goto out;
3519
3520 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3521 wl1271_ps_elp_sleep(wl);
3522
3523 out:
3524 mutex_unlock(&wl->mutex);
3525 return count;
3526}
3527
3528static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3529 wl1271_sysfs_show_bt_coex_state,
3530 wl1271_sysfs_store_bt_coex_state);
3531
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003532static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3533 struct device_attribute *attr,
3534 char *buf)
3535{
3536 struct wl1271 *wl = dev_get_drvdata(dev);
3537 ssize_t len;
3538
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003539 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003540
3541 mutex_lock(&wl->mutex);
3542 if (wl->hw_pg_ver >= 0)
3543 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3544 else
3545 len = snprintf(buf, len, "n/a\n");
3546 mutex_unlock(&wl->mutex);
3547
3548 return len;
3549}
3550
3551static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3552 wl1271_sysfs_show_hw_pg_ver, NULL);
3553
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003554int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003555{
3556 int ret;
3557
3558 if (wl->mac80211_registered)
3559 return 0;
3560
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003561 ret = wl1271_fetch_nvs(wl);
3562 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003563 /* NOTE: The wl->nvs->nvs element must be first, in
3564 * order to simplify the casting, we assume it is at
3565 * the beginning of the wl->nvs structure.
3566 */
3567 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003568
3569 wl->mac_addr[0] = nvs_ptr[11];
3570 wl->mac_addr[1] = nvs_ptr[10];
3571 wl->mac_addr[2] = nvs_ptr[6];
3572 wl->mac_addr[3] = nvs_ptr[5];
3573 wl->mac_addr[4] = nvs_ptr[4];
3574 wl->mac_addr[5] = nvs_ptr[3];
3575 }
3576
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003577 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3578
3579 ret = ieee80211_register_hw(wl->hw);
3580 if (ret < 0) {
3581 wl1271_error("unable to register mac80211 hw: %d", ret);
3582 return ret;
3583 }
3584
3585 wl->mac80211_registered = true;
3586
Eliad Pellerd60080a2010-11-24 12:53:16 +02003587 wl1271_debugfs_init(wl);
3588
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003589 register_netdevice_notifier(&wl1271_dev_notifier);
3590
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003591 wl1271_notice("loaded");
3592
3593 return 0;
3594}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003595EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003596
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003597void wl1271_unregister_hw(struct wl1271 *wl)
3598{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003599 if (wl->state == WL1271_STATE_PLT)
3600 __wl1271_plt_stop(wl);
3601
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003602 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003603 ieee80211_unregister_hw(wl->hw);
3604 wl->mac80211_registered = false;
3605
3606}
3607EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3608
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003609int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003610{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003611 static const u32 cipher_suites[] = {
3612 WLAN_CIPHER_SUITE_WEP40,
3613 WLAN_CIPHER_SUITE_WEP104,
3614 WLAN_CIPHER_SUITE_TKIP,
3615 WLAN_CIPHER_SUITE_CCMP,
3616 WL1271_CIPHER_SUITE_GEM,
3617 };
3618
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003619 /* The tx descriptor buffer and the TKIP space. */
3620 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3621 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003622
3623 /* unit us */
3624 /* FIXME: find a proper value */
3625 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003626 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003627
3628 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003629 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003630 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003631 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003632 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003633 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003634 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003635 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003636
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003637 wl->hw->wiphy->cipher_suites = cipher_suites;
3638 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3639
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003640 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003641 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003642 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003643 /*
3644 * Maximum length of elements in scanning probe request templates
3645 * should be the maximum length possible for a template, without
3646 * the IEEE80211 header of the template
3647 */
3648 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3649 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003650
Luciano Coelho4a31c112011-03-21 23:16:14 +02003651 /* make sure all our channels fit in the scanned_ch bitmask */
3652 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3653 ARRAY_SIZE(wl1271_channels_5ghz) >
3654 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003655 /*
3656 * We keep local copies of the band structs because we need to
3657 * modify them on a per-device basis.
3658 */
3659 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3660 sizeof(wl1271_band_2ghz));
3661 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3662 sizeof(wl1271_band_5ghz));
3663
3664 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3665 &wl->bands[IEEE80211_BAND_2GHZ];
3666 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3667 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003668
Kalle Valo12bd8942010-03-18 12:26:33 +02003669 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003670 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003671
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003672 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3673
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003674 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003675
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003676 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3677
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003678 wl->hw->max_rx_aggregation_subframes = 8;
3679
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003680 return 0;
3681}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003682EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003683
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003684#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003685
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003686struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003687{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003688 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003689 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003690 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003691 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003692 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003693
3694 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3695 if (!hw) {
3696 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003697 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003698 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699 }
3700
Julia Lawall929ebd32010-05-15 23:16:39 +02003701 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003702 if (!plat_dev) {
3703 wl1271_error("could not allocate platform_device");
3704 ret = -ENOMEM;
3705 goto err_plat_alloc;
3706 }
3707
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003708 wl = hw->priv;
3709 memset(wl, 0, sizeof(*wl));
3710
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003711 INIT_LIST_HEAD(&wl->list);
3712
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003713 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003714 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003716 for (i = 0; i < NUM_TX_QUEUES; i++)
3717 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003718
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003719 for (i = 0; i < NUM_TX_QUEUES; i++)
3720 for (j = 0; j < AP_MAX_LINKS; j++)
3721 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3722
Ido Yariva6208652011-03-01 15:14:41 +02003723 skb_queue_head_init(&wl->deferred_rx_queue);
3724 skb_queue_head_init(&wl->deferred_tx_queue);
3725
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003726 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003727 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003728 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003729 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3730 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3731 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003732 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003733 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003734 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003735 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003736 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3737 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003738 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003739 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003740 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003741 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003742 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003743 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003744 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003745 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003746 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003747 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003748 wl->bss_type = MAX_BSS_TYPE;
3749 wl->set_bss_type = MAX_BSS_TYPE;
3750 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003751 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003752 wl->ap_ps_map = 0;
3753 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003754 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003755 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003756
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003757 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003758 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003759 wl->tx_frames[i] = NULL;
3760
3761 spin_lock_init(&wl->wl_lock);
3762
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003763 wl->state = WL1271_STATE_OFF;
3764 mutex_init(&wl->mutex);
3765
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003766 /* Apply default driver configuration. */
3767 wl1271_conf_init(wl);
3768
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003769 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3770 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3771 if (!wl->aggr_buf) {
3772 ret = -ENOMEM;
3773 goto err_hw;
3774 }
3775
Ido Yariv990f5de2011-03-31 10:06:59 +02003776 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3777 if (!wl->dummy_packet) {
3778 ret = -ENOMEM;
3779 goto err_aggr;
3780 }
3781
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003782 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003783 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003784 if (ret) {
3785 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003786 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003787 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003788 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003789
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003790 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003791 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003792 if (ret < 0) {
3793 wl1271_error("failed to create sysfs file bt_coex_state");
3794 goto err_platform;
3795 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003796
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003797 /* Create sysfs file to get HW PG version */
3798 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3799 if (ret < 0) {
3800 wl1271_error("failed to create sysfs file hw_pg_ver");
3801 goto err_bt_coex_state;
3802 }
3803
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003804 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003805
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003806err_bt_coex_state:
3807 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3808
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003809err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003810 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003811
Ido Yariv990f5de2011-03-31 10:06:59 +02003812err_dummy_packet:
3813 dev_kfree_skb(wl->dummy_packet);
3814
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003815err_aggr:
3816 free_pages((unsigned long)wl->aggr_buf, order);
3817
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003818err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003819 wl1271_debugfs_exit(wl);
3820 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003821
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003822err_plat_alloc:
3823 ieee80211_free_hw(hw);
3824
3825err_hw_alloc:
3826
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003827 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003828}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003829EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003830
3831int wl1271_free_hw(struct wl1271 *wl)
3832{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003833 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003834 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003835 free_pages((unsigned long)wl->aggr_buf,
3836 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003837 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003838
3839 wl1271_debugfs_exit(wl);
3840
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003841 vfree(wl->fw);
3842 wl->fw = NULL;
3843 kfree(wl->nvs);
3844 wl->nvs = NULL;
3845
3846 kfree(wl->fw_status);
3847 kfree(wl->tx_res_if);
3848
3849 ieee80211_free_hw(wl->hw);
3850
3851 return 0;
3852}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003853EXPORT_SYMBOL_GPL(wl1271_free_hw);
3854
Guy Eilam491bbd62011-01-12 10:33:29 +01003855u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003856EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003857module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003858MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3859
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003860MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003861MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003862MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");