blob: bc00e52f6445daec57326299829eee976d62a4bf [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
314 .num_probe_reqs = 2,
315 .rssi_threshold = -90,
316 .snr_threshold = 0,
317 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200318 .rf = {
319 .tx_per_channel_power_compensation_2 = {
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 },
322 .tx_per_channel_power_compensation_5 = {
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 },
327 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100328 .ht = {
329 .tx_ba_win_size = 64,
330 .inactivity_timeout = 10000,
331 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200332 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200333 .num_stations = 1,
334 .ssid_profiles = 1,
335 .rx_block_num = 70,
336 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300337 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200338 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200339 .min_req_rx_blocks = 22,
340 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200341 },
342 .mem_wl128x = {
343 .num_stations = 1,
344 .ssid_profiles = 1,
345 .rx_block_num = 40,
346 .tx_min_block_num = 40,
347 .dynamic_memory = 1,
348 .min_req_tx_blocks = 45,
349 .min_req_rx_blocks = 22,
350 .tx_min = 27,
351 },
Shahar Leviff868432011-04-11 15:41:46 +0300352 .fm_coex = {
353 .enable = true,
354 .swallow_period = 5,
355 .n_divider_fref_set_1 = 0xff, /* default */
356 .n_divider_fref_set_2 = 12,
357 .m_divider_fref_set_1 = 148,
358 .m_divider_fref_set_2 = 0xffff, /* default */
359 .coex_pll_stabilization_time = 0xffffffff, /* default */
360 .ldo_stabilization_time = 0xffff, /* default */
361 .fm_disturbed_band_margin = 0xff, /* default */
362 .swallow_clk_diff = 0xff, /* default */
363 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300364 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300365};
366
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300367static void __wl1271_op_remove_interface(struct wl1271 *wl,
368 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200369static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200370
371
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200372static void wl1271_device_release(struct device *dev)
373{
374
375}
376
377static struct platform_device wl1271_device = {
378 .name = "wl1271",
379 .id = -1,
380
381 /* device model insists to have a release function */
382 .dev = {
383 .release = wl1271_device_release,
384 },
385};
386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300390static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
391 void *arg)
392{
393 struct net_device *dev = arg;
394 struct wireless_dev *wdev;
395 struct wiphy *wiphy;
396 struct ieee80211_hw *hw;
397 struct wl1271 *wl;
398 struct wl1271 *wl_temp;
399 int ret = 0;
400
401 /* Check that this notification is for us. */
402 if (what != NETDEV_CHANGE)
403 return NOTIFY_DONE;
404
405 wdev = dev->ieee80211_ptr;
406 if (wdev == NULL)
407 return NOTIFY_DONE;
408
409 wiphy = wdev->wiphy;
410 if (wiphy == NULL)
411 return NOTIFY_DONE;
412
413 hw = wiphy_priv(wiphy);
414 if (hw == NULL)
415 return NOTIFY_DONE;
416
417 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200418 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300419 list_for_each_entry(wl, &wl_list, list) {
420 if (wl == wl_temp)
421 break;
422 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200423 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300424 if (wl != wl_temp)
425 return NOTIFY_DONE;
426
427 mutex_lock(&wl->mutex);
428
429 if (wl->state == WL1271_STATE_OFF)
430 goto out;
431
432 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
433 goto out;
434
Ido Yariva6208652011-03-01 15:14:41 +0200435 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300436 if (ret < 0)
437 goto out;
438
439 if ((dev->operstate == IF_OPER_UP) &&
440 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
441 wl1271_cmd_set_sta_state(wl);
442 wl1271_info("Association completed.");
443 }
444
445 wl1271_ps_elp_sleep(wl);
446
447out:
448 mutex_unlock(&wl->mutex);
449
450 return NOTIFY_OK;
451}
452
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100453static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200454 struct regulatory_request *request)
455{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100456 struct ieee80211_supported_band *band;
457 struct ieee80211_channel *ch;
458 int i;
459
460 band = wiphy->bands[IEEE80211_BAND_5GHZ];
461 for (i = 0; i < band->n_channels; i++) {
462 ch = &band->channels[i];
463 if (ch->flags & IEEE80211_CHAN_DISABLED)
464 continue;
465
466 if (ch->flags & IEEE80211_CHAN_RADAR)
467 ch->flags |= IEEE80211_CHAN_NO_IBSS |
468 IEEE80211_CHAN_PASSIVE_SCAN;
469
470 }
471
472 return 0;
473}
474
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300475static void wl1271_conf_init(struct wl1271 *wl)
476{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300477
478 /*
479 * This function applies the default configuration to the driver. This
480 * function is invoked upon driver load (spi probe.)
481 *
482 * The configuration is stored in a run-time structure in order to
483 * facilitate for run-time adjustment of any of the parameters. Making
484 * changes to the configuration structure will apply the new values on
485 * the next interface up (wl1271_op_start.)
486 */
487
488 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300489 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300490}
491
492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493static int wl1271_plt_init(struct wl1271 *wl)
494{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200495 struct conf_tx_ac_category *conf_ac;
496 struct conf_tx_tid *conf_tid;
497 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498
Shahar Levi49d750ca2011-03-06 16:32:09 +0200499 if (wl->chip.id == CHIP_ID_1283_PG20)
500 ret = wl128x_cmd_general_parms(wl);
501 else
502 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200503 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200504 return ret;
505
Shahar Levi49d750ca2011-03-06 16:32:09 +0200506 if (wl->chip.id == CHIP_ID_1283_PG20)
507 ret = wl128x_cmd_radio_parms(wl);
508 else
509 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200510 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200511 return ret;
512
Shahar Levi49d750ca2011-03-06 16:32:09 +0200513 if (wl->chip.id != CHIP_ID_1283_PG20) {
514 ret = wl1271_cmd_ext_radio_parms(wl);
515 if (ret < 0)
516 return ret;
517 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200518 if (ret < 0)
519 return ret;
520
Shahar Levi48a61472011-03-06 16:32:08 +0200521 /* Chip-specific initializations */
522 ret = wl1271_chip_specific_init(wl);
523 if (ret < 0)
524 return ret;
525
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200526 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200527 if (ret < 0)
528 return ret;
529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530 ret = wl1271_acx_init_mem_config(wl);
531 if (ret < 0)
532 return ret;
533
Luciano Coelho12419cc2010-02-18 13:25:44 +0200534 /* PHY layer config */
535 ret = wl1271_init_phy_config(wl);
536 if (ret < 0)
537 goto out_free_memmap;
538
539 ret = wl1271_acx_dco_itrim_params(wl);
540 if (ret < 0)
541 goto out_free_memmap;
542
543 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200544 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200545 if (ret < 0)
546 goto out_free_memmap;
547
548 /* Bluetooth WLAN coexistence */
549 ret = wl1271_init_pta(wl);
550 if (ret < 0)
551 goto out_free_memmap;
552
Shahar Leviff868432011-04-11 15:41:46 +0300553 /* FM WLAN coexistence */
554 ret = wl1271_acx_fm_coex(wl);
555 if (ret < 0)
556 goto out_free_memmap;
557
Luciano Coelho12419cc2010-02-18 13:25:44 +0200558 /* Energy detection */
559 ret = wl1271_init_energy_detection(wl);
560 if (ret < 0)
561 goto out_free_memmap;
562
Gery Kahn1ec610e2011-02-01 03:03:08 -0600563 ret = wl1271_acx_sta_mem_cfg(wl);
564 if (ret < 0)
565 goto out_free_memmap;
566
Luciano Coelho12419cc2010-02-18 13:25:44 +0200567 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100568 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200569 if (ret < 0)
570 goto out_free_memmap;
571
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200572 /* Default TID/AC configuration */
573 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200574 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200575 conf_ac = &wl->conf.tx.ac_conf[i];
576 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
577 conf_ac->cw_max, conf_ac->aifsn,
578 conf_ac->tx_op_limit);
579 if (ret < 0)
580 goto out_free_memmap;
581
Luciano Coelho12419cc2010-02-18 13:25:44 +0200582 conf_tid = &wl->conf.tx.tid_conf[i];
583 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
584 conf_tid->channel_type,
585 conf_tid->tsid,
586 conf_tid->ps_scheme,
587 conf_tid->ack_policy,
588 conf_tid->apsd_conf[0],
589 conf_tid->apsd_conf[1]);
590 if (ret < 0)
591 goto out_free_memmap;
592 }
593
Luciano Coelho12419cc2010-02-18 13:25:44 +0200594 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200595 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200597 goto out_free_memmap;
598
599 /* Configure for CAM power saving (ie. always active) */
600 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
601 if (ret < 0)
602 goto out_free_memmap;
603
604 /* configure PM */
605 ret = wl1271_acx_pm_config(wl);
606 if (ret < 0)
607 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608
609 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200610
611 out_free_memmap:
612 kfree(wl->target_mem_map);
613 wl->target_mem_map = NULL;
614
615 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300616}
617
Arik Nemtsovb622d992011-02-23 00:22:31 +0200618static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
619{
620 bool fw_ps;
621
622 /* only regulate station links */
623 if (hlid < WL1271_AP_STA_HLID_START)
624 return;
625
626 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
627
628 /*
629 * Wake up from high level PS if the STA is asleep with too little
630 * blocks in FW or if the STA is awake.
631 */
632 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
633 wl1271_ps_link_end(wl, hlid);
634
635 /* Start high-level PS if the STA is asleep with enough blocks in FW */
636 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
637 wl1271_ps_link_start(wl, hlid, true);
638}
639
640static void wl1271_irq_update_links_status(struct wl1271 *wl,
641 struct wl1271_fw_ap_status *status)
642{
643 u32 cur_fw_ps_map;
644 u8 hlid;
645
646 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
647 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
648 wl1271_debug(DEBUG_PSM,
649 "link ps prev 0x%x cur 0x%x changed 0x%x",
650 wl->ap_fw_ps_map, cur_fw_ps_map,
651 wl->ap_fw_ps_map ^ cur_fw_ps_map);
652
653 wl->ap_fw_ps_map = cur_fw_ps_map;
654 }
655
656 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
657 u8 cnt = status->tx_lnk_free_blks[hlid] -
658 wl->links[hlid].prev_freed_blks;
659
660 wl->links[hlid].prev_freed_blks =
661 status->tx_lnk_free_blks[hlid];
662 wl->links[hlid].allocated_blks -= cnt;
663
664 wl1271_irq_ps_regulate_link(wl, hlid,
665 wl->links[hlid].allocated_blks);
666 }
667}
668
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300669static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200670 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200672 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200673 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200674 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200675 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676 int i;
677
Shahar Levi13b107d2011-03-06 16:32:12 +0200678 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200679 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
680 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200681 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200682 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
683 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200684 }
685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
687 "drv_rx_counter = %d, tx_results_counter = %d)",
688 status->intr,
689 status->fw_rx_counter,
690 status->drv_rx_counter,
691 status->tx_results_counter);
692
693 /* update number of available TX blocks */
694 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200695 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
696 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300697
698 wl->tx_blocks_freed[i] =
699 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200700 }
701
Ido Yarivd2f4d472011-03-31 10:07:00 +0200702 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200703
Ido Yarivd2f4d472011-03-31 10:07:00 +0200704 if (wl->bss_type == BSS_TYPE_AP_BSS) {
705 /* Update num of allocated TX blocks per link and ps status */
706 wl1271_irq_update_links_status(wl, &full_status->ap);
707 wl->tx_blocks_available += freed_blocks;
708 } else {
709 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
710
711 /*
712 * The FW might change the total number of TX memblocks before
713 * we get a notification about blocks being released. Thus, the
714 * available blocks calculation might yield a temporary result
715 * which is lower than the actual available blocks. Keeping in
716 * mind that only blocks that were allocated can be moved from
717 * TX to RX, tx_blocks_available should never decrease here.
718 */
719 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
720 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 }
722
Ido Yariva5225502010-10-12 14:49:10 +0200723 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200724 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200725 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726
727 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200728 getnstimeofday(&ts);
729 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
730 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731}
732
Ido Yariva6208652011-03-01 15:14:41 +0200733static void wl1271_flush_deferred_work(struct wl1271 *wl)
734{
735 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200736
Ido Yariva6208652011-03-01 15:14:41 +0200737 /* Pass all received frames to the network stack */
738 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
739 ieee80211_rx_ni(wl->hw, skb);
740
741 /* Return sent skbs to the network stack */
742 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
743 ieee80211_tx_status(wl->hw, skb);
744}
745
746static void wl1271_netstack_work(struct work_struct *work)
747{
748 struct wl1271 *wl =
749 container_of(work, struct wl1271, netstack_work);
750
751 do {
752 wl1271_flush_deferred_work(wl);
753 } while (skb_queue_len(&wl->deferred_rx_queue));
754}
755
756#define WL1271_IRQ_MAX_LOOPS 256
757
758irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300761 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200762 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200763 struct wl1271 *wl = (struct wl1271 *)cookie;
764 bool done = false;
765 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200766 unsigned long flags;
767
768 /* TX might be handled here, avoid redundant work */
769 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
770 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
Ido Yariv341b7cd2011-03-31 10:07:01 +0200772 /*
773 * In case edge triggered interrupt must be used, we cannot iterate
774 * more than once without introducing race conditions with the hardirq.
775 */
776 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
777 loopcount = 1;
778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 mutex_lock(&wl->mutex);
780
781 wl1271_debug(DEBUG_IRQ, "IRQ work");
782
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200783 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784 goto out;
785
Ido Yariva6208652011-03-01 15:14:41 +0200786 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787 if (ret < 0)
788 goto out;
789
Ido Yariva6208652011-03-01 15:14:41 +0200790 while (!done && loopcount--) {
791 /*
792 * In order to avoid a race with the hardirq, clear the flag
793 * before acknowledging the chip. Since the mutex is held,
794 * wl1271_ps_elp_wakeup cannot be called concurrently.
795 */
796 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
797 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200798
799 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200800 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200801 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200802 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200803 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200804 continue;
805 }
806
Eliad Pellerccc83b02010-10-27 14:09:57 +0200807 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
808 wl1271_error("watchdog interrupt received! "
809 "starting recovery.");
810 ieee80211_queue_work(wl->hw, &wl->recovery_work);
811
812 /* restarting the chip. ignore any other interrupt. */
813 goto out;
814 }
815
Ido Yariva6208652011-03-01 15:14:41 +0200816 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200817 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
818
Ido Yariv8aad2462011-03-01 15:14:38 +0200819 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200820
Ido Yariva5225502010-10-12 14:49:10 +0200821 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200822 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200823 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200824 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200825 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200826 /*
827 * In order to avoid starvation of the TX path,
828 * call the work function directly.
829 */
830 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200831 } else {
832 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200833 }
834
Ido Yariv8aad2462011-03-01 15:14:38 +0200835 /* check for tx results */
836 if (wl->fw_status->common.tx_results_counter !=
837 (wl->tx_results_count & 0xff))
838 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200839
840 /* Make sure the deferred queues don't get too long */
841 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
842 skb_queue_len(&wl->deferred_rx_queue);
843 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
844 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200845 }
846
847 if (intr & WL1271_ACX_INTR_EVENT_A) {
848 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
849 wl1271_event_handle(wl, 0);
850 }
851
852 if (intr & WL1271_ACX_INTR_EVENT_B) {
853 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
854 wl1271_event_handle(wl, 1);
855 }
856
857 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
858 wl1271_debug(DEBUG_IRQ,
859 "WL1271_ACX_INTR_INIT_COMPLETE");
860
861 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
862 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863 }
864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865 wl1271_ps_elp_sleep(wl);
866
867out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200868 spin_lock_irqsave(&wl->wl_lock, flags);
869 /* In case TX was not handled here, queue TX work */
870 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
871 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
872 wl->tx_queue_count)
873 ieee80211_queue_work(wl->hw, &wl->tx_work);
874 spin_unlock_irqrestore(&wl->wl_lock, flags);
875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200877
878 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879}
Ido Yariva6208652011-03-01 15:14:41 +0200880EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882static int wl1271_fetch_firmware(struct wl1271 *wl)
883{
884 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200885 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 int ret;
887
Arik Nemtsov166d5042010-10-16 21:44:57 +0200888 switch (wl->bss_type) {
889 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200890 if (wl->chip.id == CHIP_ID_1283_PG20)
891 fw_name = WL128X_AP_FW_NAME;
892 else
893 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200894 break;
895 case BSS_TYPE_IBSS:
896 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200897 if (wl->chip.id == CHIP_ID_1283_PG20)
898 fw_name = WL128X_FW_NAME;
899 else
900 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200901 break;
902 default:
903 wl1271_error("no compatible firmware for bss_type %d",
904 wl->bss_type);
905 return -EINVAL;
906 }
907
908 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
909
910 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
912 if (ret < 0) {
913 wl1271_error("could not get firmware: %d", ret);
914 return ret;
915 }
916
917 if (fw->size % 4) {
918 wl1271_error("firmware size is not multiple of 32 bits: %zu",
919 fw->size);
920 ret = -EILSEQ;
921 goto out;
922 }
923
Arik Nemtsov166d5042010-10-16 21:44:57 +0200924 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300926 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927
928 if (!wl->fw) {
929 wl1271_error("could not allocate memory for the firmware");
930 ret = -ENOMEM;
931 goto out;
932 }
933
934 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200935 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936 ret = 0;
937
938out:
939 release_firmware(fw);
940
941 return ret;
942}
943
944static int wl1271_fetch_nvs(struct wl1271 *wl)
945{
946 const struct firmware *fw;
947 int ret;
948
Shahar Levi5aa42342011-03-06 16:32:07 +0200949 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950
951 if (ret < 0) {
952 wl1271_error("could not get nvs file: %d", ret);
953 return ret;
954 }
955
Shahar Levibc765bf2011-03-06 16:32:10 +0200956 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957
958 if (!wl->nvs) {
959 wl1271_error("could not allocate memory for the nvs file");
960 ret = -ENOMEM;
961 goto out;
962 }
963
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200964 wl->nvs_len = fw->size;
965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966out:
967 release_firmware(fw);
968
969 return ret;
970}
971
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200972static void wl1271_recovery_work(struct work_struct *work)
973{
974 struct wl1271 *wl =
975 container_of(work, struct wl1271, recovery_work);
976
977 mutex_lock(&wl->mutex);
978
979 if (wl->state != WL1271_STATE_ON)
980 goto out;
981
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300982 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
983 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200984
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200985 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
986 ieee80211_connection_loss(wl->vif);
987
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300988 /* Prevent spurious TX during FW restart */
989 ieee80211_stop_queues(wl->hw);
990
Luciano Coelho33c2c062011-05-10 14:46:02 +0300991 if (wl->sched_scanning) {
992 ieee80211_sched_scan_stopped(wl->hw);
993 wl->sched_scanning = false;
994 }
995
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200996 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300997 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200998 ieee80211_restart_hw(wl->hw);
999
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001000 /*
1001 * Its safe to enable TX now - the queues are stopped after a request
1002 * to restart the HW.
1003 */
1004 ieee80211_wake_queues(wl->hw);
1005
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001006out:
1007 mutex_unlock(&wl->mutex);
1008}
1009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010static void wl1271_fw_wakeup(struct wl1271 *wl)
1011{
1012 u32 elp_reg;
1013
1014 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001015 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016}
1017
1018static int wl1271_setup(struct wl1271 *wl)
1019{
1020 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1021 if (!wl->fw_status)
1022 return -ENOMEM;
1023
1024 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1025 if (!wl->tx_res_if) {
1026 kfree(wl->fw_status);
1027 return -ENOMEM;
1028 }
1029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 return 0;
1031}
1032
1033static int wl1271_chip_wakeup(struct wl1271 *wl)
1034{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001035 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 int ret = 0;
1037
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001038 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001039 ret = wl1271_power_on(wl);
1040 if (ret < 0)
1041 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001043 wl1271_io_reset(wl);
1044 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 /* We don't need a real memory partition here, because we only want
1047 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001048 memset(&partition, 0, sizeof(partition));
1049 partition.reg.start = REGISTERS_BASE;
1050 partition.reg.size = REGISTERS_DOWN_SIZE;
1051 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
1053 /* ELP module wake up */
1054 wl1271_fw_wakeup(wl);
1055
1056 /* whal_FwCtrl_BootSm() */
1057
1058 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001059 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060
1061 /* 1. check if chip id is valid */
1062
1063 switch (wl->chip.id) {
1064 case CHIP_ID_1271_PG10:
1065 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1066 wl->chip.id);
1067
1068 ret = wl1271_setup(wl);
1069 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001070 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 break;
1072 case CHIP_ID_1271_PG20:
1073 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1074 wl->chip.id);
1075
Shahar Levi564f5952011-04-04 10:20:39 +03001076 /* end-of-transaction flag should be set in wl127x AP mode */
1077 if (wl->bss_type == BSS_TYPE_AP_BSS)
1078 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1079
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = wl1271_setup(wl);
1081 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001082 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001084 case CHIP_ID_1283_PG20:
1085 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1086 wl->chip.id);
1087
1088 ret = wl1271_setup(wl);
1089 if (ret < 0)
1090 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001091 if (wl1271_set_block_size(wl))
1092 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001093 break;
1094 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001096 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001098 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 }
1100
Arik Nemtsov166d5042010-10-16 21:44:57 +02001101 /* Make sure the firmware type matches the BSS type */
1102 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103 ret = wl1271_fetch_firmware(wl);
1104 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001105 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 }
1107
1108 /* No NVS from netlink, try to get it from the filesystem */
1109 if (wl->nvs == NULL) {
1110 ret = wl1271_fetch_nvs(wl);
1111 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001112 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 }
1114
1115out:
1116 return ret;
1117}
1118
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001119static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1120{
1121 unsigned int quirks = 0;
1122 unsigned int *fw_ver = wl->chip.fw_ver;
1123
1124 /* Only for wl127x */
1125 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1126 /* Check STA version */
1127 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1128 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1129 /* Check AP version */
1130 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1131 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1132 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1133
1134 return quirks;
1135}
1136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137int wl1271_plt_start(struct wl1271 *wl)
1138{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001139 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140 int ret;
1141
1142 mutex_lock(&wl->mutex);
1143
1144 wl1271_notice("power up");
1145
1146 if (wl->state != WL1271_STATE_OFF) {
1147 wl1271_error("cannot go into PLT state because not "
1148 "in off state: %d", wl->state);
1149 ret = -EBUSY;
1150 goto out;
1151 }
1152
Arik Nemtsov166d5042010-10-16 21:44:57 +02001153 wl->bss_type = BSS_TYPE_STA_BSS;
1154
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001155 while (retries) {
1156 retries--;
1157 ret = wl1271_chip_wakeup(wl);
1158 if (ret < 0)
1159 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001161 ret = wl1271_boot(wl);
1162 if (ret < 0)
1163 goto power_off;
1164
1165 ret = wl1271_plt_init(wl);
1166 if (ret < 0)
1167 goto irq_disable;
1168
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001169 wl->state = WL1271_STATE_PLT;
1170 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001171 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001172
1173 /* Check if any quirks are needed with older fw versions */
1174 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 goto out;
1176
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001177irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001178 mutex_unlock(&wl->mutex);
1179 /* Unlocking the mutex in the middle of handling is
1180 inherently unsafe. In this case we deem it safe to do,
1181 because we need to let any possibly pending IRQ out of
1182 the system (and while we are WL1271_STATE_OFF the IRQ
1183 work function will not do anything.) Also, any other
1184 possible concurrent operations will fail due to the
1185 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001186 wl1271_disable_interrupts(wl);
1187 wl1271_flush_deferred_work(wl);
1188 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001189 mutex_lock(&wl->mutex);
1190power_off:
1191 wl1271_power_off(wl);
1192 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001194 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1195 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196out:
1197 mutex_unlock(&wl->mutex);
1198
1199 return ret;
1200}
1201
Luciano Coelho4623ec72011-03-21 19:26:41 +02001202static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203{
1204 int ret = 0;
1205
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 wl1271_notice("power down");
1207
1208 if (wl->state != WL1271_STATE_PLT) {
1209 wl1271_error("cannot power down because not in PLT "
1210 "state: %d", wl->state);
1211 ret = -EBUSY;
1212 goto out;
1213 }
1214
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215 wl1271_power_off(wl);
1216
1217 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001218 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001221 wl1271_disable_interrupts(wl);
1222 wl1271_flush_deferred_work(wl);
1223 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001224 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001225 mutex_lock(&wl->mutex);
1226out:
1227 return ret;
1228}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001229
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001230int wl1271_plt_stop(struct wl1271 *wl)
1231{
1232 int ret;
1233
1234 mutex_lock(&wl->mutex);
1235 ret = __wl1271_plt_stop(wl);
1236 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237 return ret;
1238}
1239
Johannes Berg7bb45682011-02-24 14:42:06 +01001240static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241{
1242 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001243 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001244 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001245 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
Ido Yarivb07d4032011-03-01 15:14:43 +02001247 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1248
1249 if (wl->bss_type == BSS_TYPE_AP_BSS)
1250 hlid = wl1271_tx_get_hlid(skb);
1251
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001252 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001253
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001254 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001255
1256 /*
1257 * The workqueue is slow to process the tx_queue and we need stop
1258 * the queue here, otherwise the queue will get too long.
1259 */
1260 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1261 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1262 ieee80211_stop_queues(wl->hw);
1263 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1264 }
1265
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001266 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001267 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001268 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1269 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1270 } else {
1271 skb_queue_tail(&wl->tx_queue[q], skb);
1272 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 /*
1275 * The chip specific setup must run before the first TX packet -
1276 * before that, the tx_work will not be initialized!
1277 */
1278
Ido Yarivb07d4032011-03-01 15:14:43 +02001279 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1280 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001281 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001282
1283 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284}
1285
Shahar Leviae47c452011-03-06 16:32:14 +02001286int wl1271_tx_dummy_packet(struct wl1271 *wl)
1287{
Ido Yariv990f5de2011-03-31 10:06:59 +02001288 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001289
Ido Yariv990f5de2011-03-31 10:06:59 +02001290 spin_lock_irqsave(&wl->wl_lock, flags);
1291 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1292 wl->tx_queue_count++;
1293 spin_unlock_irqrestore(&wl->wl_lock, flags);
1294
1295 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1296 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1297 wl1271_tx_work_locked(wl);
1298
1299 /*
1300 * If the FW TX is busy, TX work will be scheduled by the threaded
1301 * interrupt handler function
1302 */
1303 return 0;
1304}
1305
1306/*
1307 * The size of the dummy packet should be at least 1400 bytes. However, in
1308 * order to minimize the number of bus transactions, aligning it to 512 bytes
1309 * boundaries could be beneficial, performance wise
1310 */
1311#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1312
Luciano Coelhocf27d862011-04-01 21:08:23 +03001313static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001314{
1315 struct sk_buff *skb;
1316 struct ieee80211_hdr_3addr *hdr;
1317 unsigned int dummy_packet_size;
1318
1319 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1320 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1321
1322 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001323 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001324 wl1271_warning("Failed to allocate a dummy packet skb");
1325 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001326 }
1327
1328 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1329
1330 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1331 memset(hdr, 0, sizeof(*hdr));
1332 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001333 IEEE80211_STYPE_NULLFUNC |
1334 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001335
Ido Yariv990f5de2011-03-31 10:06:59 +02001336 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001337
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001338 /* Dummy packets require the TID to be management */
1339 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001340
1341 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001342 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001343 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001344
Ido Yariv990f5de2011-03-31 10:06:59 +02001345 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001346}
1347
Ido Yariv990f5de2011-03-31 10:06:59 +02001348
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001349static struct notifier_block wl1271_dev_notifier = {
1350 .notifier_call = wl1271_dev_notify,
1351};
1352
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001353#ifdef CONFIG_PM
Eliad Peller94390642011-05-13 11:57:13 +03001354static int wl1271_configure_suspend(struct wl1271 *wl)
1355{
1356 int ret;
1357
1358 if (wl->bss_type != BSS_TYPE_STA_BSS)
1359 return 0;
1360
1361 mutex_lock(&wl->mutex);
1362
1363 ret = wl1271_ps_elp_wakeup(wl);
1364 if (ret < 0)
1365 goto out_unlock;
1366
1367 /* enter psm if needed*/
1368 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1369 DECLARE_COMPLETION_ONSTACK(compl);
1370
1371 wl->ps_compl = &compl;
1372 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1373 wl->basic_rate, true);
1374 if (ret < 0)
1375 goto out_sleep;
1376
1377 /* we must unlock here so we will be able to get events */
1378 wl1271_ps_elp_sleep(wl);
1379 mutex_unlock(&wl->mutex);
1380
1381 ret = wait_for_completion_timeout(
1382 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1383 if (ret <= 0) {
1384 wl1271_warning("couldn't enter ps mode!");
1385 ret = -EBUSY;
1386 goto out;
1387 }
1388
1389 /* take mutex again, and wakeup */
1390 mutex_lock(&wl->mutex);
1391
1392 ret = wl1271_ps_elp_wakeup(wl);
1393 if (ret < 0)
1394 goto out_unlock;
1395 }
1396out_sleep:
1397 wl1271_ps_elp_sleep(wl);
1398out_unlock:
1399 mutex_unlock(&wl->mutex);
1400out:
1401 return ret;
1402
1403}
1404
1405static void wl1271_configure_resume(struct wl1271 *wl)
1406{
1407 int ret;
1408
1409 if (wl->bss_type != BSS_TYPE_STA_BSS)
1410 return;
1411
1412 mutex_lock(&wl->mutex);
1413 ret = wl1271_ps_elp_wakeup(wl);
1414 if (ret < 0)
1415 goto out;
1416
1417 /* exit psm if it wasn't configured */
1418 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1419 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1420 wl->basic_rate, true);
1421
1422 wl1271_ps_elp_sleep(wl);
1423out:
1424 mutex_unlock(&wl->mutex);
1425}
1426
Eliad Peller402e48612011-05-13 11:57:09 +03001427static int wl1271_op_suspend(struct ieee80211_hw *hw,
1428 struct cfg80211_wowlan *wow)
1429{
1430 struct wl1271 *wl = hw->priv;
1431 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1432 wl->wow_enabled = !!wow;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001433 if (wl->wow_enabled) {
Eliad Peller94390642011-05-13 11:57:13 +03001434 int ret;
1435 ret = wl1271_configure_suspend(wl);
1436 if (ret < 0) {
1437 wl1271_warning("couldn't prepare device to suspend");
1438 return ret;
1439 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001440 /* flush any remaining work */
1441 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1442 flush_delayed_work(&wl->scan_complete_work);
1443
1444 /*
1445 * disable and re-enable interrupts in order to flush
1446 * the threaded_irq
1447 */
1448 wl1271_disable_interrupts(wl);
1449
1450 /*
1451 * set suspended flag to avoid triggering a new threaded_irq
1452 * work. no need for spinlock as interrupts are disabled.
1453 */
1454 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1455
1456 wl1271_enable_interrupts(wl);
1457 flush_work(&wl->tx_work);
1458 flush_delayed_work(&wl->pspoll_work);
1459 flush_delayed_work(&wl->elp_work);
1460 }
Eliad Peller402e48612011-05-13 11:57:09 +03001461 return 0;
1462}
1463
1464static int wl1271_op_resume(struct ieee80211_hw *hw)
1465{
1466 struct wl1271 *wl = hw->priv;
1467 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1468 wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001469
1470 /*
1471 * re-enable irq_work enqueuing, and call irq_work directly if
1472 * there is a pending work.
1473 */
1474 if (wl->wow_enabled) {
1475 struct wl1271 *wl = hw->priv;
1476 unsigned long flags;
1477 bool run_irq_work = false;
1478
1479 spin_lock_irqsave(&wl->wl_lock, flags);
1480 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1481 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1482 run_irq_work = true;
1483 spin_unlock_irqrestore(&wl->wl_lock, flags);
1484
1485 if (run_irq_work) {
1486 wl1271_debug(DEBUG_MAC80211,
1487 "run postponed irq_work directly");
1488 wl1271_irq(0, wl);
1489 wl1271_enable_interrupts(wl);
1490 }
Eliad Peller94390642011-05-13 11:57:13 +03001491
1492 wl1271_configure_resume(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001493 }
1494
Eliad Peller402e48612011-05-13 11:57:09 +03001495 return 0;
1496}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001497#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001498
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001499static int wl1271_op_start(struct ieee80211_hw *hw)
1500{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001501 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1502
1503 /*
1504 * We have to delay the booting of the hardware because
1505 * we need to know the local MAC address before downloading and
1506 * initializing the firmware. The MAC address cannot be changed
1507 * after boot, and without the proper MAC address, the firmware
1508 * will not function properly.
1509 *
1510 * The MAC address is first known when the corresponding interface
1511 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001512 *
1513 * In addition, we currently have different firmwares for AP and managed
1514 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001515 */
1516
1517 return 0;
1518}
1519
1520static void wl1271_op_stop(struct ieee80211_hw *hw)
1521{
1522 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1523}
1524
1525static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1526 struct ieee80211_vif *vif)
1527{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001529 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001530 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001532 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001533
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001534 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1535 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536
1537 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001538 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001539 wl1271_debug(DEBUG_MAC80211,
1540 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001541 ret = -EBUSY;
1542 goto out;
1543 }
1544
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001545 /*
1546 * in some very corner case HW recovery scenarios its possible to
1547 * get here before __wl1271_op_remove_interface is complete, so
1548 * opt out if that is the case.
1549 */
1550 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1551 ret = -EBUSY;
1552 goto out;
1553 }
1554
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001555 switch (vif->type) {
1556 case NL80211_IFTYPE_STATION:
1557 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001558 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001559 break;
1560 case NL80211_IFTYPE_ADHOC:
1561 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001562 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001563 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001564 case NL80211_IFTYPE_AP:
1565 wl->bss_type = BSS_TYPE_AP_BSS;
1566 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001567 default:
1568 ret = -EOPNOTSUPP;
1569 goto out;
1570 }
1571
1572 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001573
1574 if (wl->state != WL1271_STATE_OFF) {
1575 wl1271_error("cannot start because not in off state: %d",
1576 wl->state);
1577 ret = -EBUSY;
1578 goto out;
1579 }
1580
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001581 while (retries) {
1582 retries--;
1583 ret = wl1271_chip_wakeup(wl);
1584 if (ret < 0)
1585 goto power_off;
1586
1587 ret = wl1271_boot(wl);
1588 if (ret < 0)
1589 goto power_off;
1590
1591 ret = wl1271_hw_init(wl);
1592 if (ret < 0)
1593 goto irq_disable;
1594
Eliad Peller71125ab2010-10-28 21:46:43 +02001595 booted = true;
1596 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001597
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001598irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001599 mutex_unlock(&wl->mutex);
1600 /* Unlocking the mutex in the middle of handling is
1601 inherently unsafe. In this case we deem it safe to do,
1602 because we need to let any possibly pending IRQ out of
1603 the system (and while we are WL1271_STATE_OFF the IRQ
1604 work function will not do anything.) Also, any other
1605 possible concurrent operations will fail due to the
1606 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001607 wl1271_disable_interrupts(wl);
1608 wl1271_flush_deferred_work(wl);
1609 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001610 mutex_lock(&wl->mutex);
1611power_off:
1612 wl1271_power_off(wl);
1613 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001614
Eliad Peller71125ab2010-10-28 21:46:43 +02001615 if (!booted) {
1616 wl1271_error("firmware boot failed despite %d retries",
1617 WL1271_BOOT_RETRIES);
1618 goto out;
1619 }
1620
1621 wl->vif = vif;
1622 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001623 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001624 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001625
1626 /* update hw/fw version info in wiphy struct */
1627 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001628 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001629 sizeof(wiphy->fw_version));
1630
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001631 /* Check if any quirks are needed with older fw versions */
1632 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1633
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001634 /*
1635 * Now we know if 11a is supported (info from the NVS), so disable
1636 * 11a channels if not supported
1637 */
1638 if (!wl->enable_11a)
1639 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1640
1641 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1642 wl->enable_11a ? "" : "not ");
1643
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001644out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001645 mutex_unlock(&wl->mutex);
1646
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001647 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001648 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001649 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001650 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001652 return ret;
1653}
1654
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001655static void __wl1271_op_remove_interface(struct wl1271 *wl,
1656 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001657{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658 int i;
1659
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001660 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001661
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001662 /* because of hardware recovery, we may get here twice */
1663 if (wl->state != WL1271_STATE_ON)
1664 return;
1665
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001666 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001668 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001669 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001670 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001671
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001672 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001673 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001674 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001675
Luciano Coelho08688d62010-07-08 17:50:07 +03001676 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001677 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001678 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001679 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001680 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001681 }
1682
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001683 /*
1684 * this must be before the cancel_work calls below, so that the work
1685 * functions don't perform further work.
1686 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 wl->state = WL1271_STATE_OFF;
1688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001689 mutex_unlock(&wl->mutex);
1690
Ido Yariva6208652011-03-01 15:14:41 +02001691 wl1271_disable_interrupts(wl);
1692 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001693 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001694 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001696 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001697 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001698
1699 mutex_lock(&wl->mutex);
1700
1701 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001702 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001703 wl1271_power_off(wl);
1704
1705 memset(wl->bssid, 0, ETH_ALEN);
1706 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1707 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001708 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001709 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001710 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001711
1712 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001713 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1715 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001716 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717 wl->tx_results_count = 0;
1718 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001719 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001720 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001721 wl->time_offset = 0;
1722 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001723 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001724 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001725 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001726 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001727 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001728 wl->ap_fw_ps_map = 0;
1729 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001730 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001731
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001732 /*
1733 * this is performed after the cancel_work calls and the associated
1734 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1735 * get executed before all these vars have been reset.
1736 */
1737 wl->flags = 0;
1738
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001739 for (i = 0; i < NUM_TX_QUEUES; i++)
1740 wl->tx_blocks_freed[i] = 0;
1741
1742 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001743
1744 kfree(wl->fw_status);
1745 wl->fw_status = NULL;
1746 kfree(wl->tx_res_if);
1747 wl->tx_res_if = NULL;
1748 kfree(wl->target_mem_map);
1749 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001750}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001751
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001752static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1753 struct ieee80211_vif *vif)
1754{
1755 struct wl1271 *wl = hw->priv;
1756
1757 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001758 /*
1759 * wl->vif can be null here if someone shuts down the interface
1760 * just when hardware recovery has been started.
1761 */
1762 if (wl->vif) {
1763 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001764 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001765 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001766
Juuso Oikarinen67353292010-11-18 15:19:02 +02001767 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001768 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001769}
1770
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001771void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001772{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001773 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001774
1775 /* combine requested filters with current filter config */
1776 filters = wl->filters | filters;
1777
1778 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1779
1780 if (filters & FIF_PROMISC_IN_BSS) {
1781 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1782 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1783 wl->rx_config |= CFG_BSSID_FILTER_EN;
1784 }
1785 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1786 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1787 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1788 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1789 }
1790 if (filters & FIF_OTHER_BSS) {
1791 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1792 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1793 }
1794 if (filters & FIF_CONTROL) {
1795 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1796 wl->rx_filter |= CFG_RX_CTL_EN;
1797 }
1798 if (filters & FIF_FCSFAIL) {
1799 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1800 wl->rx_filter |= CFG_RX_FCS_ERROR;
1801 }
1802}
1803
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001804static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001805{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001806 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001807 /* we need to use a dummy BSSID for now */
1808 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1809 0xad, 0xbe, 0xef };
1810
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001811 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1812
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001813 /* pass through frames from all BSS */
1814 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1815
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001816 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001817 if (ret < 0)
1818 goto out;
1819
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001820 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001821
1822out:
1823 return ret;
1824}
1825
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001826static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001827{
1828 int ret;
1829
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001830 /*
1831 * One of the side effects of the JOIN command is that is clears
1832 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1833 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001834 * Currently the only valid scenario for JOIN during association
1835 * is on roaming, in which case we will also be given new keys.
1836 * Keep the below message for now, unless it starts bothering
1837 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001838 */
1839 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1840 wl1271_info("JOIN while associated.");
1841
1842 if (set_assoc)
1843 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1844
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001845 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1846 if (ret < 0)
1847 goto out;
1848
1849 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1850
1851 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1852 goto out;
1853
1854 /*
1855 * The join command disable the keep-alive mode, shut down its process,
1856 * and also clear the template config, so we need to reset it all after
1857 * the join. The acx_aid starts the keep-alive process, and the order
1858 * of the commands below is relevant.
1859 */
1860 ret = wl1271_acx_keep_alive_mode(wl, true);
1861 if (ret < 0)
1862 goto out;
1863
1864 ret = wl1271_acx_aid(wl, wl->aid);
1865 if (ret < 0)
1866 goto out;
1867
1868 ret = wl1271_cmd_build_klv_null_data(wl);
1869 if (ret < 0)
1870 goto out;
1871
1872 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1873 ACX_KEEP_ALIVE_TPL_VALID);
1874 if (ret < 0)
1875 goto out;
1876
1877out:
1878 return ret;
1879}
1880
1881static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001882{
1883 int ret;
1884
1885 /* to stop listening to a channel, we disconnect */
1886 ret = wl1271_cmd_disconnect(wl);
1887 if (ret < 0)
1888 goto out;
1889
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001890 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001891 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001892
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001893 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001894 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001895
1896out:
1897 return ret;
1898}
1899
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001900static void wl1271_set_band_rate(struct wl1271 *wl)
1901{
1902 if (wl->band == IEEE80211_BAND_2GHZ)
1903 wl->basic_rate_set = wl->conf.tx.basic_rate;
1904 else
1905 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1906}
1907
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001908static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001909{
1910 int ret;
1911
1912 if (idle) {
1913 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1914 ret = wl1271_unjoin(wl);
1915 if (ret < 0)
1916 goto out;
1917 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001918 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001919 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001920 if (ret < 0)
1921 goto out;
1922 ret = wl1271_acx_keep_alive_config(
1923 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1924 ACX_KEEP_ALIVE_TPL_INVALID);
1925 if (ret < 0)
1926 goto out;
1927 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1928 } else {
1929 /* increment the session counter */
1930 wl->session_counter++;
1931 if (wl->session_counter >= SESSION_COUNTER_MAX)
1932 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001933
1934 /* The current firmware only supports sched_scan in idle */
1935 if (wl->sched_scanning) {
1936 wl1271_scan_sched_scan_stop(wl);
1937 ieee80211_sched_scan_stopped(wl->hw);
1938 }
1939
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001940 ret = wl1271_dummy_join(wl);
1941 if (ret < 0)
1942 goto out;
1943 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1944 }
1945
1946out:
1947 return ret;
1948}
1949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001950static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1951{
1952 struct wl1271 *wl = hw->priv;
1953 struct ieee80211_conf *conf = &hw->conf;
1954 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001955 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956
1957 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1958
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001959 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1960 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 channel,
1962 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001963 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001964 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1965 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001967 /*
1968 * mac80211 will go to idle nearly immediately after transmitting some
1969 * frames, such as the deauth. To make sure those frames reach the air,
1970 * wait here until the TX queue is fully flushed.
1971 */
1972 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1973 (conf->flags & IEEE80211_CONF_IDLE))
1974 wl1271_tx_flush(wl);
1975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001976 mutex_lock(&wl->mutex);
1977
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001978 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001979 /* we support configuring the channel and band while off */
1980 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1981 wl->band = conf->channel->band;
1982 wl->channel = channel;
1983 }
1984
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001985 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001986 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001987
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001988 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1989
Ido Yariva6208652011-03-01 15:14:41 +02001990 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001991 if (ret < 0)
1992 goto out;
1993
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001994 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001995 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1996 ((wl->band != conf->channel->band) ||
1997 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001998 wl->band = conf->channel->band;
1999 wl->channel = channel;
2000
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002001 if (!is_ap) {
2002 /*
2003 * FIXME: the mac80211 should really provide a fixed
2004 * rate to use here. for now, just use the smallest
2005 * possible rate for the band as a fixed rate for
2006 * association frames and other control messages.
2007 */
2008 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2009 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002010
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002011 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2012 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002013 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002014 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002015 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002016
2017 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2018 ret = wl1271_join(wl, false);
2019 if (ret < 0)
2020 wl1271_warning("cmd join on channel "
2021 "failed %d", ret);
2022 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002023 }
2024 }
2025
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002026 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2027 ret = wl1271_sta_handle_idle(wl,
2028 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002029 if (ret < 0)
2030 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 }
2032
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002033 /*
2034 * if mac80211 changes the PSM mode, make sure the mode is not
2035 * incorrectly changed after the pspoll failure active window.
2036 */
2037 if (changed & IEEE80211_CONF_CHANGE_PS)
2038 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2039
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002040 if (conf->flags & IEEE80211_CONF_PS &&
2041 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2042 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002043
2044 /*
2045 * We enter PSM only if we're already associated.
2046 * If we're not, we'll enter it when joining an SSID,
2047 * through the bss_info_changed() hook.
2048 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002049 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002050 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002051 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002052 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002053 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002054 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002055 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002056 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002058 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002059
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002060 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002061 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002062 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063 }
2064
2065 if (conf->power_level != wl->power_level) {
2066 ret = wl1271_acx_tx_power(wl, conf->power_level);
2067 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002068 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069
2070 wl->power_level = conf->power_level;
2071 }
2072
2073out_sleep:
2074 wl1271_ps_elp_sleep(wl);
2075
2076out:
2077 mutex_unlock(&wl->mutex);
2078
2079 return ret;
2080}
2081
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002082struct wl1271_filter_params {
2083 bool enabled;
2084 int mc_list_length;
2085 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2086};
2087
Jiri Pirko22bedad2010-04-01 21:22:57 +00002088static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2089 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002090{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002091 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002092 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002093 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002094
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002095 if (unlikely(wl->state == WL1271_STATE_OFF))
2096 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002097
Juuso Oikarinen74441132009-10-13 12:47:53 +03002098 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002099 if (!fp) {
2100 wl1271_error("Out of memory setting filters.");
2101 return 0;
2102 }
2103
2104 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002105 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002106 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2107 fp->enabled = false;
2108 } else {
2109 fp->enabled = true;
2110 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002111 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002112 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002113 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002114 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002115 }
2116
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002117 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002118}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002119
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002120#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2121 FIF_ALLMULTI | \
2122 FIF_FCSFAIL | \
2123 FIF_BCN_PRBRESP_PROMISC | \
2124 FIF_CONTROL | \
2125 FIF_OTHER_BSS)
2126
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002127static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2128 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002129 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002131 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002133 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002134
Arik Nemtsov7d057862010-10-16 19:25:35 +02002135 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2136 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002137
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002138 mutex_lock(&wl->mutex);
2139
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002140 *total &= WL1271_SUPPORTED_FILTERS;
2141 changed &= WL1271_SUPPORTED_FILTERS;
2142
2143 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002144 goto out;
2145
Ido Yariva6208652011-03-01 15:14:41 +02002146 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002147 if (ret < 0)
2148 goto out;
2149
Arik Nemtsov7d057862010-10-16 19:25:35 +02002150 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2151 if (*total & FIF_ALLMULTI)
2152 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2153 else if (fp)
2154 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2155 fp->mc_list,
2156 fp->mc_list_length);
2157 if (ret < 0)
2158 goto out_sleep;
2159 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002161 /* determine, whether supported filter values have changed */
2162 if (changed == 0)
2163 goto out_sleep;
2164
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002165 /* configure filters */
2166 wl->filters = *total;
2167 wl1271_configure_filters(wl, 0);
2168
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002169 /* apply configured filters */
2170 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2171 if (ret < 0)
2172 goto out_sleep;
2173
2174out_sleep:
2175 wl1271_ps_elp_sleep(wl);
2176
2177out:
2178 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002179 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180}
2181
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002182static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2183 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2184 u16 tx_seq_16)
2185{
2186 struct wl1271_ap_key *ap_key;
2187 int i;
2188
2189 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2190
2191 if (key_size > MAX_KEY_SIZE)
2192 return -EINVAL;
2193
2194 /*
2195 * Find next free entry in ap_keys. Also check we are not replacing
2196 * an existing key.
2197 */
2198 for (i = 0; i < MAX_NUM_KEYS; i++) {
2199 if (wl->recorded_ap_keys[i] == NULL)
2200 break;
2201
2202 if (wl->recorded_ap_keys[i]->id == id) {
2203 wl1271_warning("trying to record key replacement");
2204 return -EINVAL;
2205 }
2206 }
2207
2208 if (i == MAX_NUM_KEYS)
2209 return -EBUSY;
2210
2211 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2212 if (!ap_key)
2213 return -ENOMEM;
2214
2215 ap_key->id = id;
2216 ap_key->key_type = key_type;
2217 ap_key->key_size = key_size;
2218 memcpy(ap_key->key, key, key_size);
2219 ap_key->hlid = hlid;
2220 ap_key->tx_seq_32 = tx_seq_32;
2221 ap_key->tx_seq_16 = tx_seq_16;
2222
2223 wl->recorded_ap_keys[i] = ap_key;
2224 return 0;
2225}
2226
2227static void wl1271_free_ap_keys(struct wl1271 *wl)
2228{
2229 int i;
2230
2231 for (i = 0; i < MAX_NUM_KEYS; i++) {
2232 kfree(wl->recorded_ap_keys[i]);
2233 wl->recorded_ap_keys[i] = NULL;
2234 }
2235}
2236
2237static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2238{
2239 int i, ret = 0;
2240 struct wl1271_ap_key *key;
2241 bool wep_key_added = false;
2242
2243 for (i = 0; i < MAX_NUM_KEYS; i++) {
2244 if (wl->recorded_ap_keys[i] == NULL)
2245 break;
2246
2247 key = wl->recorded_ap_keys[i];
2248 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2249 key->id, key->key_type,
2250 key->key_size, key->key,
2251 key->hlid, key->tx_seq_32,
2252 key->tx_seq_16);
2253 if (ret < 0)
2254 goto out;
2255
2256 if (key->key_type == KEY_WEP)
2257 wep_key_added = true;
2258 }
2259
2260 if (wep_key_added) {
2261 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2262 if (ret < 0)
2263 goto out;
2264 }
2265
2266out:
2267 wl1271_free_ap_keys(wl);
2268 return ret;
2269}
2270
2271static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2272 u8 key_size, const u8 *key, u32 tx_seq_32,
2273 u16 tx_seq_16, struct ieee80211_sta *sta)
2274{
2275 int ret;
2276 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2277
2278 if (is_ap) {
2279 struct wl1271_station *wl_sta;
2280 u8 hlid;
2281
2282 if (sta) {
2283 wl_sta = (struct wl1271_station *)sta->drv_priv;
2284 hlid = wl_sta->hlid;
2285 } else {
2286 hlid = WL1271_AP_BROADCAST_HLID;
2287 }
2288
2289 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2290 /*
2291 * We do not support removing keys after AP shutdown.
2292 * Pretend we do to make mac80211 happy.
2293 */
2294 if (action != KEY_ADD_OR_REPLACE)
2295 return 0;
2296
2297 ret = wl1271_record_ap_key(wl, id,
2298 key_type, key_size,
2299 key, hlid, tx_seq_32,
2300 tx_seq_16);
2301 } else {
2302 ret = wl1271_cmd_set_ap_key(wl, action,
2303 id, key_type, key_size,
2304 key, hlid, tx_seq_32,
2305 tx_seq_16);
2306 }
2307
2308 if (ret < 0)
2309 return ret;
2310 } else {
2311 const u8 *addr;
2312 static const u8 bcast_addr[ETH_ALEN] = {
2313 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2314 };
2315
2316 addr = sta ? sta->addr : bcast_addr;
2317
2318 if (is_zero_ether_addr(addr)) {
2319 /* We dont support TX only encryption */
2320 return -EOPNOTSUPP;
2321 }
2322
2323 /* The wl1271 does not allow to remove unicast keys - they
2324 will be cleared automatically on next CMD_JOIN. Ignore the
2325 request silently, as we dont want the mac80211 to emit
2326 an error message. */
2327 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2328 return 0;
2329
2330 ret = wl1271_cmd_set_sta_key(wl, action,
2331 id, key_type, key_size,
2332 key, addr, tx_seq_32,
2333 tx_seq_16);
2334 if (ret < 0)
2335 return ret;
2336
2337 /* the default WEP key needs to be configured at least once */
2338 if (key_type == KEY_WEP) {
2339 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2340 wl->default_key);
2341 if (ret < 0)
2342 return ret;
2343 }
2344 }
2345
2346 return 0;
2347}
2348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002349static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2350 struct ieee80211_vif *vif,
2351 struct ieee80211_sta *sta,
2352 struct ieee80211_key_conf *key_conf)
2353{
2354 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002356 u32 tx_seq_32 = 0;
2357 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 u8 key_type;
2359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002360 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2361
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002362 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002364 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 key_conf->keylen, key_conf->flags);
2366 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 mutex_lock(&wl->mutex);
2369
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002370 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2371 ret = -EAGAIN;
2372 goto out_unlock;
2373 }
2374
Ido Yariva6208652011-03-01 15:14:41 +02002375 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376 if (ret < 0)
2377 goto out_unlock;
2378
Johannes Berg97359d12010-08-10 09:46:38 +02002379 switch (key_conf->cipher) {
2380 case WLAN_CIPHER_SUITE_WEP40:
2381 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382 key_type = KEY_WEP;
2383
2384 key_conf->hw_key_idx = key_conf->keyidx;
2385 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002386 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002387 key_type = KEY_TKIP;
2388
2389 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002390 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2391 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002392 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002393 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002394 key_type = KEY_AES;
2395
2396 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002397 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2398 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002399 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002400 case WL1271_CIPHER_SUITE_GEM:
2401 key_type = KEY_GEM;
2402 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2403 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2404 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002406 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002407
2408 ret = -EOPNOTSUPP;
2409 goto out_sleep;
2410 }
2411
2412 switch (cmd) {
2413 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002414 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2415 key_conf->keyidx, key_type,
2416 key_conf->keylen, key_conf->key,
2417 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002418 if (ret < 0) {
2419 wl1271_error("Could not add or replace key");
2420 goto out_sleep;
2421 }
2422 break;
2423
2424 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002425 ret = wl1271_set_key(wl, KEY_REMOVE,
2426 key_conf->keyidx, key_type,
2427 key_conf->keylen, key_conf->key,
2428 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002429 if (ret < 0) {
2430 wl1271_error("Could not remove key");
2431 goto out_sleep;
2432 }
2433 break;
2434
2435 default:
2436 wl1271_error("Unsupported key cmd 0x%x", cmd);
2437 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002438 break;
2439 }
2440
2441out_sleep:
2442 wl1271_ps_elp_sleep(wl);
2443
2444out_unlock:
2445 mutex_unlock(&wl->mutex);
2446
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447 return ret;
2448}
2449
2450static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002451 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002452 struct cfg80211_scan_request *req)
2453{
2454 struct wl1271 *wl = hw->priv;
2455 int ret;
2456 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002457 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458
2459 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2460
2461 if (req->n_ssids) {
2462 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002463 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464 }
2465
2466 mutex_lock(&wl->mutex);
2467
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002468 if (wl->state == WL1271_STATE_OFF) {
2469 /*
2470 * We cannot return -EBUSY here because cfg80211 will expect
2471 * a call to ieee80211_scan_completed if we do - in this case
2472 * there won't be any call.
2473 */
2474 ret = -EAGAIN;
2475 goto out;
2476 }
2477
Ido Yariva6208652011-03-01 15:14:41 +02002478 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002479 if (ret < 0)
2480 goto out;
2481
Luciano Coelho5924f892010-08-04 03:46:22 +03002482 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483
2484 wl1271_ps_elp_sleep(wl);
2485
2486out:
2487 mutex_unlock(&wl->mutex);
2488
2489 return ret;
2490}
2491
Luciano Coelho33c2c062011-05-10 14:46:02 +03002492static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2493 struct ieee80211_vif *vif,
2494 struct cfg80211_sched_scan_request *req,
2495 struct ieee80211_sched_scan_ies *ies)
2496{
2497 struct wl1271 *wl = hw->priv;
2498 int ret;
2499
2500 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2501
2502 mutex_lock(&wl->mutex);
2503
2504 ret = wl1271_ps_elp_wakeup(wl);
2505 if (ret < 0)
2506 goto out;
2507
2508 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2509 if (ret < 0)
2510 goto out_sleep;
2511
2512 ret = wl1271_scan_sched_scan_start(wl);
2513 if (ret < 0)
2514 goto out_sleep;
2515
2516 wl->sched_scanning = true;
2517
2518out_sleep:
2519 wl1271_ps_elp_sleep(wl);
2520out:
2521 mutex_unlock(&wl->mutex);
2522 return ret;
2523}
2524
2525static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2526 struct ieee80211_vif *vif)
2527{
2528 struct wl1271 *wl = hw->priv;
2529 int ret;
2530
2531 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2532
2533 mutex_lock(&wl->mutex);
2534
2535 ret = wl1271_ps_elp_wakeup(wl);
2536 if (ret < 0)
2537 goto out;
2538
2539 wl1271_scan_sched_scan_stop(wl);
2540
2541 wl1271_ps_elp_sleep(wl);
2542out:
2543 mutex_unlock(&wl->mutex);
2544}
2545
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002546static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2547{
2548 struct wl1271 *wl = hw->priv;
2549 int ret = 0;
2550
2551 mutex_lock(&wl->mutex);
2552
2553 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2554 ret = -EAGAIN;
2555 goto out;
2556 }
2557
Ido Yariva6208652011-03-01 15:14:41 +02002558 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002559 if (ret < 0)
2560 goto out;
2561
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002562 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002563 if (ret < 0)
2564 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2565
2566 wl1271_ps_elp_sleep(wl);
2567
2568out:
2569 mutex_unlock(&wl->mutex);
2570
2571 return ret;
2572}
2573
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002574static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2575{
2576 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002577 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578
2579 mutex_lock(&wl->mutex);
2580
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002581 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2582 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002583 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002584 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002585
Ido Yariva6208652011-03-01 15:14:41 +02002586 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 if (ret < 0)
2588 goto out;
2589
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002590 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002591 if (ret < 0)
2592 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2593
2594 wl1271_ps_elp_sleep(wl);
2595
2596out:
2597 mutex_unlock(&wl->mutex);
2598
2599 return ret;
2600}
2601
Arik Nemtsove78a2872010-10-16 19:07:21 +02002602static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002603 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002604{
Eliad Peller889cb362011-05-01 09:56:45 +03002605 u8 ssid_len;
2606 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2607 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002608
Eliad Peller889cb362011-05-01 09:56:45 +03002609 if (!ptr) {
2610 wl1271_error("No SSID in IEs!");
2611 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002612 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002613
Eliad Peller889cb362011-05-01 09:56:45 +03002614 ssid_len = ptr[1];
2615 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2616 wl1271_error("SSID is too long!");
2617 return -EINVAL;
2618 }
2619
2620 wl->ssid_len = ssid_len;
2621 memcpy(wl->ssid, ptr+2, ssid_len);
2622 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002623}
2624
Arik Nemtsove78a2872010-10-16 19:07:21 +02002625static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2626 struct ieee80211_bss_conf *bss_conf,
2627 u32 changed)
2628{
2629 int ret = 0;
2630
2631 if (changed & BSS_CHANGED_ERP_SLOT) {
2632 if (bss_conf->use_short_slot)
2633 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2634 else
2635 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2636 if (ret < 0) {
2637 wl1271_warning("Set slot time failed %d", ret);
2638 goto out;
2639 }
2640 }
2641
2642 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2643 if (bss_conf->use_short_preamble)
2644 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2645 else
2646 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2647 }
2648
2649 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2650 if (bss_conf->use_cts_prot)
2651 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2652 else
2653 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2654 if (ret < 0) {
2655 wl1271_warning("Set ctsprotect failed %d", ret);
2656 goto out;
2657 }
2658 }
2659
2660out:
2661 return ret;
2662}
2663
2664static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2665 struct ieee80211_vif *vif,
2666 struct ieee80211_bss_conf *bss_conf,
2667 u32 changed)
2668{
2669 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2670 int ret = 0;
2671
2672 if ((changed & BSS_CHANGED_BEACON_INT)) {
2673 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2674 bss_conf->beacon_int);
2675
2676 wl->beacon_int = bss_conf->beacon_int;
2677 }
2678
2679 if ((changed & BSS_CHANGED_BEACON)) {
2680 struct ieee80211_hdr *hdr;
2681 int ieoffset = offsetof(struct ieee80211_mgmt,
2682 u.beacon.variable);
2683 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2684 u16 tmpl_id;
2685
2686 if (!beacon)
2687 goto out;
2688
2689 wl1271_debug(DEBUG_MASTER, "beacon updated");
2690
2691 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2692 if (ret < 0) {
2693 dev_kfree_skb(beacon);
2694 goto out;
2695 }
2696 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2697 CMD_TEMPL_BEACON;
2698 ret = wl1271_cmd_template_set(wl, tmpl_id,
2699 beacon->data,
2700 beacon->len, 0,
2701 wl1271_tx_min_rate_get(wl));
2702 if (ret < 0) {
2703 dev_kfree_skb(beacon);
2704 goto out;
2705 }
2706
2707 hdr = (struct ieee80211_hdr *) beacon->data;
2708 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2709 IEEE80211_STYPE_PROBE_RESP);
2710
2711 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2712 CMD_TEMPL_PROBE_RESPONSE;
2713 ret = wl1271_cmd_template_set(wl,
2714 tmpl_id,
2715 beacon->data,
2716 beacon->len, 0,
2717 wl1271_tx_min_rate_get(wl));
2718 dev_kfree_skb(beacon);
2719 if (ret < 0)
2720 goto out;
2721 }
2722
2723out:
2724 return ret;
2725}
2726
2727/* AP mode changes */
2728static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002729 struct ieee80211_vif *vif,
2730 struct ieee80211_bss_conf *bss_conf,
2731 u32 changed)
2732{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002733 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734
Arik Nemtsove78a2872010-10-16 19:07:21 +02002735 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2736 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002737
Arik Nemtsove78a2872010-10-16 19:07:21 +02002738 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2739 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740
Arik Nemtsov70f47422011-04-18 14:15:25 +03002741 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002742 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002743 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002744 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002745 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002746
2747 ret = wl1271_ap_init_templates(wl);
2748 if (ret < 0)
2749 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002750 }
2751
Arik Nemtsove78a2872010-10-16 19:07:21 +02002752 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2753 if (ret < 0)
2754 goto out;
2755
2756 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2757 if (bss_conf->enable_beacon) {
2758 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2759 ret = wl1271_cmd_start_bss(wl);
2760 if (ret < 0)
2761 goto out;
2762
2763 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2764 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002765
2766 ret = wl1271_ap_init_hwenc(wl);
2767 if (ret < 0)
2768 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002769 }
2770 } else {
2771 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2772 ret = wl1271_cmd_stop_bss(wl);
2773 if (ret < 0)
2774 goto out;
2775
2776 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2777 wl1271_debug(DEBUG_AP, "stopped AP");
2778 }
2779 }
2780 }
2781
Eliad Pellercb5ae052011-04-07 15:52:05 +03002782 if (changed & BSS_CHANGED_IBSS) {
2783 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2784 bss_conf->ibss_joined);
2785
2786 if (bss_conf->ibss_joined) {
2787 u32 rates = bss_conf->basic_rates;
2788 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2789 rates);
2790 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2791
2792 /* by default, use 11b rates */
2793 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2794 ret = wl1271_acx_sta_rate_policies(wl);
2795 if (ret < 0)
2796 goto out;
2797 }
2798 }
2799
Arik Nemtsove78a2872010-10-16 19:07:21 +02002800 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2801 if (ret < 0)
2802 goto out;
2803out:
2804 return;
2805}
2806
2807/* STA/IBSS mode changes */
2808static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2809 struct ieee80211_vif *vif,
2810 struct ieee80211_bss_conf *bss_conf,
2811 u32 changed)
2812{
2813 bool do_join = false, set_assoc = false;
2814 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002815 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002816 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002817 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002818 bool sta_exists = false;
2819 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002820
2821 if (is_ibss) {
2822 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2823 changed);
2824 if (ret < 0)
2825 goto out;
2826 }
2827
2828 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2829 do_join = true;
2830
2831 /* Need to update the SSID (for filtering etc) */
2832 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2833 do_join = true;
2834
2835 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002836 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2837 bss_conf->enable_beacon ? "enabled" : "disabled");
2838
2839 if (bss_conf->enable_beacon)
2840 wl->set_bss_type = BSS_TYPE_IBSS;
2841 else
2842 wl->set_bss_type = BSS_TYPE_STA_BSS;
2843 do_join = true;
2844 }
2845
Arik Nemtsove78a2872010-10-16 19:07:21 +02002846 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002847 bool enable = false;
2848 if (bss_conf->cqm_rssi_thold)
2849 enable = true;
2850 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2851 bss_conf->cqm_rssi_thold,
2852 bss_conf->cqm_rssi_hyst);
2853 if (ret < 0)
2854 goto out;
2855 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2856 }
2857
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002858 if ((changed & BSS_CHANGED_BSSID) &&
2859 /*
2860 * Now we know the correct bssid, so we send a new join command
2861 * and enable the BSSID filter
2862 */
2863 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002864 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002865
Eliad Pellerfa287b82010-12-26 09:27:50 +01002866 if (!is_zero_ether_addr(wl->bssid)) {
2867 ret = wl1271_cmd_build_null_data(wl);
2868 if (ret < 0)
2869 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002870
Eliad Pellerfa287b82010-12-26 09:27:50 +01002871 ret = wl1271_build_qos_null_data(wl);
2872 if (ret < 0)
2873 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002874
Eliad Pellerfa287b82010-12-26 09:27:50 +01002875 /* filter out all packets not from this BSSID */
2876 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002877
Eliad Pellerfa287b82010-12-26 09:27:50 +01002878 /* Need to update the BSSID (for filtering etc) */
2879 do_join = true;
2880 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002881 }
2882
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002883 rcu_read_lock();
2884 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2885 if (sta) {
2886 /* save the supp_rates of the ap */
2887 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2888 if (sta->ht_cap.ht_supported)
2889 sta_rate_set |=
2890 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002891 sta_ht_cap = sta->ht_cap;
2892 sta_exists = true;
2893 }
2894 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002895
Arik Nemtsova1008852011-02-12 23:24:20 +02002896 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002897 /* handle new association with HT and HT information change */
2898 if ((changed & BSS_CHANGED_HT) &&
2899 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002900 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002901 true);
2902 if (ret < 0) {
2903 wl1271_warning("Set ht cap true failed %d",
2904 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002905 goto out;
2906 }
2907 ret = wl1271_acx_set_ht_information(wl,
2908 bss_conf->ht_operation_mode);
2909 if (ret < 0) {
2910 wl1271_warning("Set ht information failed %d",
2911 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002912 goto out;
2913 }
2914 }
2915 /* handle new association without HT and disassociation */
2916 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002917 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002918 false);
2919 if (ret < 0) {
2920 wl1271_warning("Set ht cap false failed %d",
2921 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002922 goto out;
2923 }
2924 }
2925 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002926
Arik Nemtsove78a2872010-10-16 19:07:21 +02002927 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002929 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002930 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002932 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002934 wl->ps_poll_failures = 0;
2935
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002936 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002937 * use basic rates from AP, and determine lowest rate
2938 * to use with control frames.
2939 */
2940 rates = bss_conf->basic_rates;
2941 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2942 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002943 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002944 if (sta_rate_set)
2945 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2946 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002947 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002948 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002949 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002950
2951 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002952 * with wl1271, we don't need to update the
2953 * beacon_int and dtim_period, because the firmware
2954 * updates it by itself when the first beacon is
2955 * received after a join.
2956 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2958 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002959 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002961 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002962 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002963 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002964 dev_kfree_skb(wl->probereq);
2965 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2966 ieoffset = offsetof(struct ieee80211_mgmt,
2967 u.probe_req.variable);
2968 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002969
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002970 /* enable the connection monitoring feature */
2971 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002973 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002974
2975 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002976 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2977 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002978 enum wl1271_cmd_ps_mode mode;
2979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002981 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002982 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002983 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002985 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002987 } else {
2988 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002989 bool was_assoc =
2990 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2991 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002992 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002993 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002994
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002995 /* free probe-request template */
2996 dev_kfree_skb(wl->probereq);
2997 wl->probereq = NULL;
2998
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002999 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003000 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003001
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003002 /* revert back to minimum rates for the current band */
3003 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003004 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003005 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003006 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003007 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003008
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003009 /* disable connection monitor features */
3010 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003011
3012 /* Disable the keep-alive feature */
3013 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003014 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003015 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003016
3017 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003018 if (was_assoc) {
3019 wl1271_unjoin(wl);
3020 wl1271_dummy_join(wl);
3021 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022 }
3023 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003024
Arik Nemtsove78a2872010-10-16 19:07:21 +02003025 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3026 if (ret < 0)
3027 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003029 if (changed & BSS_CHANGED_ARP_FILTER) {
3030 __be32 addr = bss_conf->arp_addr_list[0];
3031 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3032
Eliad Pellerc5312772010-12-09 11:31:27 +02003033 if (bss_conf->arp_addr_cnt == 1 &&
3034 bss_conf->arp_filter_enabled) {
3035 /*
3036 * The template should have been configured only upon
3037 * association. however, it seems that the correct ip
3038 * isn't being set (when sending), so we have to
3039 * reconfigure the template upon every ip change.
3040 */
3041 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3042 if (ret < 0) {
3043 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003044 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003045 }
3046
3047 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003048 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003049 addr);
3050 } else
3051 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003052
3053 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003054 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003055 }
3056
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003057 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003058 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003059 if (ret < 0) {
3060 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003061 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003062 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003063 }
3064
Arik Nemtsove78a2872010-10-16 19:07:21 +02003065out:
3066 return;
3067}
3068
3069static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3070 struct ieee80211_vif *vif,
3071 struct ieee80211_bss_conf *bss_conf,
3072 u32 changed)
3073{
3074 struct wl1271 *wl = hw->priv;
3075 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3076 int ret;
3077
3078 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3079 (int)changed);
3080
3081 mutex_lock(&wl->mutex);
3082
3083 if (unlikely(wl->state == WL1271_STATE_OFF))
3084 goto out;
3085
Ido Yariva6208652011-03-01 15:14:41 +02003086 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003087 if (ret < 0)
3088 goto out;
3089
3090 if (is_ap)
3091 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3092 else
3093 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3094
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003095 wl1271_ps_elp_sleep(wl);
3096
3097out:
3098 mutex_unlock(&wl->mutex);
3099}
3100
Kalle Valoc6999d82010-02-18 13:25:41 +02003101static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3102 const struct ieee80211_tx_queue_params *params)
3103{
3104 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003105 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003106 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003107
3108 mutex_lock(&wl->mutex);
3109
3110 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3111
Kalle Valo4695dc92010-03-18 12:26:38 +02003112 if (params->uapsd)
3113 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3114 else
3115 ps_scheme = CONF_PS_SCHEME_LEGACY;
3116
Arik Nemtsov488fc542010-10-16 20:33:45 +02003117 if (wl->state == WL1271_STATE_OFF) {
3118 /*
3119 * If the state is off, the parameters will be recorded and
3120 * configured on init. This happens in AP-mode.
3121 */
3122 struct conf_tx_ac_category *conf_ac =
3123 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3124 struct conf_tx_tid *conf_tid =
3125 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3126
3127 conf_ac->ac = wl1271_tx_get_queue(queue);
3128 conf_ac->cw_min = (u8)params->cw_min;
3129 conf_ac->cw_max = params->cw_max;
3130 conf_ac->aifsn = params->aifs;
3131 conf_ac->tx_op_limit = params->txop << 5;
3132
3133 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3134 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3135 conf_tid->tsid = wl1271_tx_get_queue(queue);
3136 conf_tid->ps_scheme = ps_scheme;
3137 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3138 conf_tid->apsd_conf[0] = 0;
3139 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003140 goto out;
3141 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003142
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003143 ret = wl1271_ps_elp_wakeup(wl);
3144 if (ret < 0)
3145 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003146
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003147 /*
3148 * the txop is confed in units of 32us by the mac80211,
3149 * we need us
3150 */
3151 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3152 params->cw_min, params->cw_max,
3153 params->aifs, params->txop << 5);
3154 if (ret < 0)
3155 goto out_sleep;
3156
3157 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3158 CONF_CHANNEL_TYPE_EDCF,
3159 wl1271_tx_get_queue(queue),
3160 ps_scheme, CONF_ACK_POLICY_LEGACY,
3161 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003162
3163out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003164 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003165
3166out:
3167 mutex_unlock(&wl->mutex);
3168
3169 return ret;
3170}
3171
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003172static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3173{
3174
3175 struct wl1271 *wl = hw->priv;
3176 u64 mactime = ULLONG_MAX;
3177 int ret;
3178
3179 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3180
3181 mutex_lock(&wl->mutex);
3182
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003183 if (unlikely(wl->state == WL1271_STATE_OFF))
3184 goto out;
3185
Ido Yariva6208652011-03-01 15:14:41 +02003186 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003187 if (ret < 0)
3188 goto out;
3189
3190 ret = wl1271_acx_tsf_info(wl, &mactime);
3191 if (ret < 0)
3192 goto out_sleep;
3193
3194out_sleep:
3195 wl1271_ps_elp_sleep(wl);
3196
3197out:
3198 mutex_unlock(&wl->mutex);
3199 return mactime;
3200}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003201
John W. Linvilleece550d2010-07-28 16:41:06 -04003202static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3203 struct survey_info *survey)
3204{
3205 struct wl1271 *wl = hw->priv;
3206 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003207
John W. Linvilleece550d2010-07-28 16:41:06 -04003208 if (idx != 0)
3209 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003210
John W. Linvilleece550d2010-07-28 16:41:06 -04003211 survey->channel = conf->channel;
3212 survey->filled = SURVEY_INFO_NOISE_DBM;
3213 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003214
John W. Linvilleece550d2010-07-28 16:41:06 -04003215 return 0;
3216}
3217
Arik Nemtsov409622e2011-02-23 00:22:29 +02003218static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003219 struct ieee80211_sta *sta,
3220 u8 *hlid)
3221{
3222 struct wl1271_station *wl_sta;
3223 int id;
3224
3225 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3226 if (id >= AP_MAX_STATIONS) {
3227 wl1271_warning("could not allocate HLID - too much stations");
3228 return -EBUSY;
3229 }
3230
3231 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003232 __set_bit(id, wl->ap_hlid_map);
3233 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3234 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003235 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003236 return 0;
3237}
3238
Arik Nemtsov409622e2011-02-23 00:22:29 +02003239static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003240{
3241 int id = hlid - WL1271_AP_STA_HLID_START;
3242
Arik Nemtsov409622e2011-02-23 00:22:29 +02003243 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3244 return;
3245
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003246 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003247 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003248 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003249 __clear_bit(hlid, &wl->ap_ps_map);
3250 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003251}
3252
3253static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3254 struct ieee80211_vif *vif,
3255 struct ieee80211_sta *sta)
3256{
3257 struct wl1271 *wl = hw->priv;
3258 int ret = 0;
3259 u8 hlid;
3260
3261 mutex_lock(&wl->mutex);
3262
3263 if (unlikely(wl->state == WL1271_STATE_OFF))
3264 goto out;
3265
3266 if (wl->bss_type != BSS_TYPE_AP_BSS)
3267 goto out;
3268
3269 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3270
Arik Nemtsov409622e2011-02-23 00:22:29 +02003271 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003272 if (ret < 0)
3273 goto out;
3274
Ido Yariva6208652011-03-01 15:14:41 +02003275 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003276 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003277 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003278
3279 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3280 if (ret < 0)
3281 goto out_sleep;
3282
3283out_sleep:
3284 wl1271_ps_elp_sleep(wl);
3285
Arik Nemtsov409622e2011-02-23 00:22:29 +02003286out_free_sta:
3287 if (ret < 0)
3288 wl1271_free_sta(wl, hlid);
3289
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003290out:
3291 mutex_unlock(&wl->mutex);
3292 return ret;
3293}
3294
3295static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3296 struct ieee80211_vif *vif,
3297 struct ieee80211_sta *sta)
3298{
3299 struct wl1271 *wl = hw->priv;
3300 struct wl1271_station *wl_sta;
3301 int ret = 0, id;
3302
3303 mutex_lock(&wl->mutex);
3304
3305 if (unlikely(wl->state == WL1271_STATE_OFF))
3306 goto out;
3307
3308 if (wl->bss_type != BSS_TYPE_AP_BSS)
3309 goto out;
3310
3311 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3312
3313 wl_sta = (struct wl1271_station *)sta->drv_priv;
3314 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3315 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3316 goto out;
3317
Ido Yariva6208652011-03-01 15:14:41 +02003318 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003319 if (ret < 0)
3320 goto out;
3321
3322 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3323 if (ret < 0)
3324 goto out_sleep;
3325
Arik Nemtsov409622e2011-02-23 00:22:29 +02003326 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003327
3328out_sleep:
3329 wl1271_ps_elp_sleep(wl);
3330
3331out:
3332 mutex_unlock(&wl->mutex);
3333 return ret;
3334}
3335
Luciano Coelho4623ec72011-03-21 19:26:41 +02003336static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3337 struct ieee80211_vif *vif,
3338 enum ieee80211_ampdu_mlme_action action,
3339 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3340 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003341{
3342 struct wl1271 *wl = hw->priv;
3343 int ret;
3344
3345 mutex_lock(&wl->mutex);
3346
3347 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3348 ret = -EAGAIN;
3349 goto out;
3350 }
3351
Ido Yariva6208652011-03-01 15:14:41 +02003352 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003353 if (ret < 0)
3354 goto out;
3355
3356 switch (action) {
3357 case IEEE80211_AMPDU_RX_START:
3358 if (wl->ba_support) {
3359 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3360 true);
3361 if (!ret)
3362 wl->ba_rx_bitmap |= BIT(tid);
3363 } else {
3364 ret = -ENOTSUPP;
3365 }
3366 break;
3367
3368 case IEEE80211_AMPDU_RX_STOP:
3369 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3370 if (!ret)
3371 wl->ba_rx_bitmap &= ~BIT(tid);
3372 break;
3373
3374 /*
3375 * The BA initiator session management in FW independently.
3376 * Falling break here on purpose for all TX APDU commands.
3377 */
3378 case IEEE80211_AMPDU_TX_START:
3379 case IEEE80211_AMPDU_TX_STOP:
3380 case IEEE80211_AMPDU_TX_OPERATIONAL:
3381 ret = -EINVAL;
3382 break;
3383
3384 default:
3385 wl1271_error("Incorrect ampdu action id=%x\n", action);
3386 ret = -EINVAL;
3387 }
3388
3389 wl1271_ps_elp_sleep(wl);
3390
3391out:
3392 mutex_unlock(&wl->mutex);
3393
3394 return ret;
3395}
3396
Arik Nemtsov33437892011-04-26 23:35:39 +03003397static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3398{
3399 struct wl1271 *wl = hw->priv;
3400 bool ret = false;
3401
3402 mutex_lock(&wl->mutex);
3403
3404 if (unlikely(wl->state == WL1271_STATE_OFF))
3405 goto out;
3406
3407 /* packets are considered pending if in the TX queue or the FW */
3408 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3409
3410 /* the above is appropriate for STA mode for PS purposes */
3411 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3412
3413out:
3414 mutex_unlock(&wl->mutex);
3415
3416 return ret;
3417}
3418
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003419/* can't be const, mac80211 writes to this */
3420static struct ieee80211_rate wl1271_rates[] = {
3421 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003422 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3423 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003424 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003425 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3426 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003427 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3428 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003429 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3430 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003431 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3432 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003433 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3434 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003435 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3436 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003437 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3438 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003439 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003440 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3441 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003442 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003443 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3444 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003445 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003446 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3447 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003448 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003449 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3450 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003451 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003452 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3453 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003454 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003455 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3456 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003457 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003458 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3459 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003460};
3461
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003462/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003463static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003464 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003465 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003466 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3467 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3468 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003469 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003470 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3471 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3472 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003473 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003474 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3475 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3476 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003477 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003478};
3479
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003480/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003481static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003482 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003483 7, /* CONF_HW_RXTX_RATE_MCS7 */
3484 6, /* CONF_HW_RXTX_RATE_MCS6 */
3485 5, /* CONF_HW_RXTX_RATE_MCS5 */
3486 4, /* CONF_HW_RXTX_RATE_MCS4 */
3487 3, /* CONF_HW_RXTX_RATE_MCS3 */
3488 2, /* CONF_HW_RXTX_RATE_MCS2 */
3489 1, /* CONF_HW_RXTX_RATE_MCS1 */
3490 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003491
3492 11, /* CONF_HW_RXTX_RATE_54 */
3493 10, /* CONF_HW_RXTX_RATE_48 */
3494 9, /* CONF_HW_RXTX_RATE_36 */
3495 8, /* CONF_HW_RXTX_RATE_24 */
3496
3497 /* TI-specific rate */
3498 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3499
3500 7, /* CONF_HW_RXTX_RATE_18 */
3501 6, /* CONF_HW_RXTX_RATE_12 */
3502 3, /* CONF_HW_RXTX_RATE_11 */
3503 5, /* CONF_HW_RXTX_RATE_9 */
3504 4, /* CONF_HW_RXTX_RATE_6 */
3505 2, /* CONF_HW_RXTX_RATE_5_5 */
3506 1, /* CONF_HW_RXTX_RATE_2 */
3507 0 /* CONF_HW_RXTX_RATE_1 */
3508};
3509
Shahar Levie8b03a22010-10-13 16:09:39 +02003510/* 11n STA capabilities */
3511#define HW_RX_HIGHEST_RATE 72
3512
Shahar Levi00d20102010-11-08 11:20:10 +00003513#ifdef CONFIG_WL12XX_HT
3514#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003515 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3516 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003517 .ht_supported = true, \
3518 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3519 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3520 .mcs = { \
3521 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3522 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3523 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3524 }, \
3525}
Shahar Levi18357852010-10-13 16:09:41 +02003526#else
Shahar Levi00d20102010-11-08 11:20:10 +00003527#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003528 .ht_supported = false, \
3529}
3530#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003531
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532/* can't be const, mac80211 writes to this */
3533static struct ieee80211_supported_band wl1271_band_2ghz = {
3534 .channels = wl1271_channels,
3535 .n_channels = ARRAY_SIZE(wl1271_channels),
3536 .bitrates = wl1271_rates,
3537 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003538 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003539};
3540
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003541/* 5 GHz data rates for WL1273 */
3542static struct ieee80211_rate wl1271_rates_5ghz[] = {
3543 { .bitrate = 60,
3544 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3545 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3546 { .bitrate = 90,
3547 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3548 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3549 { .bitrate = 120,
3550 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3551 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3552 { .bitrate = 180,
3553 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3554 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3555 { .bitrate = 240,
3556 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3557 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3558 { .bitrate = 360,
3559 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3560 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3561 { .bitrate = 480,
3562 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3563 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3564 { .bitrate = 540,
3565 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3566 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3567};
3568
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003569/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003570static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003571 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003572 { .hw_value = 8, .center_freq = 5040},
3573 { .hw_value = 9, .center_freq = 5045},
3574 { .hw_value = 11, .center_freq = 5055},
3575 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003576 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003577 { .hw_value = 34, .center_freq = 5170},
3578 { .hw_value = 36, .center_freq = 5180},
3579 { .hw_value = 38, .center_freq = 5190},
3580 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003581 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003582 { .hw_value = 44, .center_freq = 5220},
3583 { .hw_value = 46, .center_freq = 5230},
3584 { .hw_value = 48, .center_freq = 5240},
3585 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003586 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003587 { .hw_value = 60, .center_freq = 5300},
3588 { .hw_value = 64, .center_freq = 5320},
3589 { .hw_value = 100, .center_freq = 5500},
3590 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003591 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003592 { .hw_value = 112, .center_freq = 5560},
3593 { .hw_value = 116, .center_freq = 5580},
3594 { .hw_value = 120, .center_freq = 5600},
3595 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003596 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003597 { .hw_value = 132, .center_freq = 5660},
3598 { .hw_value = 136, .center_freq = 5680},
3599 { .hw_value = 140, .center_freq = 5700},
3600 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003601 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003602 { .hw_value = 157, .center_freq = 5785},
3603 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003604 { .hw_value = 165, .center_freq = 5825},
3605};
3606
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003607/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003608static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003609 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003610 7, /* CONF_HW_RXTX_RATE_MCS7 */
3611 6, /* CONF_HW_RXTX_RATE_MCS6 */
3612 5, /* CONF_HW_RXTX_RATE_MCS5 */
3613 4, /* CONF_HW_RXTX_RATE_MCS4 */
3614 3, /* CONF_HW_RXTX_RATE_MCS3 */
3615 2, /* CONF_HW_RXTX_RATE_MCS2 */
3616 1, /* CONF_HW_RXTX_RATE_MCS1 */
3617 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003618
3619 7, /* CONF_HW_RXTX_RATE_54 */
3620 6, /* CONF_HW_RXTX_RATE_48 */
3621 5, /* CONF_HW_RXTX_RATE_36 */
3622 4, /* CONF_HW_RXTX_RATE_24 */
3623
3624 /* TI-specific rate */
3625 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3626
3627 3, /* CONF_HW_RXTX_RATE_18 */
3628 2, /* CONF_HW_RXTX_RATE_12 */
3629 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3630 1, /* CONF_HW_RXTX_RATE_9 */
3631 0, /* CONF_HW_RXTX_RATE_6 */
3632 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3633 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3634 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3635};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003636
3637static struct ieee80211_supported_band wl1271_band_5ghz = {
3638 .channels = wl1271_channels_5ghz,
3639 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3640 .bitrates = wl1271_rates_5ghz,
3641 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003642 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003643};
3644
Tobias Klausera0ea9492010-05-20 10:38:11 +02003645static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003646 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3647 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3648};
3649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003650static const struct ieee80211_ops wl1271_ops = {
3651 .start = wl1271_op_start,
3652 .stop = wl1271_op_stop,
3653 .add_interface = wl1271_op_add_interface,
3654 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003655#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003656 .suspend = wl1271_op_suspend,
3657 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003658#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003660 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003661 .configure_filter = wl1271_op_configure_filter,
3662 .tx = wl1271_op_tx,
3663 .set_key = wl1271_op_set_key,
3664 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003665 .sched_scan_start = wl1271_op_sched_scan_start,
3666 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003668 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003669 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003670 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003671 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003672 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003673 .sta_add = wl1271_op_sta_add,
3674 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003675 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003676 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003677 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003678};
3679
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003680
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003681u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003682{
3683 u8 idx;
3684
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003685 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003686
3687 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3688 wl1271_error("Illegal RX rate from HW: %d", rate);
3689 return 0;
3690 }
3691
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003692 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003693 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3694 wl1271_error("Unsupported RX rate from HW: %d", rate);
3695 return 0;
3696 }
3697
3698 return idx;
3699}
3700
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003701static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3702 struct device_attribute *attr,
3703 char *buf)
3704{
3705 struct wl1271 *wl = dev_get_drvdata(dev);
3706 ssize_t len;
3707
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003708 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003709
3710 mutex_lock(&wl->mutex);
3711 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3712 wl->sg_enabled);
3713 mutex_unlock(&wl->mutex);
3714
3715 return len;
3716
3717}
3718
3719static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3720 struct device_attribute *attr,
3721 const char *buf, size_t count)
3722{
3723 struct wl1271 *wl = dev_get_drvdata(dev);
3724 unsigned long res;
3725 int ret;
3726
Luciano Coelho6277ed62011-04-01 17:49:54 +03003727 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003728 if (ret < 0) {
3729 wl1271_warning("incorrect value written to bt_coex_mode");
3730 return count;
3731 }
3732
3733 mutex_lock(&wl->mutex);
3734
3735 res = !!res;
3736
3737 if (res == wl->sg_enabled)
3738 goto out;
3739
3740 wl->sg_enabled = res;
3741
3742 if (wl->state == WL1271_STATE_OFF)
3743 goto out;
3744
Ido Yariva6208652011-03-01 15:14:41 +02003745 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003746 if (ret < 0)
3747 goto out;
3748
3749 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3750 wl1271_ps_elp_sleep(wl);
3751
3752 out:
3753 mutex_unlock(&wl->mutex);
3754 return count;
3755}
3756
3757static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3758 wl1271_sysfs_show_bt_coex_state,
3759 wl1271_sysfs_store_bt_coex_state);
3760
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003761static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3762 struct device_attribute *attr,
3763 char *buf)
3764{
3765 struct wl1271 *wl = dev_get_drvdata(dev);
3766 ssize_t len;
3767
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003768 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003769
3770 mutex_lock(&wl->mutex);
3771 if (wl->hw_pg_ver >= 0)
3772 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3773 else
3774 len = snprintf(buf, len, "n/a\n");
3775 mutex_unlock(&wl->mutex);
3776
3777 return len;
3778}
3779
3780static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3781 wl1271_sysfs_show_hw_pg_ver, NULL);
3782
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003783int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003784{
3785 int ret;
3786
3787 if (wl->mac80211_registered)
3788 return 0;
3789
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003790 ret = wl1271_fetch_nvs(wl);
3791 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003792 /* NOTE: The wl->nvs->nvs element must be first, in
3793 * order to simplify the casting, we assume it is at
3794 * the beginning of the wl->nvs structure.
3795 */
3796 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003797
3798 wl->mac_addr[0] = nvs_ptr[11];
3799 wl->mac_addr[1] = nvs_ptr[10];
3800 wl->mac_addr[2] = nvs_ptr[6];
3801 wl->mac_addr[3] = nvs_ptr[5];
3802 wl->mac_addr[4] = nvs_ptr[4];
3803 wl->mac_addr[5] = nvs_ptr[3];
3804 }
3805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003806 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3807
3808 ret = ieee80211_register_hw(wl->hw);
3809 if (ret < 0) {
3810 wl1271_error("unable to register mac80211 hw: %d", ret);
3811 return ret;
3812 }
3813
3814 wl->mac80211_registered = true;
3815
Eliad Pellerd60080a2010-11-24 12:53:16 +02003816 wl1271_debugfs_init(wl);
3817
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003818 register_netdevice_notifier(&wl1271_dev_notifier);
3819
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003820 wl1271_notice("loaded");
3821
3822 return 0;
3823}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003824EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003825
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003826void wl1271_unregister_hw(struct wl1271 *wl)
3827{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003828 if (wl->state == WL1271_STATE_PLT)
3829 __wl1271_plt_stop(wl);
3830
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003831 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003832 ieee80211_unregister_hw(wl->hw);
3833 wl->mac80211_registered = false;
3834
3835}
3836EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3837
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003838int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003839{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003840 static const u32 cipher_suites[] = {
3841 WLAN_CIPHER_SUITE_WEP40,
3842 WLAN_CIPHER_SUITE_WEP104,
3843 WLAN_CIPHER_SUITE_TKIP,
3844 WLAN_CIPHER_SUITE_CCMP,
3845 WL1271_CIPHER_SUITE_GEM,
3846 };
3847
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003848 /* The tx descriptor buffer and the TKIP space. */
3849 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3850 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003851
3852 /* unit us */
3853 /* FIXME: find a proper value */
3854 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003855 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003856
3857 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003858 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003859 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003860 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003861 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003862 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003863 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003864 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003865 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003866 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003867
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003868 wl->hw->wiphy->cipher_suites = cipher_suites;
3869 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3870
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003871 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003872 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003873 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003874 /*
3875 * Maximum length of elements in scanning probe request templates
3876 * should be the maximum length possible for a template, without
3877 * the IEEE80211 header of the template
3878 */
3879 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3880 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003881
Luciano Coelho4a31c112011-03-21 23:16:14 +02003882 /* make sure all our channels fit in the scanned_ch bitmask */
3883 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3884 ARRAY_SIZE(wl1271_channels_5ghz) >
3885 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003886 /*
3887 * We keep local copies of the band structs because we need to
3888 * modify them on a per-device basis.
3889 */
3890 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3891 sizeof(wl1271_band_2ghz));
3892 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3893 sizeof(wl1271_band_5ghz));
3894
3895 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3896 &wl->bands[IEEE80211_BAND_2GHZ];
3897 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3898 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003899
Kalle Valo12bd8942010-03-18 12:26:33 +02003900 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003901 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003902
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003903 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3904
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003905 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003906
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003907 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3908
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003909 wl->hw->max_rx_aggregation_subframes = 8;
3910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003911 return 0;
3912}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003913EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003914
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003915#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003916
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003917struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003918{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003919 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003920 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003921 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003922 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003923 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003924
3925 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3926 if (!hw) {
3927 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003928 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003929 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003930 }
3931
Julia Lawall929ebd32010-05-15 23:16:39 +02003932 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003933 if (!plat_dev) {
3934 wl1271_error("could not allocate platform_device");
3935 ret = -ENOMEM;
3936 goto err_plat_alloc;
3937 }
3938
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003939 wl = hw->priv;
3940 memset(wl, 0, sizeof(*wl));
3941
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003942 INIT_LIST_HEAD(&wl->list);
3943
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003944 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003945 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003946
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003947 for (i = 0; i < NUM_TX_QUEUES; i++)
3948 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003949
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003950 for (i = 0; i < NUM_TX_QUEUES; i++)
3951 for (j = 0; j < AP_MAX_LINKS; j++)
3952 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3953
Ido Yariva6208652011-03-01 15:14:41 +02003954 skb_queue_head_init(&wl->deferred_rx_queue);
3955 skb_queue_head_init(&wl->deferred_tx_queue);
3956
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003957 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003958 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003959 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003960 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3961 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3962 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003963 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003964 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003965 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003966 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003967 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3968 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003969 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003970 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003971 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003972 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003973 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003974 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003975 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003976 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003977 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003978 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003979 wl->bss_type = MAX_BSS_TYPE;
3980 wl->set_bss_type = MAX_BSS_TYPE;
3981 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003982 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003983 wl->ap_ps_map = 0;
3984 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003985 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003986 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003987 wl->sched_scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003988
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003989 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003990 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003991 wl->tx_frames[i] = NULL;
3992
3993 spin_lock_init(&wl->wl_lock);
3994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003995 wl->state = WL1271_STATE_OFF;
3996 mutex_init(&wl->mutex);
3997
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003998 /* Apply default driver configuration. */
3999 wl1271_conf_init(wl);
4000
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004001 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4002 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4003 if (!wl->aggr_buf) {
4004 ret = -ENOMEM;
4005 goto err_hw;
4006 }
4007
Ido Yariv990f5de2011-03-31 10:06:59 +02004008 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4009 if (!wl->dummy_packet) {
4010 ret = -ENOMEM;
4011 goto err_aggr;
4012 }
4013
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004014 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004015 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004016 if (ret) {
4017 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004018 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004019 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004020 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004021
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004022 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004023 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004024 if (ret < 0) {
4025 wl1271_error("failed to create sysfs file bt_coex_state");
4026 goto err_platform;
4027 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004028
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004029 /* Create sysfs file to get HW PG version */
4030 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4031 if (ret < 0) {
4032 wl1271_error("failed to create sysfs file hw_pg_ver");
4033 goto err_bt_coex_state;
4034 }
4035
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004036 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004037
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004038err_bt_coex_state:
4039 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4040
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004041err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004042 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004043
Ido Yariv990f5de2011-03-31 10:06:59 +02004044err_dummy_packet:
4045 dev_kfree_skb(wl->dummy_packet);
4046
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004047err_aggr:
4048 free_pages((unsigned long)wl->aggr_buf, order);
4049
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004050err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004051 wl1271_debugfs_exit(wl);
4052 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004053
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004054err_plat_alloc:
4055 ieee80211_free_hw(hw);
4056
4057err_hw_alloc:
4058
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004059 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004060}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004061EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004062
4063int wl1271_free_hw(struct wl1271 *wl)
4064{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004065 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004066 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004067 free_pages((unsigned long)wl->aggr_buf,
4068 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004069 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004070
4071 wl1271_debugfs_exit(wl);
4072
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004073 vfree(wl->fw);
4074 wl->fw = NULL;
4075 kfree(wl->nvs);
4076 wl->nvs = NULL;
4077
4078 kfree(wl->fw_status);
4079 kfree(wl->tx_res_if);
4080
4081 ieee80211_free_hw(wl->hw);
4082
4083 return 0;
4084}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004085EXPORT_SYMBOL_GPL(wl1271_free_hw);
4086
Guy Eilam491bbd62011-01-12 10:33:29 +01004087u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004088EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004089module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004090MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4091
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004092MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004093MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004094MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");