blob: a2171a4e9413228d7b4a8bcf54d82de240b48374 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300314 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300315 .num_probe_reqs = 2,
316 .rssi_threshold = -90,
317 .snr_threshold = 0,
318 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200319 .rf = {
320 .tx_per_channel_power_compensation_2 = {
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 },
323 .tx_per_channel_power_compensation_5 = {
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 },
328 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100329 .ht = {
330 .tx_ba_win_size = 64,
331 .inactivity_timeout = 10000,
332 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200333 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200334 .num_stations = 1,
335 .ssid_profiles = 1,
336 .rx_block_num = 70,
337 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300338 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200339 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200340 .min_req_rx_blocks = 22,
341 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200342 },
343 .mem_wl128x = {
344 .num_stations = 1,
345 .ssid_profiles = 1,
346 .rx_block_num = 40,
347 .tx_min_block_num = 40,
348 .dynamic_memory = 1,
349 .min_req_tx_blocks = 45,
350 .min_req_rx_blocks = 22,
351 .tx_min = 27,
352 },
Shahar Leviff868432011-04-11 15:41:46 +0300353 .fm_coex = {
354 .enable = true,
355 .swallow_period = 5,
356 .n_divider_fref_set_1 = 0xff, /* default */
357 .n_divider_fref_set_2 = 12,
358 .m_divider_fref_set_1 = 148,
359 .m_divider_fref_set_2 = 0xffff, /* default */
360 .coex_pll_stabilization_time = 0xffffffff, /* default */
361 .ldo_stabilization_time = 0xffff, /* default */
362 .fm_disturbed_band_margin = 0xff, /* default */
363 .swallow_clk_diff = 0xff, /* default */
364 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300365 .rx_streaming = {
366 .duration = 150,
367 .queues = 0x1,
368 .interval = 20,
369 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300370 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300371};
372
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300373static void __wl1271_op_remove_interface(struct wl1271 *wl,
374 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200375static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200376
377
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200378static void wl1271_device_release(struct device *dev)
379{
380
381}
382
383static struct platform_device wl1271_device = {
384 .name = "wl1271",
385 .id = -1,
386
387 /* device model insists to have a release function */
388 .dev = {
389 .release = wl1271_device_release,
390 },
391};
392
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200393static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300394static LIST_HEAD(wl_list);
395
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300396static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
397 void *arg)
398{
399 struct net_device *dev = arg;
400 struct wireless_dev *wdev;
401 struct wiphy *wiphy;
402 struct ieee80211_hw *hw;
403 struct wl1271 *wl;
404 struct wl1271 *wl_temp;
405 int ret = 0;
406
407 /* Check that this notification is for us. */
408 if (what != NETDEV_CHANGE)
409 return NOTIFY_DONE;
410
411 wdev = dev->ieee80211_ptr;
412 if (wdev == NULL)
413 return NOTIFY_DONE;
414
415 wiphy = wdev->wiphy;
416 if (wiphy == NULL)
417 return NOTIFY_DONE;
418
419 hw = wiphy_priv(wiphy);
420 if (hw == NULL)
421 return NOTIFY_DONE;
422
423 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200424 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300425 list_for_each_entry(wl, &wl_list, list) {
426 if (wl == wl_temp)
427 break;
428 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200429 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300430 if (wl != wl_temp)
431 return NOTIFY_DONE;
432
433 mutex_lock(&wl->mutex);
434
435 if (wl->state == WL1271_STATE_OFF)
436 goto out;
437
438 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
439 goto out;
440
Ido Yariva6208652011-03-01 15:14:41 +0200441 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300442 if (ret < 0)
443 goto out;
444
445 if ((dev->operstate == IF_OPER_UP) &&
446 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
447 wl1271_cmd_set_sta_state(wl);
448 wl1271_info("Association completed.");
449 }
450
451 wl1271_ps_elp_sleep(wl);
452
453out:
454 mutex_unlock(&wl->mutex);
455
456 return NOTIFY_OK;
457}
458
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100459static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200460 struct regulatory_request *request)
461{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100462 struct ieee80211_supported_band *band;
463 struct ieee80211_channel *ch;
464 int i;
465
466 band = wiphy->bands[IEEE80211_BAND_5GHZ];
467 for (i = 0; i < band->n_channels; i++) {
468 ch = &band->channels[i];
469 if (ch->flags & IEEE80211_CHAN_DISABLED)
470 continue;
471
472 if (ch->flags & IEEE80211_CHAN_RADAR)
473 ch->flags |= IEEE80211_CHAN_NO_IBSS |
474 IEEE80211_CHAN_PASSIVE_SCAN;
475
476 }
477
478 return 0;
479}
480
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300481static void wl1271_conf_init(struct wl1271 *wl)
482{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300483
484 /*
485 * This function applies the default configuration to the driver. This
486 * function is invoked upon driver load (spi probe.)
487 *
488 * The configuration is stored in a run-time structure in order to
489 * facilitate for run-time adjustment of any of the parameters. Making
490 * changes to the configuration structure will apply the new values on
491 * the next interface up (wl1271_op_start.)
492 */
493
494 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300495 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300496}
497
498
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499static int wl1271_plt_init(struct wl1271 *wl)
500{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200501 struct conf_tx_ac_category *conf_ac;
502 struct conf_tx_tid *conf_tid;
503 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300504
Shahar Levi49d750ca2011-03-06 16:32:09 +0200505 if (wl->chip.id == CHIP_ID_1283_PG20)
506 ret = wl128x_cmd_general_parms(wl);
507 else
508 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200509 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200510 return ret;
511
Shahar Levi49d750ca2011-03-06 16:32:09 +0200512 if (wl->chip.id == CHIP_ID_1283_PG20)
513 ret = wl128x_cmd_radio_parms(wl);
514 else
515 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200516 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200517 return ret;
518
Shahar Levi49d750ca2011-03-06 16:32:09 +0200519 if (wl->chip.id != CHIP_ID_1283_PG20) {
520 ret = wl1271_cmd_ext_radio_parms(wl);
521 if (ret < 0)
522 return ret;
523 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200524 if (ret < 0)
525 return ret;
526
Shahar Levi48a61472011-03-06 16:32:08 +0200527 /* Chip-specific initializations */
528 ret = wl1271_chip_specific_init(wl);
529 if (ret < 0)
530 return ret;
531
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200532 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200533 if (ret < 0)
534 return ret;
535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300536 ret = wl1271_acx_init_mem_config(wl);
537 if (ret < 0)
538 return ret;
539
Luciano Coelho12419cc2010-02-18 13:25:44 +0200540 /* PHY layer config */
541 ret = wl1271_init_phy_config(wl);
542 if (ret < 0)
543 goto out_free_memmap;
544
545 ret = wl1271_acx_dco_itrim_params(wl);
546 if (ret < 0)
547 goto out_free_memmap;
548
549 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200550 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200551 if (ret < 0)
552 goto out_free_memmap;
553
554 /* Bluetooth WLAN coexistence */
555 ret = wl1271_init_pta(wl);
556 if (ret < 0)
557 goto out_free_memmap;
558
Shahar Leviff868432011-04-11 15:41:46 +0300559 /* FM WLAN coexistence */
560 ret = wl1271_acx_fm_coex(wl);
561 if (ret < 0)
562 goto out_free_memmap;
563
Luciano Coelho12419cc2010-02-18 13:25:44 +0200564 /* Energy detection */
565 ret = wl1271_init_energy_detection(wl);
566 if (ret < 0)
567 goto out_free_memmap;
568
Gery Kahn1ec610e2011-02-01 03:03:08 -0600569 ret = wl1271_acx_sta_mem_cfg(wl);
570 if (ret < 0)
571 goto out_free_memmap;
572
Luciano Coelho12419cc2010-02-18 13:25:44 +0200573 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100574 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200575 if (ret < 0)
576 goto out_free_memmap;
577
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200578 /* Default TID/AC configuration */
579 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200580 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200581 conf_ac = &wl->conf.tx.ac_conf[i];
582 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
583 conf_ac->cw_max, conf_ac->aifsn,
584 conf_ac->tx_op_limit);
585 if (ret < 0)
586 goto out_free_memmap;
587
Luciano Coelho12419cc2010-02-18 13:25:44 +0200588 conf_tid = &wl->conf.tx.tid_conf[i];
589 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
590 conf_tid->channel_type,
591 conf_tid->tsid,
592 conf_tid->ps_scheme,
593 conf_tid->ack_policy,
594 conf_tid->apsd_conf[0],
595 conf_tid->apsd_conf[1]);
596 if (ret < 0)
597 goto out_free_memmap;
598 }
599
Luciano Coelho12419cc2010-02-18 13:25:44 +0200600 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200601 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300602 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200603 goto out_free_memmap;
604
605 /* Configure for CAM power saving (ie. always active) */
606 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
607 if (ret < 0)
608 goto out_free_memmap;
609
610 /* configure PM */
611 ret = wl1271_acx_pm_config(wl);
612 if (ret < 0)
613 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300614
615 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200616
617 out_free_memmap:
618 kfree(wl->target_mem_map);
619 wl->target_mem_map = NULL;
620
621 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300622}
623
Arik Nemtsovb622d992011-02-23 00:22:31 +0200624static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
625{
626 bool fw_ps;
627
628 /* only regulate station links */
629 if (hlid < WL1271_AP_STA_HLID_START)
630 return;
631
632 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
633
634 /*
635 * Wake up from high level PS if the STA is asleep with too little
636 * blocks in FW or if the STA is awake.
637 */
638 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
639 wl1271_ps_link_end(wl, hlid);
640
641 /* Start high-level PS if the STA is asleep with enough blocks in FW */
642 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
643 wl1271_ps_link_start(wl, hlid, true);
644}
645
646static void wl1271_irq_update_links_status(struct wl1271 *wl,
647 struct wl1271_fw_ap_status *status)
648{
649 u32 cur_fw_ps_map;
650 u8 hlid;
651
652 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
653 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
654 wl1271_debug(DEBUG_PSM,
655 "link ps prev 0x%x cur 0x%x changed 0x%x",
656 wl->ap_fw_ps_map, cur_fw_ps_map,
657 wl->ap_fw_ps_map ^ cur_fw_ps_map);
658
659 wl->ap_fw_ps_map = cur_fw_ps_map;
660 }
661
662 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
663 u8 cnt = status->tx_lnk_free_blks[hlid] -
664 wl->links[hlid].prev_freed_blks;
665
666 wl->links[hlid].prev_freed_blks =
667 status->tx_lnk_free_blks[hlid];
668 wl->links[hlid].allocated_blks -= cnt;
669
670 wl1271_irq_ps_regulate_link(wl, hlid,
671 wl->links[hlid].allocated_blks);
672 }
673}
674
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300675static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200676 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200678 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200679 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200680 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200681 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300682 int i;
683
Shahar Levi13b107d2011-03-06 16:32:12 +0200684 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200685 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
686 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200687 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200688 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
689 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200690 }
691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300692 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
693 "drv_rx_counter = %d, tx_results_counter = %d)",
694 status->intr,
695 status->fw_rx_counter,
696 status->drv_rx_counter,
697 status->tx_results_counter);
698
699 /* update number of available TX blocks */
700 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200701 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
702 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300703
704 wl->tx_blocks_freed[i] =
705 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200706 }
707
Ido Yarivd2f4d472011-03-31 10:07:00 +0200708 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200709
Ido Yarivd2f4d472011-03-31 10:07:00 +0200710 if (wl->bss_type == BSS_TYPE_AP_BSS) {
711 /* Update num of allocated TX blocks per link and ps status */
712 wl1271_irq_update_links_status(wl, &full_status->ap);
713 wl->tx_blocks_available += freed_blocks;
714 } else {
715 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
716
717 /*
718 * The FW might change the total number of TX memblocks before
719 * we get a notification about blocks being released. Thus, the
720 * available blocks calculation might yield a temporary result
721 * which is lower than the actual available blocks. Keeping in
722 * mind that only blocks that were allocated can be moved from
723 * TX to RX, tx_blocks_available should never decrease here.
724 */
725 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
726 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727 }
728
Ido Yariva5225502010-10-12 14:49:10 +0200729 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200730 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200731 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732
733 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200734 getnstimeofday(&ts);
735 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
736 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300737}
738
Ido Yariva6208652011-03-01 15:14:41 +0200739static void wl1271_flush_deferred_work(struct wl1271 *wl)
740{
741 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200742
Ido Yariva6208652011-03-01 15:14:41 +0200743 /* Pass all received frames to the network stack */
744 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
745 ieee80211_rx_ni(wl->hw, skb);
746
747 /* Return sent skbs to the network stack */
748 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
749 ieee80211_tx_status(wl->hw, skb);
750}
751
752static void wl1271_netstack_work(struct work_struct *work)
753{
754 struct wl1271 *wl =
755 container_of(work, struct wl1271, netstack_work);
756
757 do {
758 wl1271_flush_deferred_work(wl);
759 } while (skb_queue_len(&wl->deferred_rx_queue));
760}
761
762#define WL1271_IRQ_MAX_LOOPS 256
763
764irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300765{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300767 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200768 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200769 struct wl1271 *wl = (struct wl1271 *)cookie;
770 bool done = false;
771 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200772 unsigned long flags;
773
774 /* TX might be handled here, avoid redundant work */
775 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
776 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777
Ido Yariv341b7cd2011-03-31 10:07:01 +0200778 /*
779 * In case edge triggered interrupt must be used, we cannot iterate
780 * more than once without introducing race conditions with the hardirq.
781 */
782 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
783 loopcount = 1;
784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 mutex_lock(&wl->mutex);
786
787 wl1271_debug(DEBUG_IRQ, "IRQ work");
788
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200789 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 goto out;
791
Ido Yariva6208652011-03-01 15:14:41 +0200792 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300793 if (ret < 0)
794 goto out;
795
Ido Yariva6208652011-03-01 15:14:41 +0200796 while (!done && loopcount--) {
797 /*
798 * In order to avoid a race with the hardirq, clear the flag
799 * before acknowledging the chip. Since the mutex is held,
800 * wl1271_ps_elp_wakeup cannot be called concurrently.
801 */
802 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
803 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200804
805 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200806 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200807 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200808 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200809 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200810 continue;
811 }
812
Eliad Pellerccc83b02010-10-27 14:09:57 +0200813 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
814 wl1271_error("watchdog interrupt received! "
815 "starting recovery.");
816 ieee80211_queue_work(wl->hw, &wl->recovery_work);
817
818 /* restarting the chip. ignore any other interrupt. */
819 goto out;
820 }
821
Ido Yariva6208652011-03-01 15:14:41 +0200822 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200823 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
824
Ido Yariv8aad2462011-03-01 15:14:38 +0200825 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200826
Ido Yariva5225502010-10-12 14:49:10 +0200827 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200828 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200829 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200830 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200831 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200832 /*
833 * In order to avoid starvation of the TX path,
834 * call the work function directly.
835 */
836 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200837 } else {
838 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200839 }
840
Ido Yariv8aad2462011-03-01 15:14:38 +0200841 /* check for tx results */
842 if (wl->fw_status->common.tx_results_counter !=
843 (wl->tx_results_count & 0xff))
844 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200845
846 /* Make sure the deferred queues don't get too long */
847 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
848 skb_queue_len(&wl->deferred_rx_queue);
849 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
850 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200851 }
852
853 if (intr & WL1271_ACX_INTR_EVENT_A) {
854 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
855 wl1271_event_handle(wl, 0);
856 }
857
858 if (intr & WL1271_ACX_INTR_EVENT_B) {
859 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
860 wl1271_event_handle(wl, 1);
861 }
862
863 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
864 wl1271_debug(DEBUG_IRQ,
865 "WL1271_ACX_INTR_INIT_COMPLETE");
866
867 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
868 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300869 }
870
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300871 wl1271_ps_elp_sleep(wl);
872
873out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200874 spin_lock_irqsave(&wl->wl_lock, flags);
875 /* In case TX was not handled here, queue TX work */
876 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
878 wl->tx_queue_count)
879 ieee80211_queue_work(wl->hw, &wl->tx_work);
880 spin_unlock_irqrestore(&wl->wl_lock, flags);
881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200883
884 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300885}
Ido Yariva6208652011-03-01 15:14:41 +0200886EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888static int wl1271_fetch_firmware(struct wl1271 *wl)
889{
890 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200891 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892 int ret;
893
Arik Nemtsov166d5042010-10-16 21:44:57 +0200894 switch (wl->bss_type) {
895 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200896 if (wl->chip.id == CHIP_ID_1283_PG20)
897 fw_name = WL128X_AP_FW_NAME;
898 else
899 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200900 break;
901 case BSS_TYPE_IBSS:
902 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200903 if (wl->chip.id == CHIP_ID_1283_PG20)
904 fw_name = WL128X_FW_NAME;
905 else
906 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200907 break;
908 default:
909 wl1271_error("no compatible firmware for bss_type %d",
910 wl->bss_type);
911 return -EINVAL;
912 }
913
914 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
915
916 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300917
918 if (ret < 0) {
919 wl1271_error("could not get firmware: %d", ret);
920 return ret;
921 }
922
923 if (fw->size % 4) {
924 wl1271_error("firmware size is not multiple of 32 bits: %zu",
925 fw->size);
926 ret = -EILSEQ;
927 goto out;
928 }
929
Arik Nemtsov166d5042010-10-16 21:44:57 +0200930 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300932 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933
934 if (!wl->fw) {
935 wl1271_error("could not allocate memory for the firmware");
936 ret = -ENOMEM;
937 goto out;
938 }
939
940 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200941 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942 ret = 0;
943
944out:
945 release_firmware(fw);
946
947 return ret;
948}
949
950static int wl1271_fetch_nvs(struct wl1271 *wl)
951{
952 const struct firmware *fw;
953 int ret;
954
Shahar Levi5aa42342011-03-06 16:32:07 +0200955 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956
957 if (ret < 0) {
958 wl1271_error("could not get nvs file: %d", ret);
959 return ret;
960 }
961
Shahar Levibc765bf2011-03-06 16:32:10 +0200962 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300963
964 if (!wl->nvs) {
965 wl1271_error("could not allocate memory for the nvs file");
966 ret = -ENOMEM;
967 goto out;
968 }
969
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200970 wl->nvs_len = fw->size;
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972out:
973 release_firmware(fw);
974
975 return ret;
976}
977
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200978static void wl1271_recovery_work(struct work_struct *work)
979{
980 struct wl1271 *wl =
981 container_of(work, struct wl1271, recovery_work);
982
983 mutex_lock(&wl->mutex);
984
985 if (wl->state != WL1271_STATE_ON)
986 goto out;
987
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300988 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
989 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200990
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200991 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
992 ieee80211_connection_loss(wl->vif);
993
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300994 /* Prevent spurious TX during FW restart */
995 ieee80211_stop_queues(wl->hw);
996
Luciano Coelho33c2c062011-05-10 14:46:02 +0300997 if (wl->sched_scanning) {
998 ieee80211_sched_scan_stopped(wl->hw);
999 wl->sched_scanning = false;
1000 }
1001
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001002 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001003 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001004 ieee80211_restart_hw(wl->hw);
1005
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001006 /*
1007 * Its safe to enable TX now - the queues are stopped after a request
1008 * to restart the HW.
1009 */
1010 ieee80211_wake_queues(wl->hw);
1011
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001012out:
1013 mutex_unlock(&wl->mutex);
1014}
1015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016static void wl1271_fw_wakeup(struct wl1271 *wl)
1017{
1018 u32 elp_reg;
1019
1020 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001021 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022}
1023
1024static int wl1271_setup(struct wl1271 *wl)
1025{
1026 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1027 if (!wl->fw_status)
1028 return -ENOMEM;
1029
1030 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1031 if (!wl->tx_res_if) {
1032 kfree(wl->fw_status);
1033 return -ENOMEM;
1034 }
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 return 0;
1037}
1038
1039static int wl1271_chip_wakeup(struct wl1271 *wl)
1040{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001041 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 int ret = 0;
1043
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001044 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001045 ret = wl1271_power_on(wl);
1046 if (ret < 0)
1047 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001049 wl1271_io_reset(wl);
1050 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051
1052 /* We don't need a real memory partition here, because we only want
1053 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001054 memset(&partition, 0, sizeof(partition));
1055 partition.reg.start = REGISTERS_BASE;
1056 partition.reg.size = REGISTERS_DOWN_SIZE;
1057 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
1059 /* ELP module wake up */
1060 wl1271_fw_wakeup(wl);
1061
1062 /* whal_FwCtrl_BootSm() */
1063
1064 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001065 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066
1067 /* 1. check if chip id is valid */
1068
1069 switch (wl->chip.id) {
1070 case CHIP_ID_1271_PG10:
1071 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1072 wl->chip.id);
1073
1074 ret = wl1271_setup(wl);
1075 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001076 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001077 break;
1078 case CHIP_ID_1271_PG20:
1079 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1080 wl->chip.id);
1081
Shahar Levi564f5952011-04-04 10:20:39 +03001082 /* end-of-transaction flag should be set in wl127x AP mode */
1083 if (wl->bss_type == BSS_TYPE_AP_BSS)
1084 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1085
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001086 ret = wl1271_setup(wl);
1087 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001088 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001090 case CHIP_ID_1283_PG20:
1091 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1092 wl->chip.id);
1093
1094 ret = wl1271_setup(wl);
1095 if (ret < 0)
1096 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001097 if (wl1271_set_block_size(wl))
1098 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001099 break;
1100 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001102 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001104 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105 }
1106
Arik Nemtsov166d5042010-10-16 21:44:57 +02001107 /* Make sure the firmware type matches the BSS type */
1108 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001109 ret = wl1271_fetch_firmware(wl);
1110 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001111 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112 }
1113
1114 /* No NVS from netlink, try to get it from the filesystem */
1115 if (wl->nvs == NULL) {
1116 ret = wl1271_fetch_nvs(wl);
1117 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001118 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119 }
1120
1121out:
1122 return ret;
1123}
1124
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001125static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1126{
1127 unsigned int quirks = 0;
1128 unsigned int *fw_ver = wl->chip.fw_ver;
1129
1130 /* Only for wl127x */
1131 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1132 /* Check STA version */
1133 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1134 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1135 /* Check AP version */
1136 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1137 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1138 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1139
1140 return quirks;
1141}
1142
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001143int wl1271_plt_start(struct wl1271 *wl)
1144{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001145 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146 int ret;
1147
1148 mutex_lock(&wl->mutex);
1149
1150 wl1271_notice("power up");
1151
1152 if (wl->state != WL1271_STATE_OFF) {
1153 wl1271_error("cannot go into PLT state because not "
1154 "in off state: %d", wl->state);
1155 ret = -EBUSY;
1156 goto out;
1157 }
1158
Arik Nemtsov166d5042010-10-16 21:44:57 +02001159 wl->bss_type = BSS_TYPE_STA_BSS;
1160
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001161 while (retries) {
1162 retries--;
1163 ret = wl1271_chip_wakeup(wl);
1164 if (ret < 0)
1165 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001166
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001167 ret = wl1271_boot(wl);
1168 if (ret < 0)
1169 goto power_off;
1170
1171 ret = wl1271_plt_init(wl);
1172 if (ret < 0)
1173 goto irq_disable;
1174
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001175 wl->state = WL1271_STATE_PLT;
1176 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001177 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001178
1179 /* Check if any quirks are needed with older fw versions */
1180 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001181 goto out;
1182
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001183irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001184 mutex_unlock(&wl->mutex);
1185 /* Unlocking the mutex in the middle of handling is
1186 inherently unsafe. In this case we deem it safe to do,
1187 because we need to let any possibly pending IRQ out of
1188 the system (and while we are WL1271_STATE_OFF the IRQ
1189 work function will not do anything.) Also, any other
1190 possible concurrent operations will fail due to the
1191 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001192 wl1271_disable_interrupts(wl);
1193 wl1271_flush_deferred_work(wl);
1194 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001195 mutex_lock(&wl->mutex);
1196power_off:
1197 wl1271_power_off(wl);
1198 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001199
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001200 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1201 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202out:
1203 mutex_unlock(&wl->mutex);
1204
1205 return ret;
1206}
1207
Luciano Coelho4623ec72011-03-21 19:26:41 +02001208static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001209{
1210 int ret = 0;
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212 wl1271_notice("power down");
1213
1214 if (wl->state != WL1271_STATE_PLT) {
1215 wl1271_error("cannot power down because not in PLT "
1216 "state: %d", wl->state);
1217 ret = -EBUSY;
1218 goto out;
1219 }
1220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001221 wl1271_power_off(wl);
1222
1223 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001224 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001227 wl1271_disable_interrupts(wl);
1228 wl1271_flush_deferred_work(wl);
1229 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001230 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001231 mutex_lock(&wl->mutex);
1232out:
1233 return ret;
1234}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001235
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001236int wl1271_plt_stop(struct wl1271 *wl)
1237{
1238 int ret;
1239
1240 mutex_lock(&wl->mutex);
1241 ret = __wl1271_plt_stop(wl);
1242 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243 return ret;
1244}
1245
Johannes Berg7bb45682011-02-24 14:42:06 +01001246static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247{
1248 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001249 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001250 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001251 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252
Ido Yarivb07d4032011-03-01 15:14:43 +02001253 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1254
1255 if (wl->bss_type == BSS_TYPE_AP_BSS)
1256 hlid = wl1271_tx_get_hlid(skb);
1257
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001258 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001259
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001260 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001261
1262 /*
1263 * The workqueue is slow to process the tx_queue and we need stop
1264 * the queue here, otherwise the queue will get too long.
1265 */
1266 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1267 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1268 ieee80211_stop_queues(wl->hw);
1269 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1270 }
1271
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001272 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001273 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001274 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1275 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1276 } else {
1277 skb_queue_tail(&wl->tx_queue[q], skb);
1278 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279
1280 /*
1281 * The chip specific setup must run before the first TX packet -
1282 * before that, the tx_work will not be initialized!
1283 */
1284
Ido Yarivb07d4032011-03-01 15:14:43 +02001285 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1286 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001287 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001288
1289 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290}
1291
Shahar Leviae47c452011-03-06 16:32:14 +02001292int wl1271_tx_dummy_packet(struct wl1271 *wl)
1293{
Ido Yariv990f5de2011-03-31 10:06:59 +02001294 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001295
Ido Yariv990f5de2011-03-31 10:06:59 +02001296 spin_lock_irqsave(&wl->wl_lock, flags);
1297 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1298 wl->tx_queue_count++;
1299 spin_unlock_irqrestore(&wl->wl_lock, flags);
1300
1301 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1302 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1303 wl1271_tx_work_locked(wl);
1304
1305 /*
1306 * If the FW TX is busy, TX work will be scheduled by the threaded
1307 * interrupt handler function
1308 */
1309 return 0;
1310}
1311
1312/*
1313 * The size of the dummy packet should be at least 1400 bytes. However, in
1314 * order to minimize the number of bus transactions, aligning it to 512 bytes
1315 * boundaries could be beneficial, performance wise
1316 */
1317#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1318
Luciano Coelhocf27d862011-04-01 21:08:23 +03001319static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001320{
1321 struct sk_buff *skb;
1322 struct ieee80211_hdr_3addr *hdr;
1323 unsigned int dummy_packet_size;
1324
1325 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1326 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1327
1328 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001329 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001330 wl1271_warning("Failed to allocate a dummy packet skb");
1331 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001332 }
1333
1334 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1335
1336 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1337 memset(hdr, 0, sizeof(*hdr));
1338 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001339 IEEE80211_STYPE_NULLFUNC |
1340 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001341
Ido Yariv990f5de2011-03-31 10:06:59 +02001342 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001343
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001344 /* Dummy packets require the TID to be management */
1345 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001346
1347 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001348 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001349 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001350
Ido Yariv990f5de2011-03-31 10:06:59 +02001351 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001352}
1353
Ido Yariv990f5de2011-03-31 10:06:59 +02001354
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001355static struct notifier_block wl1271_dev_notifier = {
1356 .notifier_call = wl1271_dev_notify,
1357};
1358
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001359#ifdef CONFIG_PM
Eliad Peller94390642011-05-13 11:57:13 +03001360static int wl1271_configure_suspend(struct wl1271 *wl)
1361{
1362 int ret;
1363
1364 if (wl->bss_type != BSS_TYPE_STA_BSS)
1365 return 0;
1366
1367 mutex_lock(&wl->mutex);
1368
1369 ret = wl1271_ps_elp_wakeup(wl);
1370 if (ret < 0)
1371 goto out_unlock;
1372
1373 /* enter psm if needed*/
1374 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1375 DECLARE_COMPLETION_ONSTACK(compl);
1376
1377 wl->ps_compl = &compl;
1378 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1379 wl->basic_rate, true);
1380 if (ret < 0)
1381 goto out_sleep;
1382
1383 /* we must unlock here so we will be able to get events */
1384 wl1271_ps_elp_sleep(wl);
1385 mutex_unlock(&wl->mutex);
1386
1387 ret = wait_for_completion_timeout(
1388 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1389 if (ret <= 0) {
1390 wl1271_warning("couldn't enter ps mode!");
1391 ret = -EBUSY;
1392 goto out;
1393 }
1394
1395 /* take mutex again, and wakeup */
1396 mutex_lock(&wl->mutex);
1397
1398 ret = wl1271_ps_elp_wakeup(wl);
1399 if (ret < 0)
1400 goto out_unlock;
1401 }
1402out_sleep:
1403 wl1271_ps_elp_sleep(wl);
1404out_unlock:
1405 mutex_unlock(&wl->mutex);
1406out:
1407 return ret;
1408
1409}
1410
1411static void wl1271_configure_resume(struct wl1271 *wl)
1412{
1413 int ret;
1414
1415 if (wl->bss_type != BSS_TYPE_STA_BSS)
1416 return;
1417
1418 mutex_lock(&wl->mutex);
1419 ret = wl1271_ps_elp_wakeup(wl);
1420 if (ret < 0)
1421 goto out;
1422
1423 /* exit psm if it wasn't configured */
1424 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1425 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1426 wl->basic_rate, true);
1427
1428 wl1271_ps_elp_sleep(wl);
1429out:
1430 mutex_unlock(&wl->mutex);
1431}
1432
Eliad Peller402e48612011-05-13 11:57:09 +03001433static int wl1271_op_suspend(struct ieee80211_hw *hw,
1434 struct cfg80211_wowlan *wow)
1435{
1436 struct wl1271 *wl = hw->priv;
1437 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1438 wl->wow_enabled = !!wow;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001439 if (wl->wow_enabled) {
Eliad Peller94390642011-05-13 11:57:13 +03001440 int ret;
1441 ret = wl1271_configure_suspend(wl);
1442 if (ret < 0) {
1443 wl1271_warning("couldn't prepare device to suspend");
1444 return ret;
1445 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001446 /* flush any remaining work */
1447 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1448 flush_delayed_work(&wl->scan_complete_work);
1449
1450 /*
1451 * disable and re-enable interrupts in order to flush
1452 * the threaded_irq
1453 */
1454 wl1271_disable_interrupts(wl);
1455
1456 /*
1457 * set suspended flag to avoid triggering a new threaded_irq
1458 * work. no need for spinlock as interrupts are disabled.
1459 */
1460 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1461
1462 wl1271_enable_interrupts(wl);
1463 flush_work(&wl->tx_work);
1464 flush_delayed_work(&wl->pspoll_work);
1465 flush_delayed_work(&wl->elp_work);
1466 }
Eliad Peller402e48612011-05-13 11:57:09 +03001467 return 0;
1468}
1469
1470static int wl1271_op_resume(struct ieee80211_hw *hw)
1471{
1472 struct wl1271 *wl = hw->priv;
1473 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1474 wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001475
1476 /*
1477 * re-enable irq_work enqueuing, and call irq_work directly if
1478 * there is a pending work.
1479 */
1480 if (wl->wow_enabled) {
1481 struct wl1271 *wl = hw->priv;
1482 unsigned long flags;
1483 bool run_irq_work = false;
1484
1485 spin_lock_irqsave(&wl->wl_lock, flags);
1486 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1487 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1488 run_irq_work = true;
1489 spin_unlock_irqrestore(&wl->wl_lock, flags);
1490
1491 if (run_irq_work) {
1492 wl1271_debug(DEBUG_MAC80211,
1493 "run postponed irq_work directly");
1494 wl1271_irq(0, wl);
1495 wl1271_enable_interrupts(wl);
1496 }
Eliad Peller94390642011-05-13 11:57:13 +03001497
1498 wl1271_configure_resume(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001499 }
1500
Eliad Peller402e48612011-05-13 11:57:09 +03001501 return 0;
1502}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001503#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001504
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001505static int wl1271_op_start(struct ieee80211_hw *hw)
1506{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001507 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1508
1509 /*
1510 * We have to delay the booting of the hardware because
1511 * we need to know the local MAC address before downloading and
1512 * initializing the firmware. The MAC address cannot be changed
1513 * after boot, and without the proper MAC address, the firmware
1514 * will not function properly.
1515 *
1516 * The MAC address is first known when the corresponding interface
1517 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001518 *
1519 * In addition, we currently have different firmwares for AP and managed
1520 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001521 */
1522
1523 return 0;
1524}
1525
1526static void wl1271_op_stop(struct ieee80211_hw *hw)
1527{
1528 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1529}
1530
1531static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1532 struct ieee80211_vif *vif)
1533{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001535 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001536 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001538 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001539
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001540 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1541 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001542
1543 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001544 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001545 wl1271_debug(DEBUG_MAC80211,
1546 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001547 ret = -EBUSY;
1548 goto out;
1549 }
1550
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001551 /*
1552 * in some very corner case HW recovery scenarios its possible to
1553 * get here before __wl1271_op_remove_interface is complete, so
1554 * opt out if that is the case.
1555 */
1556 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1557 ret = -EBUSY;
1558 goto out;
1559 }
1560
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001561 switch (vif->type) {
1562 case NL80211_IFTYPE_STATION:
1563 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001564 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001565 break;
1566 case NL80211_IFTYPE_ADHOC:
1567 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001568 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001569 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001570 case NL80211_IFTYPE_AP:
1571 wl->bss_type = BSS_TYPE_AP_BSS;
1572 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001573 default:
1574 ret = -EOPNOTSUPP;
1575 goto out;
1576 }
1577
1578 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579
1580 if (wl->state != WL1271_STATE_OFF) {
1581 wl1271_error("cannot start because not in off state: %d",
1582 wl->state);
1583 ret = -EBUSY;
1584 goto out;
1585 }
1586
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001587 while (retries) {
1588 retries--;
1589 ret = wl1271_chip_wakeup(wl);
1590 if (ret < 0)
1591 goto power_off;
1592
1593 ret = wl1271_boot(wl);
1594 if (ret < 0)
1595 goto power_off;
1596
1597 ret = wl1271_hw_init(wl);
1598 if (ret < 0)
1599 goto irq_disable;
1600
Eliad Peller71125ab2010-10-28 21:46:43 +02001601 booted = true;
1602 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001603
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001604irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001605 mutex_unlock(&wl->mutex);
1606 /* Unlocking the mutex in the middle of handling is
1607 inherently unsafe. In this case we deem it safe to do,
1608 because we need to let any possibly pending IRQ out of
1609 the system (and while we are WL1271_STATE_OFF the IRQ
1610 work function will not do anything.) Also, any other
1611 possible concurrent operations will fail due to the
1612 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001613 wl1271_disable_interrupts(wl);
1614 wl1271_flush_deferred_work(wl);
1615 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001616 mutex_lock(&wl->mutex);
1617power_off:
1618 wl1271_power_off(wl);
1619 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001620
Eliad Peller71125ab2010-10-28 21:46:43 +02001621 if (!booted) {
1622 wl1271_error("firmware boot failed despite %d retries",
1623 WL1271_BOOT_RETRIES);
1624 goto out;
1625 }
1626
1627 wl->vif = vif;
1628 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001629 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001630 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001631
1632 /* update hw/fw version info in wiphy struct */
1633 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001634 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001635 sizeof(wiphy->fw_version));
1636
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001637 /* Check if any quirks are needed with older fw versions */
1638 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1639
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001640 /*
1641 * Now we know if 11a is supported (info from the NVS), so disable
1642 * 11a channels if not supported
1643 */
1644 if (!wl->enable_11a)
1645 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1646
1647 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1648 wl->enable_11a ? "" : "not ");
1649
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001650out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001651 mutex_unlock(&wl->mutex);
1652
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001653 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001654 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001655 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001656 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658 return ret;
1659}
1660
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001661static void __wl1271_op_remove_interface(struct wl1271 *wl,
1662 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001663{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001664 int i;
1665
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001666 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001667
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001668 /* because of hardware recovery, we may get here twice */
1669 if (wl->state != WL1271_STATE_ON)
1670 return;
1671
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001672 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001673
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001674 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001675 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001676 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001677
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001678 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001679 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001680 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001681
Luciano Coelho08688d62010-07-08 17:50:07 +03001682 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001683 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001684 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001685 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001686 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 }
1688
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001689 /*
1690 * this must be before the cancel_work calls below, so that the work
1691 * functions don't perform further work.
1692 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 wl->state = WL1271_STATE_OFF;
1694
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001695 mutex_unlock(&wl->mutex);
1696
Ido Yariva6208652011-03-01 15:14:41 +02001697 wl1271_disable_interrupts(wl);
1698 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001699 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001700 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001702 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001703 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704
1705 mutex_lock(&wl->mutex);
1706
1707 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001708 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 wl1271_power_off(wl);
1710
1711 memset(wl->bssid, 0, ETH_ALEN);
1712 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1713 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001714 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001715 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001716 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001717
1718 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001719 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001720 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1721 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001722 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001723 wl->tx_results_count = 0;
1724 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001725 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001726 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727 wl->time_offset = 0;
1728 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001729 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001730 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001731 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001732 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001733 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001734 wl->ap_fw_ps_map = 0;
1735 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001736 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001737
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001738 /*
1739 * this is performed after the cancel_work calls and the associated
1740 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1741 * get executed before all these vars have been reset.
1742 */
1743 wl->flags = 0;
1744
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001745 for (i = 0; i < NUM_TX_QUEUES; i++)
1746 wl->tx_blocks_freed[i] = 0;
1747
1748 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001749
1750 kfree(wl->fw_status);
1751 wl->fw_status = NULL;
1752 kfree(wl->tx_res_if);
1753 wl->tx_res_if = NULL;
1754 kfree(wl->target_mem_map);
1755 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001756}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001757
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001758static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1759 struct ieee80211_vif *vif)
1760{
1761 struct wl1271 *wl = hw->priv;
1762
1763 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001764 /*
1765 * wl->vif can be null here if someone shuts down the interface
1766 * just when hardware recovery has been started.
1767 */
1768 if (wl->vif) {
1769 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001770 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001771 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001772
Juuso Oikarinen67353292010-11-18 15:19:02 +02001773 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001774 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001775}
1776
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001777void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001778{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001779 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001780
1781 /* combine requested filters with current filter config */
1782 filters = wl->filters | filters;
1783
1784 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1785
1786 if (filters & FIF_PROMISC_IN_BSS) {
1787 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1788 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1789 wl->rx_config |= CFG_BSSID_FILTER_EN;
1790 }
1791 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1792 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1793 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1794 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1795 }
1796 if (filters & FIF_OTHER_BSS) {
1797 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1798 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1799 }
1800 if (filters & FIF_CONTROL) {
1801 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1802 wl->rx_filter |= CFG_RX_CTL_EN;
1803 }
1804 if (filters & FIF_FCSFAIL) {
1805 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1806 wl->rx_filter |= CFG_RX_FCS_ERROR;
1807 }
1808}
1809
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001810static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001811{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001812 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001813 /* we need to use a dummy BSSID for now */
1814 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1815 0xad, 0xbe, 0xef };
1816
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001817 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1818
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001819 /* pass through frames from all BSS */
1820 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1821
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001822 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001823 if (ret < 0)
1824 goto out;
1825
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001826 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001827
1828out:
1829 return ret;
1830}
1831
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001832static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001833{
1834 int ret;
1835
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001836 /*
1837 * One of the side effects of the JOIN command is that is clears
1838 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1839 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001840 * Currently the only valid scenario for JOIN during association
1841 * is on roaming, in which case we will also be given new keys.
1842 * Keep the below message for now, unless it starts bothering
1843 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001844 */
1845 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1846 wl1271_info("JOIN while associated.");
1847
1848 if (set_assoc)
1849 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1850
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001851 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1852 if (ret < 0)
1853 goto out;
1854
1855 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1856
1857 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1858 goto out;
1859
1860 /*
1861 * The join command disable the keep-alive mode, shut down its process,
1862 * and also clear the template config, so we need to reset it all after
1863 * the join. The acx_aid starts the keep-alive process, and the order
1864 * of the commands below is relevant.
1865 */
1866 ret = wl1271_acx_keep_alive_mode(wl, true);
1867 if (ret < 0)
1868 goto out;
1869
1870 ret = wl1271_acx_aid(wl, wl->aid);
1871 if (ret < 0)
1872 goto out;
1873
1874 ret = wl1271_cmd_build_klv_null_data(wl);
1875 if (ret < 0)
1876 goto out;
1877
1878 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1879 ACX_KEEP_ALIVE_TPL_VALID);
1880 if (ret < 0)
1881 goto out;
1882
1883out:
1884 return ret;
1885}
1886
1887static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001888{
1889 int ret;
1890
1891 /* to stop listening to a channel, we disconnect */
1892 ret = wl1271_cmd_disconnect(wl);
1893 if (ret < 0)
1894 goto out;
1895
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001896 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001897 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001898
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001899 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001900 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001901
1902out:
1903 return ret;
1904}
1905
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001906static void wl1271_set_band_rate(struct wl1271 *wl)
1907{
1908 if (wl->band == IEEE80211_BAND_2GHZ)
1909 wl->basic_rate_set = wl->conf.tx.basic_rate;
1910 else
1911 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1912}
1913
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001914static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001915{
1916 int ret;
1917
1918 if (idle) {
1919 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1920 ret = wl1271_unjoin(wl);
1921 if (ret < 0)
1922 goto out;
1923 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001924 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001925 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001926 if (ret < 0)
1927 goto out;
1928 ret = wl1271_acx_keep_alive_config(
1929 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1930 ACX_KEEP_ALIVE_TPL_INVALID);
1931 if (ret < 0)
1932 goto out;
1933 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1934 } else {
1935 /* increment the session counter */
1936 wl->session_counter++;
1937 if (wl->session_counter >= SESSION_COUNTER_MAX)
1938 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001939
1940 /* The current firmware only supports sched_scan in idle */
1941 if (wl->sched_scanning) {
1942 wl1271_scan_sched_scan_stop(wl);
1943 ieee80211_sched_scan_stopped(wl->hw);
1944 }
1945
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001946 ret = wl1271_dummy_join(wl);
1947 if (ret < 0)
1948 goto out;
1949 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1950 }
1951
1952out:
1953 return ret;
1954}
1955
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001956static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1957{
1958 struct wl1271 *wl = hw->priv;
1959 struct ieee80211_conf *conf = &hw->conf;
1960 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001961 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962
1963 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1964
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001965 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1966 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967 channel,
1968 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001969 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001970 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1971 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001972
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001973 /*
1974 * mac80211 will go to idle nearly immediately after transmitting some
1975 * frames, such as the deauth. To make sure those frames reach the air,
1976 * wait here until the TX queue is fully flushed.
1977 */
1978 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1979 (conf->flags & IEEE80211_CONF_IDLE))
1980 wl1271_tx_flush(wl);
1981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982 mutex_lock(&wl->mutex);
1983
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001984 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001985 /* we support configuring the channel and band while off */
1986 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1987 wl->band = conf->channel->band;
1988 wl->channel = channel;
1989 }
1990
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001991 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001992 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001993
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001994 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1995
Ido Yariva6208652011-03-01 15:14:41 +02001996 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 if (ret < 0)
1998 goto out;
1999
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002000 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002001 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2002 ((wl->band != conf->channel->band) ||
2003 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002004 wl->band = conf->channel->band;
2005 wl->channel = channel;
2006
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002007 if (!is_ap) {
2008 /*
2009 * FIXME: the mac80211 should really provide a fixed
2010 * rate to use here. for now, just use the smallest
2011 * possible rate for the band as a fixed rate for
2012 * association frames and other control messages.
2013 */
2014 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2015 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002016
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002017 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2018 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002019 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002020 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002021 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002022
2023 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2024 ret = wl1271_join(wl, false);
2025 if (ret < 0)
2026 wl1271_warning("cmd join on channel "
2027 "failed %d", ret);
2028 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002029 }
2030 }
2031
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002032 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2033 ret = wl1271_sta_handle_idle(wl,
2034 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002035 if (ret < 0)
2036 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037 }
2038
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002039 /*
2040 * if mac80211 changes the PSM mode, make sure the mode is not
2041 * incorrectly changed after the pspoll failure active window.
2042 */
2043 if (changed & IEEE80211_CONF_CHANGE_PS)
2044 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2045
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002046 if (conf->flags & IEEE80211_CONF_PS &&
2047 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2048 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049
2050 /*
2051 * We enter PSM only if we're already associated.
2052 * If we're not, we'll enter it when joining an SSID,
2053 * through the bss_info_changed() hook.
2054 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002055 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002056 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002057 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002058 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002059 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002061 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002062 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002063
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002064 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002066 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002067 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002068 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069 }
2070
2071 if (conf->power_level != wl->power_level) {
2072 ret = wl1271_acx_tx_power(wl, conf->power_level);
2073 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002074 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075
2076 wl->power_level = conf->power_level;
2077 }
2078
2079out_sleep:
2080 wl1271_ps_elp_sleep(wl);
2081
2082out:
2083 mutex_unlock(&wl->mutex);
2084
2085 return ret;
2086}
2087
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002088struct wl1271_filter_params {
2089 bool enabled;
2090 int mc_list_length;
2091 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2092};
2093
Jiri Pirko22bedad2010-04-01 21:22:57 +00002094static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2095 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002096{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002097 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002098 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002099 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002100
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002101 if (unlikely(wl->state == WL1271_STATE_OFF))
2102 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002103
Juuso Oikarinen74441132009-10-13 12:47:53 +03002104 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002105 if (!fp) {
2106 wl1271_error("Out of memory setting filters.");
2107 return 0;
2108 }
2109
2110 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002111 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002112 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2113 fp->enabled = false;
2114 } else {
2115 fp->enabled = true;
2116 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002117 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002118 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002119 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002120 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002121 }
2122
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002123 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002124}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002126#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2127 FIF_ALLMULTI | \
2128 FIF_FCSFAIL | \
2129 FIF_BCN_PRBRESP_PROMISC | \
2130 FIF_CONTROL | \
2131 FIF_OTHER_BSS)
2132
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2134 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002135 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002136{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002137 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002139 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002140
Arik Nemtsov7d057862010-10-16 19:25:35 +02002141 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2142 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002144 mutex_lock(&wl->mutex);
2145
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002146 *total &= WL1271_SUPPORTED_FILTERS;
2147 changed &= WL1271_SUPPORTED_FILTERS;
2148
2149 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002150 goto out;
2151
Ido Yariva6208652011-03-01 15:14:41 +02002152 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002153 if (ret < 0)
2154 goto out;
2155
Arik Nemtsov7d057862010-10-16 19:25:35 +02002156 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2157 if (*total & FIF_ALLMULTI)
2158 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2159 else if (fp)
2160 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2161 fp->mc_list,
2162 fp->mc_list_length);
2163 if (ret < 0)
2164 goto out_sleep;
2165 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002166
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002167 /* determine, whether supported filter values have changed */
2168 if (changed == 0)
2169 goto out_sleep;
2170
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002171 /* configure filters */
2172 wl->filters = *total;
2173 wl1271_configure_filters(wl, 0);
2174
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002175 /* apply configured filters */
2176 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2177 if (ret < 0)
2178 goto out_sleep;
2179
2180out_sleep:
2181 wl1271_ps_elp_sleep(wl);
2182
2183out:
2184 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002185 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002186}
2187
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002188static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2189 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2190 u16 tx_seq_16)
2191{
2192 struct wl1271_ap_key *ap_key;
2193 int i;
2194
2195 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2196
2197 if (key_size > MAX_KEY_SIZE)
2198 return -EINVAL;
2199
2200 /*
2201 * Find next free entry in ap_keys. Also check we are not replacing
2202 * an existing key.
2203 */
2204 for (i = 0; i < MAX_NUM_KEYS; i++) {
2205 if (wl->recorded_ap_keys[i] == NULL)
2206 break;
2207
2208 if (wl->recorded_ap_keys[i]->id == id) {
2209 wl1271_warning("trying to record key replacement");
2210 return -EINVAL;
2211 }
2212 }
2213
2214 if (i == MAX_NUM_KEYS)
2215 return -EBUSY;
2216
2217 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2218 if (!ap_key)
2219 return -ENOMEM;
2220
2221 ap_key->id = id;
2222 ap_key->key_type = key_type;
2223 ap_key->key_size = key_size;
2224 memcpy(ap_key->key, key, key_size);
2225 ap_key->hlid = hlid;
2226 ap_key->tx_seq_32 = tx_seq_32;
2227 ap_key->tx_seq_16 = tx_seq_16;
2228
2229 wl->recorded_ap_keys[i] = ap_key;
2230 return 0;
2231}
2232
2233static void wl1271_free_ap_keys(struct wl1271 *wl)
2234{
2235 int i;
2236
2237 for (i = 0; i < MAX_NUM_KEYS; i++) {
2238 kfree(wl->recorded_ap_keys[i]);
2239 wl->recorded_ap_keys[i] = NULL;
2240 }
2241}
2242
2243static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2244{
2245 int i, ret = 0;
2246 struct wl1271_ap_key *key;
2247 bool wep_key_added = false;
2248
2249 for (i = 0; i < MAX_NUM_KEYS; i++) {
2250 if (wl->recorded_ap_keys[i] == NULL)
2251 break;
2252
2253 key = wl->recorded_ap_keys[i];
2254 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2255 key->id, key->key_type,
2256 key->key_size, key->key,
2257 key->hlid, key->tx_seq_32,
2258 key->tx_seq_16);
2259 if (ret < 0)
2260 goto out;
2261
2262 if (key->key_type == KEY_WEP)
2263 wep_key_added = true;
2264 }
2265
2266 if (wep_key_added) {
2267 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2268 if (ret < 0)
2269 goto out;
2270 }
2271
2272out:
2273 wl1271_free_ap_keys(wl);
2274 return ret;
2275}
2276
2277static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2278 u8 key_size, const u8 *key, u32 tx_seq_32,
2279 u16 tx_seq_16, struct ieee80211_sta *sta)
2280{
2281 int ret;
2282 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2283
2284 if (is_ap) {
2285 struct wl1271_station *wl_sta;
2286 u8 hlid;
2287
2288 if (sta) {
2289 wl_sta = (struct wl1271_station *)sta->drv_priv;
2290 hlid = wl_sta->hlid;
2291 } else {
2292 hlid = WL1271_AP_BROADCAST_HLID;
2293 }
2294
2295 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2296 /*
2297 * We do not support removing keys after AP shutdown.
2298 * Pretend we do to make mac80211 happy.
2299 */
2300 if (action != KEY_ADD_OR_REPLACE)
2301 return 0;
2302
2303 ret = wl1271_record_ap_key(wl, id,
2304 key_type, key_size,
2305 key, hlid, tx_seq_32,
2306 tx_seq_16);
2307 } else {
2308 ret = wl1271_cmd_set_ap_key(wl, action,
2309 id, key_type, key_size,
2310 key, hlid, tx_seq_32,
2311 tx_seq_16);
2312 }
2313
2314 if (ret < 0)
2315 return ret;
2316 } else {
2317 const u8 *addr;
2318 static const u8 bcast_addr[ETH_ALEN] = {
2319 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2320 };
2321
2322 addr = sta ? sta->addr : bcast_addr;
2323
2324 if (is_zero_ether_addr(addr)) {
2325 /* We dont support TX only encryption */
2326 return -EOPNOTSUPP;
2327 }
2328
2329 /* The wl1271 does not allow to remove unicast keys - they
2330 will be cleared automatically on next CMD_JOIN. Ignore the
2331 request silently, as we dont want the mac80211 to emit
2332 an error message. */
2333 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2334 return 0;
2335
2336 ret = wl1271_cmd_set_sta_key(wl, action,
2337 id, key_type, key_size,
2338 key, addr, tx_seq_32,
2339 tx_seq_16);
2340 if (ret < 0)
2341 return ret;
2342
2343 /* the default WEP key needs to be configured at least once */
2344 if (key_type == KEY_WEP) {
2345 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2346 wl->default_key);
2347 if (ret < 0)
2348 return ret;
2349 }
2350 }
2351
2352 return 0;
2353}
2354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2356 struct ieee80211_vif *vif,
2357 struct ieee80211_sta *sta,
2358 struct ieee80211_key_conf *key_conf)
2359{
2360 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002362 u32 tx_seq_32 = 0;
2363 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 u8 key_type;
2365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2367
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002368 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002370 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002371 key_conf->keylen, key_conf->flags);
2372 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2373
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 mutex_lock(&wl->mutex);
2375
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002376 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2377 ret = -EAGAIN;
2378 goto out_unlock;
2379 }
2380
Ido Yariva6208652011-03-01 15:14:41 +02002381 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002382 if (ret < 0)
2383 goto out_unlock;
2384
Johannes Berg97359d12010-08-10 09:46:38 +02002385 switch (key_conf->cipher) {
2386 case WLAN_CIPHER_SUITE_WEP40:
2387 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 key_type = KEY_WEP;
2389
2390 key_conf->hw_key_idx = key_conf->keyidx;
2391 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002392 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393 key_type = KEY_TKIP;
2394
2395 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002396 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2397 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002398 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002399 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 key_type = KEY_AES;
2401
2402 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002403 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2404 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002406 case WL1271_CIPHER_SUITE_GEM:
2407 key_type = KEY_GEM;
2408 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2409 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2410 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002411 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002412 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002413
2414 ret = -EOPNOTSUPP;
2415 goto out_sleep;
2416 }
2417
2418 switch (cmd) {
2419 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002420 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2421 key_conf->keyidx, key_type,
2422 key_conf->keylen, key_conf->key,
2423 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002424 if (ret < 0) {
2425 wl1271_error("Could not add or replace key");
2426 goto out_sleep;
2427 }
2428 break;
2429
2430 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002431 ret = wl1271_set_key(wl, KEY_REMOVE,
2432 key_conf->keyidx, key_type,
2433 key_conf->keylen, key_conf->key,
2434 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002435 if (ret < 0) {
2436 wl1271_error("Could not remove key");
2437 goto out_sleep;
2438 }
2439 break;
2440
2441 default:
2442 wl1271_error("Unsupported key cmd 0x%x", cmd);
2443 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444 break;
2445 }
2446
2447out_sleep:
2448 wl1271_ps_elp_sleep(wl);
2449
2450out_unlock:
2451 mutex_unlock(&wl->mutex);
2452
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 return ret;
2454}
2455
2456static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002457 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458 struct cfg80211_scan_request *req)
2459{
2460 struct wl1271 *wl = hw->priv;
2461 int ret;
2462 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002463 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464
2465 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2466
2467 if (req->n_ssids) {
2468 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002469 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470 }
2471
2472 mutex_lock(&wl->mutex);
2473
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002474 if (wl->state == WL1271_STATE_OFF) {
2475 /*
2476 * We cannot return -EBUSY here because cfg80211 will expect
2477 * a call to ieee80211_scan_completed if we do - in this case
2478 * there won't be any call.
2479 */
2480 ret = -EAGAIN;
2481 goto out;
2482 }
2483
Ido Yariva6208652011-03-01 15:14:41 +02002484 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002485 if (ret < 0)
2486 goto out;
2487
Luciano Coelho5924f892010-08-04 03:46:22 +03002488 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002489
2490 wl1271_ps_elp_sleep(wl);
2491
2492out:
2493 mutex_unlock(&wl->mutex);
2494
2495 return ret;
2496}
2497
Luciano Coelho33c2c062011-05-10 14:46:02 +03002498static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2499 struct ieee80211_vif *vif,
2500 struct cfg80211_sched_scan_request *req,
2501 struct ieee80211_sched_scan_ies *ies)
2502{
2503 struct wl1271 *wl = hw->priv;
2504 int ret;
2505
2506 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2507
2508 mutex_lock(&wl->mutex);
2509
2510 ret = wl1271_ps_elp_wakeup(wl);
2511 if (ret < 0)
2512 goto out;
2513
2514 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2515 if (ret < 0)
2516 goto out_sleep;
2517
2518 ret = wl1271_scan_sched_scan_start(wl);
2519 if (ret < 0)
2520 goto out_sleep;
2521
2522 wl->sched_scanning = true;
2523
2524out_sleep:
2525 wl1271_ps_elp_sleep(wl);
2526out:
2527 mutex_unlock(&wl->mutex);
2528 return ret;
2529}
2530
2531static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2532 struct ieee80211_vif *vif)
2533{
2534 struct wl1271 *wl = hw->priv;
2535 int ret;
2536
2537 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2538
2539 mutex_lock(&wl->mutex);
2540
2541 ret = wl1271_ps_elp_wakeup(wl);
2542 if (ret < 0)
2543 goto out;
2544
2545 wl1271_scan_sched_scan_stop(wl);
2546
2547 wl1271_ps_elp_sleep(wl);
2548out:
2549 mutex_unlock(&wl->mutex);
2550}
2551
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002552static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2553{
2554 struct wl1271 *wl = hw->priv;
2555 int ret = 0;
2556
2557 mutex_lock(&wl->mutex);
2558
2559 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2560 ret = -EAGAIN;
2561 goto out;
2562 }
2563
Ido Yariva6208652011-03-01 15:14:41 +02002564 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002565 if (ret < 0)
2566 goto out;
2567
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002568 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002569 if (ret < 0)
2570 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2571
2572 wl1271_ps_elp_sleep(wl);
2573
2574out:
2575 mutex_unlock(&wl->mutex);
2576
2577 return ret;
2578}
2579
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002580static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2581{
2582 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002583 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584
2585 mutex_lock(&wl->mutex);
2586
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002587 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2588 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002589 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002590 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002591
Ido Yariva6208652011-03-01 15:14:41 +02002592 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002593 if (ret < 0)
2594 goto out;
2595
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002596 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002597 if (ret < 0)
2598 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2599
2600 wl1271_ps_elp_sleep(wl);
2601
2602out:
2603 mutex_unlock(&wl->mutex);
2604
2605 return ret;
2606}
2607
Arik Nemtsove78a2872010-10-16 19:07:21 +02002608static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002609 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002610{
Eliad Peller889cb362011-05-01 09:56:45 +03002611 u8 ssid_len;
2612 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2613 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002614
Eliad Peller889cb362011-05-01 09:56:45 +03002615 if (!ptr) {
2616 wl1271_error("No SSID in IEs!");
2617 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002618 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002619
Eliad Peller889cb362011-05-01 09:56:45 +03002620 ssid_len = ptr[1];
2621 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2622 wl1271_error("SSID is too long!");
2623 return -EINVAL;
2624 }
2625
2626 wl->ssid_len = ssid_len;
2627 memcpy(wl->ssid, ptr+2, ssid_len);
2628 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002629}
2630
Arik Nemtsove78a2872010-10-16 19:07:21 +02002631static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2632 struct ieee80211_bss_conf *bss_conf,
2633 u32 changed)
2634{
2635 int ret = 0;
2636
2637 if (changed & BSS_CHANGED_ERP_SLOT) {
2638 if (bss_conf->use_short_slot)
2639 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2640 else
2641 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2642 if (ret < 0) {
2643 wl1271_warning("Set slot time failed %d", ret);
2644 goto out;
2645 }
2646 }
2647
2648 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2649 if (bss_conf->use_short_preamble)
2650 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2651 else
2652 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2653 }
2654
2655 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2656 if (bss_conf->use_cts_prot)
2657 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2658 else
2659 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2660 if (ret < 0) {
2661 wl1271_warning("Set ctsprotect failed %d", ret);
2662 goto out;
2663 }
2664 }
2665
2666out:
2667 return ret;
2668}
2669
2670static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2671 struct ieee80211_vif *vif,
2672 struct ieee80211_bss_conf *bss_conf,
2673 u32 changed)
2674{
2675 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2676 int ret = 0;
2677
2678 if ((changed & BSS_CHANGED_BEACON_INT)) {
2679 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2680 bss_conf->beacon_int);
2681
2682 wl->beacon_int = bss_conf->beacon_int;
2683 }
2684
2685 if ((changed & BSS_CHANGED_BEACON)) {
2686 struct ieee80211_hdr *hdr;
2687 int ieoffset = offsetof(struct ieee80211_mgmt,
2688 u.beacon.variable);
2689 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2690 u16 tmpl_id;
2691
2692 if (!beacon)
2693 goto out;
2694
2695 wl1271_debug(DEBUG_MASTER, "beacon updated");
2696
2697 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2698 if (ret < 0) {
2699 dev_kfree_skb(beacon);
2700 goto out;
2701 }
2702 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2703 CMD_TEMPL_BEACON;
2704 ret = wl1271_cmd_template_set(wl, tmpl_id,
2705 beacon->data,
2706 beacon->len, 0,
2707 wl1271_tx_min_rate_get(wl));
2708 if (ret < 0) {
2709 dev_kfree_skb(beacon);
2710 goto out;
2711 }
2712
2713 hdr = (struct ieee80211_hdr *) beacon->data;
2714 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2715 IEEE80211_STYPE_PROBE_RESP);
2716
2717 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2718 CMD_TEMPL_PROBE_RESPONSE;
2719 ret = wl1271_cmd_template_set(wl,
2720 tmpl_id,
2721 beacon->data,
2722 beacon->len, 0,
2723 wl1271_tx_min_rate_get(wl));
2724 dev_kfree_skb(beacon);
2725 if (ret < 0)
2726 goto out;
2727 }
2728
2729out:
2730 return ret;
2731}
2732
2733/* AP mode changes */
2734static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735 struct ieee80211_vif *vif,
2736 struct ieee80211_bss_conf *bss_conf,
2737 u32 changed)
2738{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002739 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740
Arik Nemtsove78a2872010-10-16 19:07:21 +02002741 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2742 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743
Arik Nemtsove78a2872010-10-16 19:07:21 +02002744 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2745 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002746
Arik Nemtsov70f47422011-04-18 14:15:25 +03002747 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002748 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002749 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002750 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002751 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002752
2753 ret = wl1271_ap_init_templates(wl);
2754 if (ret < 0)
2755 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002756 }
2757
Arik Nemtsove78a2872010-10-16 19:07:21 +02002758 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2759 if (ret < 0)
2760 goto out;
2761
2762 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2763 if (bss_conf->enable_beacon) {
2764 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2765 ret = wl1271_cmd_start_bss(wl);
2766 if (ret < 0)
2767 goto out;
2768
2769 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2770 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771
2772 ret = wl1271_ap_init_hwenc(wl);
2773 if (ret < 0)
2774 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002775 }
2776 } else {
2777 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2778 ret = wl1271_cmd_stop_bss(wl);
2779 if (ret < 0)
2780 goto out;
2781
2782 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2783 wl1271_debug(DEBUG_AP, "stopped AP");
2784 }
2785 }
2786 }
2787
Eliad Pellercb5ae052011-04-07 15:52:05 +03002788 if (changed & BSS_CHANGED_IBSS) {
2789 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2790 bss_conf->ibss_joined);
2791
2792 if (bss_conf->ibss_joined) {
2793 u32 rates = bss_conf->basic_rates;
2794 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2795 rates);
2796 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2797
2798 /* by default, use 11b rates */
2799 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2800 ret = wl1271_acx_sta_rate_policies(wl);
2801 if (ret < 0)
2802 goto out;
2803 }
2804 }
2805
Arik Nemtsove78a2872010-10-16 19:07:21 +02002806 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2807 if (ret < 0)
2808 goto out;
2809out:
2810 return;
2811}
2812
2813/* STA/IBSS mode changes */
2814static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2815 struct ieee80211_vif *vif,
2816 struct ieee80211_bss_conf *bss_conf,
2817 u32 changed)
2818{
2819 bool do_join = false, set_assoc = false;
2820 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002821 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002822 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002823 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002824 bool sta_exists = false;
2825 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002826
2827 if (is_ibss) {
2828 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2829 changed);
2830 if (ret < 0)
2831 goto out;
2832 }
2833
2834 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2835 do_join = true;
2836
2837 /* Need to update the SSID (for filtering etc) */
2838 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2839 do_join = true;
2840
2841 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002842 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2843 bss_conf->enable_beacon ? "enabled" : "disabled");
2844
2845 if (bss_conf->enable_beacon)
2846 wl->set_bss_type = BSS_TYPE_IBSS;
2847 else
2848 wl->set_bss_type = BSS_TYPE_STA_BSS;
2849 do_join = true;
2850 }
2851
Arik Nemtsove78a2872010-10-16 19:07:21 +02002852 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002853 bool enable = false;
2854 if (bss_conf->cqm_rssi_thold)
2855 enable = true;
2856 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2857 bss_conf->cqm_rssi_thold,
2858 bss_conf->cqm_rssi_hyst);
2859 if (ret < 0)
2860 goto out;
2861 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2862 }
2863
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002864 if ((changed & BSS_CHANGED_BSSID) &&
2865 /*
2866 * Now we know the correct bssid, so we send a new join command
2867 * and enable the BSSID filter
2868 */
2869 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002870 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002871
Eliad Pellerfa287b82010-12-26 09:27:50 +01002872 if (!is_zero_ether_addr(wl->bssid)) {
2873 ret = wl1271_cmd_build_null_data(wl);
2874 if (ret < 0)
2875 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002876
Eliad Pellerfa287b82010-12-26 09:27:50 +01002877 ret = wl1271_build_qos_null_data(wl);
2878 if (ret < 0)
2879 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002880
Eliad Pellerfa287b82010-12-26 09:27:50 +01002881 /* filter out all packets not from this BSSID */
2882 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002883
Eliad Pellerfa287b82010-12-26 09:27:50 +01002884 /* Need to update the BSSID (for filtering etc) */
2885 do_join = true;
2886 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002887 }
2888
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002889 rcu_read_lock();
2890 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2891 if (sta) {
2892 /* save the supp_rates of the ap */
2893 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2894 if (sta->ht_cap.ht_supported)
2895 sta_rate_set |=
2896 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002897 sta_ht_cap = sta->ht_cap;
2898 sta_exists = true;
2899 }
2900 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002901
Arik Nemtsova1008852011-02-12 23:24:20 +02002902 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002903 /* handle new association with HT and HT information change */
2904 if ((changed & BSS_CHANGED_HT) &&
2905 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002906 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002907 true);
2908 if (ret < 0) {
2909 wl1271_warning("Set ht cap true failed %d",
2910 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002911 goto out;
2912 }
2913 ret = wl1271_acx_set_ht_information(wl,
2914 bss_conf->ht_operation_mode);
2915 if (ret < 0) {
2916 wl1271_warning("Set ht information failed %d",
2917 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002918 goto out;
2919 }
2920 }
2921 /* handle new association without HT and disassociation */
2922 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002923 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002924 false);
2925 if (ret < 0) {
2926 wl1271_warning("Set ht cap false failed %d",
2927 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002928 goto out;
2929 }
2930 }
2931 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002932
Arik Nemtsove78a2872010-10-16 19:07:21 +02002933 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002935 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002936 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002937 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002938 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002939
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002940 wl->ps_poll_failures = 0;
2941
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002942 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002943 * use basic rates from AP, and determine lowest rate
2944 * to use with control frames.
2945 */
2946 rates = bss_conf->basic_rates;
2947 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2948 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002949 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002950 if (sta_rate_set)
2951 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2952 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002953 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002954 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002955 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002956
2957 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002958 * with wl1271, we don't need to update the
2959 * beacon_int and dtim_period, because the firmware
2960 * updates it by itself when the first beacon is
2961 * received after a join.
2962 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002963 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2964 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002965 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002967 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002968 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002969 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002970 dev_kfree_skb(wl->probereq);
2971 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2972 ieoffset = offsetof(struct ieee80211_mgmt,
2973 u.probe_req.variable);
2974 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002975
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002976 /* enable the connection monitoring feature */
2977 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002978 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002979 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980
2981 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002982 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2983 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002984 enum wl1271_cmd_ps_mode mode;
2985
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002986 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002987 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002988 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002989 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002990 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002991 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002992 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002993 } else {
2994 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002995 bool was_assoc =
2996 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2997 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002998 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002999 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003000
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003001 /* free probe-request template */
3002 dev_kfree_skb(wl->probereq);
3003 wl->probereq = NULL;
3004
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003005 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003006 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003007
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003008 /* revert back to minimum rates for the current band */
3009 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003010 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003011 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003012 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003013 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003014
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003015 /* disable connection monitor features */
3016 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003017
3018 /* Disable the keep-alive feature */
3019 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003020 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003021 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003022
3023 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003024 if (was_assoc) {
3025 wl1271_unjoin(wl);
3026 wl1271_dummy_join(wl);
3027 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 }
3029 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003030
Arik Nemtsove78a2872010-10-16 19:07:21 +02003031 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3032 if (ret < 0)
3033 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003034
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003035 if (changed & BSS_CHANGED_ARP_FILTER) {
3036 __be32 addr = bss_conf->arp_addr_list[0];
3037 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3038
Eliad Pellerc5312772010-12-09 11:31:27 +02003039 if (bss_conf->arp_addr_cnt == 1 &&
3040 bss_conf->arp_filter_enabled) {
3041 /*
3042 * The template should have been configured only upon
3043 * association. however, it seems that the correct ip
3044 * isn't being set (when sending), so we have to
3045 * reconfigure the template upon every ip change.
3046 */
3047 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3048 if (ret < 0) {
3049 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003050 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003051 }
3052
3053 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003054 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003055 addr);
3056 } else
3057 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003058
3059 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003060 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003061 }
3062
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003063 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003064 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003065 if (ret < 0) {
3066 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003067 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003068 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003069 }
3070
Arik Nemtsove78a2872010-10-16 19:07:21 +02003071out:
3072 return;
3073}
3074
3075static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3076 struct ieee80211_vif *vif,
3077 struct ieee80211_bss_conf *bss_conf,
3078 u32 changed)
3079{
3080 struct wl1271 *wl = hw->priv;
3081 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3082 int ret;
3083
3084 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3085 (int)changed);
3086
3087 mutex_lock(&wl->mutex);
3088
3089 if (unlikely(wl->state == WL1271_STATE_OFF))
3090 goto out;
3091
Ido Yariva6208652011-03-01 15:14:41 +02003092 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003093 if (ret < 0)
3094 goto out;
3095
3096 if (is_ap)
3097 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3098 else
3099 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3100
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003101 wl1271_ps_elp_sleep(wl);
3102
3103out:
3104 mutex_unlock(&wl->mutex);
3105}
3106
Kalle Valoc6999d82010-02-18 13:25:41 +02003107static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3108 const struct ieee80211_tx_queue_params *params)
3109{
3110 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003111 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003112 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003113
3114 mutex_lock(&wl->mutex);
3115
3116 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3117
Kalle Valo4695dc92010-03-18 12:26:38 +02003118 if (params->uapsd)
3119 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3120 else
3121 ps_scheme = CONF_PS_SCHEME_LEGACY;
3122
Arik Nemtsov488fc542010-10-16 20:33:45 +02003123 if (wl->state == WL1271_STATE_OFF) {
3124 /*
3125 * If the state is off, the parameters will be recorded and
3126 * configured on init. This happens in AP-mode.
3127 */
3128 struct conf_tx_ac_category *conf_ac =
3129 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3130 struct conf_tx_tid *conf_tid =
3131 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3132
3133 conf_ac->ac = wl1271_tx_get_queue(queue);
3134 conf_ac->cw_min = (u8)params->cw_min;
3135 conf_ac->cw_max = params->cw_max;
3136 conf_ac->aifsn = params->aifs;
3137 conf_ac->tx_op_limit = params->txop << 5;
3138
3139 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3140 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3141 conf_tid->tsid = wl1271_tx_get_queue(queue);
3142 conf_tid->ps_scheme = ps_scheme;
3143 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3144 conf_tid->apsd_conf[0] = 0;
3145 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003146 goto out;
3147 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003148
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003149 ret = wl1271_ps_elp_wakeup(wl);
3150 if (ret < 0)
3151 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003152
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003153 /*
3154 * the txop is confed in units of 32us by the mac80211,
3155 * we need us
3156 */
3157 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3158 params->cw_min, params->cw_max,
3159 params->aifs, params->txop << 5);
3160 if (ret < 0)
3161 goto out_sleep;
3162
3163 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3164 CONF_CHANNEL_TYPE_EDCF,
3165 wl1271_tx_get_queue(queue),
3166 ps_scheme, CONF_ACK_POLICY_LEGACY,
3167 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003168
3169out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003170 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003171
3172out:
3173 mutex_unlock(&wl->mutex);
3174
3175 return ret;
3176}
3177
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003178static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3179{
3180
3181 struct wl1271 *wl = hw->priv;
3182 u64 mactime = ULLONG_MAX;
3183 int ret;
3184
3185 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3186
3187 mutex_lock(&wl->mutex);
3188
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003189 if (unlikely(wl->state == WL1271_STATE_OFF))
3190 goto out;
3191
Ido Yariva6208652011-03-01 15:14:41 +02003192 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003193 if (ret < 0)
3194 goto out;
3195
3196 ret = wl1271_acx_tsf_info(wl, &mactime);
3197 if (ret < 0)
3198 goto out_sleep;
3199
3200out_sleep:
3201 wl1271_ps_elp_sleep(wl);
3202
3203out:
3204 mutex_unlock(&wl->mutex);
3205 return mactime;
3206}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003207
John W. Linvilleece550d2010-07-28 16:41:06 -04003208static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3209 struct survey_info *survey)
3210{
3211 struct wl1271 *wl = hw->priv;
3212 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003213
John W. Linvilleece550d2010-07-28 16:41:06 -04003214 if (idx != 0)
3215 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003216
John W. Linvilleece550d2010-07-28 16:41:06 -04003217 survey->channel = conf->channel;
3218 survey->filled = SURVEY_INFO_NOISE_DBM;
3219 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003220
John W. Linvilleece550d2010-07-28 16:41:06 -04003221 return 0;
3222}
3223
Arik Nemtsov409622e2011-02-23 00:22:29 +02003224static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003225 struct ieee80211_sta *sta,
3226 u8 *hlid)
3227{
3228 struct wl1271_station *wl_sta;
3229 int id;
3230
3231 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3232 if (id >= AP_MAX_STATIONS) {
3233 wl1271_warning("could not allocate HLID - too much stations");
3234 return -EBUSY;
3235 }
3236
3237 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003238 __set_bit(id, wl->ap_hlid_map);
3239 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3240 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003241 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003242 return 0;
3243}
3244
Arik Nemtsov409622e2011-02-23 00:22:29 +02003245static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003246{
3247 int id = hlid - WL1271_AP_STA_HLID_START;
3248
Arik Nemtsov409622e2011-02-23 00:22:29 +02003249 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3250 return;
3251
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003252 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003253 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003254 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003255 __clear_bit(hlid, &wl->ap_ps_map);
3256 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003257}
3258
3259static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3260 struct ieee80211_vif *vif,
3261 struct ieee80211_sta *sta)
3262{
3263 struct wl1271 *wl = hw->priv;
3264 int ret = 0;
3265 u8 hlid;
3266
3267 mutex_lock(&wl->mutex);
3268
3269 if (unlikely(wl->state == WL1271_STATE_OFF))
3270 goto out;
3271
3272 if (wl->bss_type != BSS_TYPE_AP_BSS)
3273 goto out;
3274
3275 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3276
Arik Nemtsov409622e2011-02-23 00:22:29 +02003277 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003278 if (ret < 0)
3279 goto out;
3280
Ido Yariva6208652011-03-01 15:14:41 +02003281 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003282 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003283 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003284
3285 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3286 if (ret < 0)
3287 goto out_sleep;
3288
3289out_sleep:
3290 wl1271_ps_elp_sleep(wl);
3291
Arik Nemtsov409622e2011-02-23 00:22:29 +02003292out_free_sta:
3293 if (ret < 0)
3294 wl1271_free_sta(wl, hlid);
3295
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003296out:
3297 mutex_unlock(&wl->mutex);
3298 return ret;
3299}
3300
3301static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3302 struct ieee80211_vif *vif,
3303 struct ieee80211_sta *sta)
3304{
3305 struct wl1271 *wl = hw->priv;
3306 struct wl1271_station *wl_sta;
3307 int ret = 0, id;
3308
3309 mutex_lock(&wl->mutex);
3310
3311 if (unlikely(wl->state == WL1271_STATE_OFF))
3312 goto out;
3313
3314 if (wl->bss_type != BSS_TYPE_AP_BSS)
3315 goto out;
3316
3317 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3318
3319 wl_sta = (struct wl1271_station *)sta->drv_priv;
3320 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3321 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3322 goto out;
3323
Ido Yariva6208652011-03-01 15:14:41 +02003324 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003325 if (ret < 0)
3326 goto out;
3327
3328 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3329 if (ret < 0)
3330 goto out_sleep;
3331
Arik Nemtsov409622e2011-02-23 00:22:29 +02003332 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003333
3334out_sleep:
3335 wl1271_ps_elp_sleep(wl);
3336
3337out:
3338 mutex_unlock(&wl->mutex);
3339 return ret;
3340}
3341
Luciano Coelho4623ec72011-03-21 19:26:41 +02003342static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3343 struct ieee80211_vif *vif,
3344 enum ieee80211_ampdu_mlme_action action,
3345 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3346 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003347{
3348 struct wl1271 *wl = hw->priv;
3349 int ret;
3350
3351 mutex_lock(&wl->mutex);
3352
3353 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3354 ret = -EAGAIN;
3355 goto out;
3356 }
3357
Ido Yariva6208652011-03-01 15:14:41 +02003358 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003359 if (ret < 0)
3360 goto out;
3361
Shahar Levi70559a02011-05-22 16:10:22 +03003362 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3363 tid, action);
3364
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003365 switch (action) {
3366 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003367 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003368 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3369 true);
3370 if (!ret)
3371 wl->ba_rx_bitmap |= BIT(tid);
3372 } else {
3373 ret = -ENOTSUPP;
3374 }
3375 break;
3376
3377 case IEEE80211_AMPDU_RX_STOP:
3378 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3379 if (!ret)
3380 wl->ba_rx_bitmap &= ~BIT(tid);
3381 break;
3382
3383 /*
3384 * The BA initiator session management in FW independently.
3385 * Falling break here on purpose for all TX APDU commands.
3386 */
3387 case IEEE80211_AMPDU_TX_START:
3388 case IEEE80211_AMPDU_TX_STOP:
3389 case IEEE80211_AMPDU_TX_OPERATIONAL:
3390 ret = -EINVAL;
3391 break;
3392
3393 default:
3394 wl1271_error("Incorrect ampdu action id=%x\n", action);
3395 ret = -EINVAL;
3396 }
3397
3398 wl1271_ps_elp_sleep(wl);
3399
3400out:
3401 mutex_unlock(&wl->mutex);
3402
3403 return ret;
3404}
3405
Arik Nemtsov33437892011-04-26 23:35:39 +03003406static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3407{
3408 struct wl1271 *wl = hw->priv;
3409 bool ret = false;
3410
3411 mutex_lock(&wl->mutex);
3412
3413 if (unlikely(wl->state == WL1271_STATE_OFF))
3414 goto out;
3415
3416 /* packets are considered pending if in the TX queue or the FW */
3417 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3418
3419 /* the above is appropriate for STA mode for PS purposes */
3420 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3421
3422out:
3423 mutex_unlock(&wl->mutex);
3424
3425 return ret;
3426}
3427
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428/* can't be const, mac80211 writes to this */
3429static struct ieee80211_rate wl1271_rates[] = {
3430 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003431 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3432 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003433 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003434 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3435 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003436 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3437 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003438 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3439 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3441 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003442 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3443 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003444 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3445 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003446 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3447 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003448 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003449 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3450 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003451 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003452 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3453 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003454 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003455 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3456 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003457 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003458 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3459 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003460 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003461 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3462 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003463 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003464 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3465 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003466 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003467 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3468 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003469};
3470
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003471/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003472static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003473 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003474 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003475 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3476 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3477 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003478 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003479 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3480 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3481 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003482 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003483 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3484 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3485 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003486 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003487};
3488
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003489/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003490static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003491 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003492 7, /* CONF_HW_RXTX_RATE_MCS7 */
3493 6, /* CONF_HW_RXTX_RATE_MCS6 */
3494 5, /* CONF_HW_RXTX_RATE_MCS5 */
3495 4, /* CONF_HW_RXTX_RATE_MCS4 */
3496 3, /* CONF_HW_RXTX_RATE_MCS3 */
3497 2, /* CONF_HW_RXTX_RATE_MCS2 */
3498 1, /* CONF_HW_RXTX_RATE_MCS1 */
3499 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003500
3501 11, /* CONF_HW_RXTX_RATE_54 */
3502 10, /* CONF_HW_RXTX_RATE_48 */
3503 9, /* CONF_HW_RXTX_RATE_36 */
3504 8, /* CONF_HW_RXTX_RATE_24 */
3505
3506 /* TI-specific rate */
3507 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3508
3509 7, /* CONF_HW_RXTX_RATE_18 */
3510 6, /* CONF_HW_RXTX_RATE_12 */
3511 3, /* CONF_HW_RXTX_RATE_11 */
3512 5, /* CONF_HW_RXTX_RATE_9 */
3513 4, /* CONF_HW_RXTX_RATE_6 */
3514 2, /* CONF_HW_RXTX_RATE_5_5 */
3515 1, /* CONF_HW_RXTX_RATE_2 */
3516 0 /* CONF_HW_RXTX_RATE_1 */
3517};
3518
Shahar Levie8b03a22010-10-13 16:09:39 +02003519/* 11n STA capabilities */
3520#define HW_RX_HIGHEST_RATE 72
3521
Shahar Levi00d20102010-11-08 11:20:10 +00003522#ifdef CONFIG_WL12XX_HT
3523#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003524 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3525 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003526 .ht_supported = true, \
3527 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3528 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3529 .mcs = { \
3530 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3531 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3532 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3533 }, \
3534}
Shahar Levi18357852010-10-13 16:09:41 +02003535#else
Shahar Levi00d20102010-11-08 11:20:10 +00003536#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003537 .ht_supported = false, \
3538}
3539#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003540
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003541/* can't be const, mac80211 writes to this */
3542static struct ieee80211_supported_band wl1271_band_2ghz = {
3543 .channels = wl1271_channels,
3544 .n_channels = ARRAY_SIZE(wl1271_channels),
3545 .bitrates = wl1271_rates,
3546 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003547 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003548};
3549
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003550/* 5 GHz data rates for WL1273 */
3551static struct ieee80211_rate wl1271_rates_5ghz[] = {
3552 { .bitrate = 60,
3553 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3554 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3555 { .bitrate = 90,
3556 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3557 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3558 { .bitrate = 120,
3559 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3560 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3561 { .bitrate = 180,
3562 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3563 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3564 { .bitrate = 240,
3565 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3566 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3567 { .bitrate = 360,
3568 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3569 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3570 { .bitrate = 480,
3571 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3572 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3573 { .bitrate = 540,
3574 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3575 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3576};
3577
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003578/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003579static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003580 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003581 { .hw_value = 8, .center_freq = 5040},
3582 { .hw_value = 9, .center_freq = 5045},
3583 { .hw_value = 11, .center_freq = 5055},
3584 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003585 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003586 { .hw_value = 34, .center_freq = 5170},
3587 { .hw_value = 36, .center_freq = 5180},
3588 { .hw_value = 38, .center_freq = 5190},
3589 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003590 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003591 { .hw_value = 44, .center_freq = 5220},
3592 { .hw_value = 46, .center_freq = 5230},
3593 { .hw_value = 48, .center_freq = 5240},
3594 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003595 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003596 { .hw_value = 60, .center_freq = 5300},
3597 { .hw_value = 64, .center_freq = 5320},
3598 { .hw_value = 100, .center_freq = 5500},
3599 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003600 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003601 { .hw_value = 112, .center_freq = 5560},
3602 { .hw_value = 116, .center_freq = 5580},
3603 { .hw_value = 120, .center_freq = 5600},
3604 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003605 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003606 { .hw_value = 132, .center_freq = 5660},
3607 { .hw_value = 136, .center_freq = 5680},
3608 { .hw_value = 140, .center_freq = 5700},
3609 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003610 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003611 { .hw_value = 157, .center_freq = 5785},
3612 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003613 { .hw_value = 165, .center_freq = 5825},
3614};
3615
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003616/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003617static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003618 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003619 7, /* CONF_HW_RXTX_RATE_MCS7 */
3620 6, /* CONF_HW_RXTX_RATE_MCS6 */
3621 5, /* CONF_HW_RXTX_RATE_MCS5 */
3622 4, /* CONF_HW_RXTX_RATE_MCS4 */
3623 3, /* CONF_HW_RXTX_RATE_MCS3 */
3624 2, /* CONF_HW_RXTX_RATE_MCS2 */
3625 1, /* CONF_HW_RXTX_RATE_MCS1 */
3626 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003627
3628 7, /* CONF_HW_RXTX_RATE_54 */
3629 6, /* CONF_HW_RXTX_RATE_48 */
3630 5, /* CONF_HW_RXTX_RATE_36 */
3631 4, /* CONF_HW_RXTX_RATE_24 */
3632
3633 /* TI-specific rate */
3634 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3635
3636 3, /* CONF_HW_RXTX_RATE_18 */
3637 2, /* CONF_HW_RXTX_RATE_12 */
3638 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3639 1, /* CONF_HW_RXTX_RATE_9 */
3640 0, /* CONF_HW_RXTX_RATE_6 */
3641 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3642 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3643 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3644};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003645
3646static struct ieee80211_supported_band wl1271_band_5ghz = {
3647 .channels = wl1271_channels_5ghz,
3648 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3649 .bitrates = wl1271_rates_5ghz,
3650 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003651 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003652};
3653
Tobias Klausera0ea9492010-05-20 10:38:11 +02003654static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003655 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3656 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3657};
3658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659static const struct ieee80211_ops wl1271_ops = {
3660 .start = wl1271_op_start,
3661 .stop = wl1271_op_stop,
3662 .add_interface = wl1271_op_add_interface,
3663 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003664#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003665 .suspend = wl1271_op_suspend,
3666 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003667#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003668 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003669 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003670 .configure_filter = wl1271_op_configure_filter,
3671 .tx = wl1271_op_tx,
3672 .set_key = wl1271_op_set_key,
3673 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003674 .sched_scan_start = wl1271_op_sched_scan_start,
3675 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003676 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003677 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003678 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003679 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003680 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003681 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003682 .sta_add = wl1271_op_sta_add,
3683 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003684 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003685 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003686 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003687};
3688
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003689
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003690u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003691{
3692 u8 idx;
3693
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003694 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003695
3696 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3697 wl1271_error("Illegal RX rate from HW: %d", rate);
3698 return 0;
3699 }
3700
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003701 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003702 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3703 wl1271_error("Unsupported RX rate from HW: %d", rate);
3704 return 0;
3705 }
3706
3707 return idx;
3708}
3709
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003710static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3711 struct device_attribute *attr,
3712 char *buf)
3713{
3714 struct wl1271 *wl = dev_get_drvdata(dev);
3715 ssize_t len;
3716
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003717 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003718
3719 mutex_lock(&wl->mutex);
3720 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3721 wl->sg_enabled);
3722 mutex_unlock(&wl->mutex);
3723
3724 return len;
3725
3726}
3727
3728static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3729 struct device_attribute *attr,
3730 const char *buf, size_t count)
3731{
3732 struct wl1271 *wl = dev_get_drvdata(dev);
3733 unsigned long res;
3734 int ret;
3735
Luciano Coelho6277ed62011-04-01 17:49:54 +03003736 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003737 if (ret < 0) {
3738 wl1271_warning("incorrect value written to bt_coex_mode");
3739 return count;
3740 }
3741
3742 mutex_lock(&wl->mutex);
3743
3744 res = !!res;
3745
3746 if (res == wl->sg_enabled)
3747 goto out;
3748
3749 wl->sg_enabled = res;
3750
3751 if (wl->state == WL1271_STATE_OFF)
3752 goto out;
3753
Ido Yariva6208652011-03-01 15:14:41 +02003754 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003755 if (ret < 0)
3756 goto out;
3757
3758 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3759 wl1271_ps_elp_sleep(wl);
3760
3761 out:
3762 mutex_unlock(&wl->mutex);
3763 return count;
3764}
3765
3766static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3767 wl1271_sysfs_show_bt_coex_state,
3768 wl1271_sysfs_store_bt_coex_state);
3769
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003770static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3771 struct device_attribute *attr,
3772 char *buf)
3773{
3774 struct wl1271 *wl = dev_get_drvdata(dev);
3775 ssize_t len;
3776
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003777 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003778
3779 mutex_lock(&wl->mutex);
3780 if (wl->hw_pg_ver >= 0)
3781 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3782 else
3783 len = snprintf(buf, len, "n/a\n");
3784 mutex_unlock(&wl->mutex);
3785
3786 return len;
3787}
3788
3789static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3790 wl1271_sysfs_show_hw_pg_ver, NULL);
3791
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003792int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003793{
3794 int ret;
3795
3796 if (wl->mac80211_registered)
3797 return 0;
3798
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003799 ret = wl1271_fetch_nvs(wl);
3800 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003801 /* NOTE: The wl->nvs->nvs element must be first, in
3802 * order to simplify the casting, we assume it is at
3803 * the beginning of the wl->nvs structure.
3804 */
3805 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003806
3807 wl->mac_addr[0] = nvs_ptr[11];
3808 wl->mac_addr[1] = nvs_ptr[10];
3809 wl->mac_addr[2] = nvs_ptr[6];
3810 wl->mac_addr[3] = nvs_ptr[5];
3811 wl->mac_addr[4] = nvs_ptr[4];
3812 wl->mac_addr[5] = nvs_ptr[3];
3813 }
3814
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003815 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3816
3817 ret = ieee80211_register_hw(wl->hw);
3818 if (ret < 0) {
3819 wl1271_error("unable to register mac80211 hw: %d", ret);
3820 return ret;
3821 }
3822
3823 wl->mac80211_registered = true;
3824
Eliad Pellerd60080a2010-11-24 12:53:16 +02003825 wl1271_debugfs_init(wl);
3826
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003827 register_netdevice_notifier(&wl1271_dev_notifier);
3828
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003829 wl1271_notice("loaded");
3830
3831 return 0;
3832}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003833EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003834
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003835void wl1271_unregister_hw(struct wl1271 *wl)
3836{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003837 if (wl->state == WL1271_STATE_PLT)
3838 __wl1271_plt_stop(wl);
3839
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003840 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003841 ieee80211_unregister_hw(wl->hw);
3842 wl->mac80211_registered = false;
3843
3844}
3845EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3846
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003847int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003848{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003849 static const u32 cipher_suites[] = {
3850 WLAN_CIPHER_SUITE_WEP40,
3851 WLAN_CIPHER_SUITE_WEP104,
3852 WLAN_CIPHER_SUITE_TKIP,
3853 WLAN_CIPHER_SUITE_CCMP,
3854 WL1271_CIPHER_SUITE_GEM,
3855 };
3856
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003857 /* The tx descriptor buffer and the TKIP space. */
3858 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3859 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003860
3861 /* unit us */
3862 /* FIXME: find a proper value */
3863 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003864 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003865
3866 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003867 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003868 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003869 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003870 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003871 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003872 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003873 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003874 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003875 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003876
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003877 wl->hw->wiphy->cipher_suites = cipher_suites;
3878 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3879
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003880 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003881 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003882 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003883 /*
3884 * Maximum length of elements in scanning probe request templates
3885 * should be the maximum length possible for a template, without
3886 * the IEEE80211 header of the template
3887 */
3888 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3889 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003890
Luciano Coelho4a31c112011-03-21 23:16:14 +02003891 /* make sure all our channels fit in the scanned_ch bitmask */
3892 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3893 ARRAY_SIZE(wl1271_channels_5ghz) >
3894 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003895 /*
3896 * We keep local copies of the band structs because we need to
3897 * modify them on a per-device basis.
3898 */
3899 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3900 sizeof(wl1271_band_2ghz));
3901 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3902 sizeof(wl1271_band_5ghz));
3903
3904 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3905 &wl->bands[IEEE80211_BAND_2GHZ];
3906 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3907 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003908
Kalle Valo12bd8942010-03-18 12:26:33 +02003909 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003910 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003911
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003912 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3913
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003914 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003915
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003916 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3917
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003918 wl->hw->max_rx_aggregation_subframes = 8;
3919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003920 return 0;
3921}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003922EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003924#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003925
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003926struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003927{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003928 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003929 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003930 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003931 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003932 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003933
3934 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3935 if (!hw) {
3936 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003937 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003938 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003939 }
3940
Julia Lawall929ebd32010-05-15 23:16:39 +02003941 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003942 if (!plat_dev) {
3943 wl1271_error("could not allocate platform_device");
3944 ret = -ENOMEM;
3945 goto err_plat_alloc;
3946 }
3947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003948 wl = hw->priv;
3949 memset(wl, 0, sizeof(*wl));
3950
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003951 INIT_LIST_HEAD(&wl->list);
3952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003954 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003955
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003956 for (i = 0; i < NUM_TX_QUEUES; i++)
3957 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003958
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003959 for (i = 0; i < NUM_TX_QUEUES; i++)
3960 for (j = 0; j < AP_MAX_LINKS; j++)
3961 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3962
Ido Yariva6208652011-03-01 15:14:41 +02003963 skb_queue_head_init(&wl->deferred_rx_queue);
3964 skb_queue_head_init(&wl->deferred_tx_queue);
3965
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003966 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003967 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003968 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003969 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3970 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3971 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003972 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003973 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003974 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003975 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003976 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3977 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003978 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003979 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003980 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003981 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003982 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003983 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003984 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003985 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003986 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003987 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003988 wl->bss_type = MAX_BSS_TYPE;
3989 wl->set_bss_type = MAX_BSS_TYPE;
3990 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003991 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003992 wl->ap_ps_map = 0;
3993 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003994 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003995 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003996 wl->sched_scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003997
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003998 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003999 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004000 wl->tx_frames[i] = NULL;
4001
4002 spin_lock_init(&wl->wl_lock);
4003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004004 wl->state = WL1271_STATE_OFF;
4005 mutex_init(&wl->mutex);
4006
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004007 /* Apply default driver configuration. */
4008 wl1271_conf_init(wl);
4009
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004010 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4011 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4012 if (!wl->aggr_buf) {
4013 ret = -ENOMEM;
4014 goto err_hw;
4015 }
4016
Ido Yariv990f5de2011-03-31 10:06:59 +02004017 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4018 if (!wl->dummy_packet) {
4019 ret = -ENOMEM;
4020 goto err_aggr;
4021 }
4022
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004023 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004024 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004025 if (ret) {
4026 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004027 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004028 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004029 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004030
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004031 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004032 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004033 if (ret < 0) {
4034 wl1271_error("failed to create sysfs file bt_coex_state");
4035 goto err_platform;
4036 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004037
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004038 /* Create sysfs file to get HW PG version */
4039 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4040 if (ret < 0) {
4041 wl1271_error("failed to create sysfs file hw_pg_ver");
4042 goto err_bt_coex_state;
4043 }
4044
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004045 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004046
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004047err_bt_coex_state:
4048 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4049
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004050err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004051 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004052
Ido Yariv990f5de2011-03-31 10:06:59 +02004053err_dummy_packet:
4054 dev_kfree_skb(wl->dummy_packet);
4055
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004056err_aggr:
4057 free_pages((unsigned long)wl->aggr_buf, order);
4058
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004059err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004060 wl1271_debugfs_exit(wl);
4061 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004062
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004063err_plat_alloc:
4064 ieee80211_free_hw(hw);
4065
4066err_hw_alloc:
4067
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004068 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004069}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004070EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004071
4072int wl1271_free_hw(struct wl1271 *wl)
4073{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004074 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004075 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004076 free_pages((unsigned long)wl->aggr_buf,
4077 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004078 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004079
4080 wl1271_debugfs_exit(wl);
4081
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004082 vfree(wl->fw);
4083 wl->fw = NULL;
4084 kfree(wl->nvs);
4085 wl->nvs = NULL;
4086
4087 kfree(wl->fw_status);
4088 kfree(wl->tx_res_if);
4089
4090 ieee80211_free_hw(wl->hw);
4091
4092 return 0;
4093}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004094EXPORT_SYMBOL_GPL(wl1271_free_hw);
4095
Guy Eilam491bbd62011-01-12 10:33:29 +01004096u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004097EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004098module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004099MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4100
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004101MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004102MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004103MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");