blob: e6497dc669df096a57bc914e515b9212c18784c8 [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 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300365 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300366};
367
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300368static void __wl1271_op_remove_interface(struct wl1271 *wl,
369 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200370static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200371
372
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200373static void wl1271_device_release(struct device *dev)
374{
375
376}
377
378static struct platform_device wl1271_device = {
379 .name = "wl1271",
380 .id = -1,
381
382 /* device model insists to have a release function */
383 .dev = {
384 .release = wl1271_device_release,
385 },
386};
387
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200388static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300389static LIST_HEAD(wl_list);
390
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300391static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
392 void *arg)
393{
394 struct net_device *dev = arg;
395 struct wireless_dev *wdev;
396 struct wiphy *wiphy;
397 struct ieee80211_hw *hw;
398 struct wl1271 *wl;
399 struct wl1271 *wl_temp;
400 int ret = 0;
401
402 /* Check that this notification is for us. */
403 if (what != NETDEV_CHANGE)
404 return NOTIFY_DONE;
405
406 wdev = dev->ieee80211_ptr;
407 if (wdev == NULL)
408 return NOTIFY_DONE;
409
410 wiphy = wdev->wiphy;
411 if (wiphy == NULL)
412 return NOTIFY_DONE;
413
414 hw = wiphy_priv(wiphy);
415 if (hw == NULL)
416 return NOTIFY_DONE;
417
418 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200419 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 list_for_each_entry(wl, &wl_list, list) {
421 if (wl == wl_temp)
422 break;
423 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200424 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300425 if (wl != wl_temp)
426 return NOTIFY_DONE;
427
428 mutex_lock(&wl->mutex);
429
430 if (wl->state == WL1271_STATE_OFF)
431 goto out;
432
433 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
434 goto out;
435
Ido Yariva6208652011-03-01 15:14:41 +0200436 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300437 if (ret < 0)
438 goto out;
439
440 if ((dev->operstate == IF_OPER_UP) &&
441 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
442 wl1271_cmd_set_sta_state(wl);
443 wl1271_info("Association completed.");
444 }
445
446 wl1271_ps_elp_sleep(wl);
447
448out:
449 mutex_unlock(&wl->mutex);
450
451 return NOTIFY_OK;
452}
453
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100454static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200455 struct regulatory_request *request)
456{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100457 struct ieee80211_supported_band *band;
458 struct ieee80211_channel *ch;
459 int i;
460
461 band = wiphy->bands[IEEE80211_BAND_5GHZ];
462 for (i = 0; i < band->n_channels; i++) {
463 ch = &band->channels[i];
464 if (ch->flags & IEEE80211_CHAN_DISABLED)
465 continue;
466
467 if (ch->flags & IEEE80211_CHAN_RADAR)
468 ch->flags |= IEEE80211_CHAN_NO_IBSS |
469 IEEE80211_CHAN_PASSIVE_SCAN;
470
471 }
472
473 return 0;
474}
475
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300476static void wl1271_conf_init(struct wl1271 *wl)
477{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300478
479 /*
480 * This function applies the default configuration to the driver. This
481 * function is invoked upon driver load (spi probe.)
482 *
483 * The configuration is stored in a run-time structure in order to
484 * facilitate for run-time adjustment of any of the parameters. Making
485 * changes to the configuration structure will apply the new values on
486 * the next interface up (wl1271_op_start.)
487 */
488
489 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300490 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300491}
492
493
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300494static int wl1271_plt_init(struct wl1271 *wl)
495{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200496 struct conf_tx_ac_category *conf_ac;
497 struct conf_tx_tid *conf_tid;
498 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300499
Shahar Levi49d750ca2011-03-06 16:32:09 +0200500 if (wl->chip.id == CHIP_ID_1283_PG20)
501 ret = wl128x_cmd_general_parms(wl);
502 else
503 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200504 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200505 return ret;
506
Shahar Levi49d750ca2011-03-06 16:32:09 +0200507 if (wl->chip.id == CHIP_ID_1283_PG20)
508 ret = wl128x_cmd_radio_parms(wl);
509 else
510 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200511 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200512 return ret;
513
Shahar Levi49d750ca2011-03-06 16:32:09 +0200514 if (wl->chip.id != CHIP_ID_1283_PG20) {
515 ret = wl1271_cmd_ext_radio_parms(wl);
516 if (ret < 0)
517 return ret;
518 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200519 if (ret < 0)
520 return ret;
521
Shahar Levi48a61472011-03-06 16:32:08 +0200522 /* Chip-specific initializations */
523 ret = wl1271_chip_specific_init(wl);
524 if (ret < 0)
525 return ret;
526
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200527 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200528 if (ret < 0)
529 return ret;
530
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300531 ret = wl1271_acx_init_mem_config(wl);
532 if (ret < 0)
533 return ret;
534
Luciano Coelho12419cc2010-02-18 13:25:44 +0200535 /* PHY layer config */
536 ret = wl1271_init_phy_config(wl);
537 if (ret < 0)
538 goto out_free_memmap;
539
540 ret = wl1271_acx_dco_itrim_params(wl);
541 if (ret < 0)
542 goto out_free_memmap;
543
544 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200545 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200546 if (ret < 0)
547 goto out_free_memmap;
548
549 /* Bluetooth WLAN coexistence */
550 ret = wl1271_init_pta(wl);
551 if (ret < 0)
552 goto out_free_memmap;
553
Shahar Leviff868432011-04-11 15:41:46 +0300554 /* FM WLAN coexistence */
555 ret = wl1271_acx_fm_coex(wl);
556 if (ret < 0)
557 goto out_free_memmap;
558
Luciano Coelho12419cc2010-02-18 13:25:44 +0200559 /* Energy detection */
560 ret = wl1271_init_energy_detection(wl);
561 if (ret < 0)
562 goto out_free_memmap;
563
Gery Kahn1ec610e2011-02-01 03:03:08 -0600564 ret = wl1271_acx_sta_mem_cfg(wl);
565 if (ret < 0)
566 goto out_free_memmap;
567
Luciano Coelho12419cc2010-02-18 13:25:44 +0200568 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100569 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200570 if (ret < 0)
571 goto out_free_memmap;
572
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200573 /* Default TID/AC configuration */
574 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200575 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200576 conf_ac = &wl->conf.tx.ac_conf[i];
577 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
578 conf_ac->cw_max, conf_ac->aifsn,
579 conf_ac->tx_op_limit);
580 if (ret < 0)
581 goto out_free_memmap;
582
Luciano Coelho12419cc2010-02-18 13:25:44 +0200583 conf_tid = &wl->conf.tx.tid_conf[i];
584 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
585 conf_tid->channel_type,
586 conf_tid->tsid,
587 conf_tid->ps_scheme,
588 conf_tid->ack_policy,
589 conf_tid->apsd_conf[0],
590 conf_tid->apsd_conf[1]);
591 if (ret < 0)
592 goto out_free_memmap;
593 }
594
Luciano Coelho12419cc2010-02-18 13:25:44 +0200595 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200596 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300597 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200598 goto out_free_memmap;
599
600 /* Configure for CAM power saving (ie. always active) */
601 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
602 if (ret < 0)
603 goto out_free_memmap;
604
605 /* configure PM */
606 ret = wl1271_acx_pm_config(wl);
607 if (ret < 0)
608 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300609
610 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200611
612 out_free_memmap:
613 kfree(wl->target_mem_map);
614 wl->target_mem_map = NULL;
615
616 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300617}
618
Arik Nemtsovb622d992011-02-23 00:22:31 +0200619static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
620{
621 bool fw_ps;
622
623 /* only regulate station links */
624 if (hlid < WL1271_AP_STA_HLID_START)
625 return;
626
627 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
628
629 /*
630 * Wake up from high level PS if the STA is asleep with too little
631 * blocks in FW or if the STA is awake.
632 */
633 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
634 wl1271_ps_link_end(wl, hlid);
635
636 /* Start high-level PS if the STA is asleep with enough blocks in FW */
637 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
638 wl1271_ps_link_start(wl, hlid, true);
639}
640
641static void wl1271_irq_update_links_status(struct wl1271 *wl,
642 struct wl1271_fw_ap_status *status)
643{
644 u32 cur_fw_ps_map;
645 u8 hlid;
646
647 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
648 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
649 wl1271_debug(DEBUG_PSM,
650 "link ps prev 0x%x cur 0x%x changed 0x%x",
651 wl->ap_fw_ps_map, cur_fw_ps_map,
652 wl->ap_fw_ps_map ^ cur_fw_ps_map);
653
654 wl->ap_fw_ps_map = cur_fw_ps_map;
655 }
656
657 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
658 u8 cnt = status->tx_lnk_free_blks[hlid] -
659 wl->links[hlid].prev_freed_blks;
660
661 wl->links[hlid].prev_freed_blks =
662 status->tx_lnk_free_blks[hlid];
663 wl->links[hlid].allocated_blks -= cnt;
664
665 wl1271_irq_ps_regulate_link(wl, hlid,
666 wl->links[hlid].allocated_blks);
667 }
668}
669
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300670static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200671 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200673 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200674 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200675 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200676 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 int i;
678
Shahar Levi13b107d2011-03-06 16:32:12 +0200679 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200680 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
681 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200682 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200683 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
684 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200685 }
686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300687 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
688 "drv_rx_counter = %d, tx_results_counter = %d)",
689 status->intr,
690 status->fw_rx_counter,
691 status->drv_rx_counter,
692 status->tx_results_counter);
693
694 /* update number of available TX blocks */
695 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200696 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
697 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300698
699 wl->tx_blocks_freed[i] =
700 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200701 }
702
Ido Yarivd2f4d472011-03-31 10:07:00 +0200703 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200704
Ido Yarivd2f4d472011-03-31 10:07:00 +0200705 if (wl->bss_type == BSS_TYPE_AP_BSS) {
706 /* Update num of allocated TX blocks per link and ps status */
707 wl1271_irq_update_links_status(wl, &full_status->ap);
708 wl->tx_blocks_available += freed_blocks;
709 } else {
710 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
711
712 /*
713 * The FW might change the total number of TX memblocks before
714 * we get a notification about blocks being released. Thus, the
715 * available blocks calculation might yield a temporary result
716 * which is lower than the actual available blocks. Keeping in
717 * mind that only blocks that were allocated can be moved from
718 * TX to RX, tx_blocks_available should never decrease here.
719 */
720 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
721 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722 }
723
Ido Yariva5225502010-10-12 14:49:10 +0200724 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200725 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200726 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300727
728 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200729 getnstimeofday(&ts);
730 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
731 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300732}
733
Ido Yariva6208652011-03-01 15:14:41 +0200734static void wl1271_flush_deferred_work(struct wl1271 *wl)
735{
736 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200737
Ido Yariva6208652011-03-01 15:14:41 +0200738 /* Pass all received frames to the network stack */
739 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
740 ieee80211_rx_ni(wl->hw, skb);
741
742 /* Return sent skbs to the network stack */
743 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
744 ieee80211_tx_status(wl->hw, skb);
745}
746
747static void wl1271_netstack_work(struct work_struct *work)
748{
749 struct wl1271 *wl =
750 container_of(work, struct wl1271, netstack_work);
751
752 do {
753 wl1271_flush_deferred_work(wl);
754 } while (skb_queue_len(&wl->deferred_rx_queue));
755}
756
757#define WL1271_IRQ_MAX_LOOPS 256
758
759irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300761 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300762 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200763 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200764 struct wl1271 *wl = (struct wl1271 *)cookie;
765 bool done = false;
766 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200767 unsigned long flags;
768
769 /* TX might be handled here, avoid redundant work */
770 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
771 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300772
Ido Yariv341b7cd2011-03-31 10:07:01 +0200773 /*
774 * In case edge triggered interrupt must be used, we cannot iterate
775 * more than once without introducing race conditions with the hardirq.
776 */
777 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
778 loopcount = 1;
779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780 mutex_lock(&wl->mutex);
781
782 wl1271_debug(DEBUG_IRQ, "IRQ work");
783
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200784 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300785 goto out;
786
Ido Yariva6208652011-03-01 15:14:41 +0200787 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788 if (ret < 0)
789 goto out;
790
Ido Yariva6208652011-03-01 15:14:41 +0200791 while (!done && loopcount--) {
792 /*
793 * In order to avoid a race with the hardirq, clear the flag
794 * before acknowledging the chip. Since the mutex is held,
795 * wl1271_ps_elp_wakeup cannot be called concurrently.
796 */
797 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
798 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200799
800 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200801 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200802 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200803 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200804 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200805 continue;
806 }
807
Eliad Pellerccc83b02010-10-27 14:09:57 +0200808 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
809 wl1271_error("watchdog interrupt received! "
810 "starting recovery.");
811 ieee80211_queue_work(wl->hw, &wl->recovery_work);
812
813 /* restarting the chip. ignore any other interrupt. */
814 goto out;
815 }
816
Ido Yariva6208652011-03-01 15:14:41 +0200817 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200818 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
819
Ido Yariv8aad2462011-03-01 15:14:38 +0200820 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200821
Ido Yariva5225502010-10-12 14:49:10 +0200822 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200823 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200824 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200825 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200826 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200827 /*
828 * In order to avoid starvation of the TX path,
829 * call the work function directly.
830 */
831 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200832 } else {
833 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200834 }
835
Ido Yariv8aad2462011-03-01 15:14:38 +0200836 /* check for tx results */
837 if (wl->fw_status->common.tx_results_counter !=
838 (wl->tx_results_count & 0xff))
839 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200840
841 /* Make sure the deferred queues don't get too long */
842 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
843 skb_queue_len(&wl->deferred_rx_queue);
844 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
845 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200846 }
847
848 if (intr & WL1271_ACX_INTR_EVENT_A) {
849 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
850 wl1271_event_handle(wl, 0);
851 }
852
853 if (intr & WL1271_ACX_INTR_EVENT_B) {
854 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
855 wl1271_event_handle(wl, 1);
856 }
857
858 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
859 wl1271_debug(DEBUG_IRQ,
860 "WL1271_ACX_INTR_INIT_COMPLETE");
861
862 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
863 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300864 }
865
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866 wl1271_ps_elp_sleep(wl);
867
868out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200869 spin_lock_irqsave(&wl->wl_lock, flags);
870 /* In case TX was not handled here, queue TX work */
871 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
872 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
873 wl->tx_queue_count)
874 ieee80211_queue_work(wl->hw, &wl->tx_work);
875 spin_unlock_irqrestore(&wl->wl_lock, flags);
876
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200878
879 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300880}
Ido Yariva6208652011-03-01 15:14:41 +0200881EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883static int wl1271_fetch_firmware(struct wl1271 *wl)
884{
885 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200886 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300887 int ret;
888
Arik Nemtsov166d5042010-10-16 21:44:57 +0200889 switch (wl->bss_type) {
890 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200891 if (wl->chip.id == CHIP_ID_1283_PG20)
892 fw_name = WL128X_AP_FW_NAME;
893 else
894 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200895 break;
896 case BSS_TYPE_IBSS:
897 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200898 if (wl->chip.id == CHIP_ID_1283_PG20)
899 fw_name = WL128X_FW_NAME;
900 else
901 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200902 break;
903 default:
904 wl1271_error("no compatible firmware for bss_type %d",
905 wl->bss_type);
906 return -EINVAL;
907 }
908
909 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
910
911 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300912
913 if (ret < 0) {
914 wl1271_error("could not get firmware: %d", ret);
915 return ret;
916 }
917
918 if (fw->size % 4) {
919 wl1271_error("firmware size is not multiple of 32 bits: %zu",
920 fw->size);
921 ret = -EILSEQ;
922 goto out;
923 }
924
Arik Nemtsov166d5042010-10-16 21:44:57 +0200925 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300926 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300927 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928
929 if (!wl->fw) {
930 wl1271_error("could not allocate memory for the firmware");
931 ret = -ENOMEM;
932 goto out;
933 }
934
935 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200936 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300937 ret = 0;
938
939out:
940 release_firmware(fw);
941
942 return ret;
943}
944
945static int wl1271_fetch_nvs(struct wl1271 *wl)
946{
947 const struct firmware *fw;
948 int ret;
949
Shahar Levi5aa42342011-03-06 16:32:07 +0200950 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300951
952 if (ret < 0) {
953 wl1271_error("could not get nvs file: %d", ret);
954 return ret;
955 }
956
Shahar Levibc765bf2011-03-06 16:32:10 +0200957 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958
959 if (!wl->nvs) {
960 wl1271_error("could not allocate memory for the nvs file");
961 ret = -ENOMEM;
962 goto out;
963 }
964
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200965 wl->nvs_len = fw->size;
966
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300967out:
968 release_firmware(fw);
969
970 return ret;
971}
972
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200973static void wl1271_recovery_work(struct work_struct *work)
974{
975 struct wl1271 *wl =
976 container_of(work, struct wl1271, recovery_work);
977
978 mutex_lock(&wl->mutex);
979
980 if (wl->state != WL1271_STATE_ON)
981 goto out;
982
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300983 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
984 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200985
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200986 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
987 ieee80211_connection_loss(wl->vif);
988
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300989 /* Prevent spurious TX during FW restart */
990 ieee80211_stop_queues(wl->hw);
991
Luciano Coelho33c2c062011-05-10 14:46:02 +0300992 if (wl->sched_scanning) {
993 ieee80211_sched_scan_stopped(wl->hw);
994 wl->sched_scanning = false;
995 }
996
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200997 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300998 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200999 ieee80211_restart_hw(wl->hw);
1000
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001001 /*
1002 * Its safe to enable TX now - the queues are stopped after a request
1003 * to restart the HW.
1004 */
1005 ieee80211_wake_queues(wl->hw);
1006
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001007out:
1008 mutex_unlock(&wl->mutex);
1009}
1010
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011static void wl1271_fw_wakeup(struct wl1271 *wl)
1012{
1013 u32 elp_reg;
1014
1015 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001016 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001017}
1018
1019static int wl1271_setup(struct wl1271 *wl)
1020{
1021 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1022 if (!wl->fw_status)
1023 return -ENOMEM;
1024
1025 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1026 if (!wl->tx_res_if) {
1027 kfree(wl->fw_status);
1028 return -ENOMEM;
1029 }
1030
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 return 0;
1032}
1033
1034static int wl1271_chip_wakeup(struct wl1271 *wl)
1035{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001036 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 int ret = 0;
1038
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001039 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001040 ret = wl1271_power_on(wl);
1041 if (ret < 0)
1042 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001044 wl1271_io_reset(wl);
1045 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
1047 /* We don't need a real memory partition here, because we only want
1048 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001049 memset(&partition, 0, sizeof(partition));
1050 partition.reg.start = REGISTERS_BASE;
1051 partition.reg.size = REGISTERS_DOWN_SIZE;
1052 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053
1054 /* ELP module wake up */
1055 wl1271_fw_wakeup(wl);
1056
1057 /* whal_FwCtrl_BootSm() */
1058
1059 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001060 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001061
1062 /* 1. check if chip id is valid */
1063
1064 switch (wl->chip.id) {
1065 case CHIP_ID_1271_PG10:
1066 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1067 wl->chip.id);
1068
1069 ret = wl1271_setup(wl);
1070 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001071 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 break;
1073 case CHIP_ID_1271_PG20:
1074 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1075 wl->chip.id);
1076
Shahar Levi564f5952011-04-04 10:20:39 +03001077 /* end-of-transaction flag should be set in wl127x AP mode */
1078 if (wl->bss_type == BSS_TYPE_AP_BSS)
1079 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1080
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 ret = wl1271_setup(wl);
1082 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001083 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001085 case CHIP_ID_1283_PG20:
1086 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1087 wl->chip.id);
1088
1089 ret = wl1271_setup(wl);
1090 if (ret < 0)
1091 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001092 if (wl1271_set_block_size(wl))
1093 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001094 break;
1095 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001097 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001099 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001100 }
1101
Arik Nemtsov166d5042010-10-16 21:44:57 +02001102 /* Make sure the firmware type matches the BSS type */
1103 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001104 ret = wl1271_fetch_firmware(wl);
1105 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001106 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 }
1108
1109 /* No NVS from netlink, try to get it from the filesystem */
1110 if (wl->nvs == NULL) {
1111 ret = wl1271_fetch_nvs(wl);
1112 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001113 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001114 }
1115
1116out:
1117 return ret;
1118}
1119
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001120static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1121{
1122 unsigned int quirks = 0;
1123 unsigned int *fw_ver = wl->chip.fw_ver;
1124
1125 /* Only for wl127x */
1126 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1127 /* Check STA version */
1128 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1129 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1130 /* Check AP version */
1131 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1132 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1133 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1134
1135 return quirks;
1136}
1137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001138int wl1271_plt_start(struct wl1271 *wl)
1139{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001140 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001141 int ret;
1142
1143 mutex_lock(&wl->mutex);
1144
1145 wl1271_notice("power up");
1146
1147 if (wl->state != WL1271_STATE_OFF) {
1148 wl1271_error("cannot go into PLT state because not "
1149 "in off state: %d", wl->state);
1150 ret = -EBUSY;
1151 goto out;
1152 }
1153
Arik Nemtsov166d5042010-10-16 21:44:57 +02001154 wl->bss_type = BSS_TYPE_STA_BSS;
1155
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001156 while (retries) {
1157 retries--;
1158 ret = wl1271_chip_wakeup(wl);
1159 if (ret < 0)
1160 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001162 ret = wl1271_boot(wl);
1163 if (ret < 0)
1164 goto power_off;
1165
1166 ret = wl1271_plt_init(wl);
1167 if (ret < 0)
1168 goto irq_disable;
1169
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001170 wl->state = WL1271_STATE_PLT;
1171 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001172 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001173
1174 /* Check if any quirks are needed with older fw versions */
1175 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001176 goto out;
1177
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001178irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001179 mutex_unlock(&wl->mutex);
1180 /* Unlocking the mutex in the middle of handling is
1181 inherently unsafe. In this case we deem it safe to do,
1182 because we need to let any possibly pending IRQ out of
1183 the system (and while we are WL1271_STATE_OFF the IRQ
1184 work function will not do anything.) Also, any other
1185 possible concurrent operations will fail due to the
1186 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001187 wl1271_disable_interrupts(wl);
1188 wl1271_flush_deferred_work(wl);
1189 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001190 mutex_lock(&wl->mutex);
1191power_off:
1192 wl1271_power_off(wl);
1193 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001194
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001195 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1196 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001197out:
1198 mutex_unlock(&wl->mutex);
1199
1200 return ret;
1201}
1202
Luciano Coelho4623ec72011-03-21 19:26:41 +02001203static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001204{
1205 int ret = 0;
1206
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001207 wl1271_notice("power down");
1208
1209 if (wl->state != WL1271_STATE_PLT) {
1210 wl1271_error("cannot power down because not in PLT "
1211 "state: %d", wl->state);
1212 ret = -EBUSY;
1213 goto out;
1214 }
1215
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001216 wl1271_power_off(wl);
1217
1218 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001219 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001221 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001222 wl1271_disable_interrupts(wl);
1223 wl1271_flush_deferred_work(wl);
1224 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001225 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001226 mutex_lock(&wl->mutex);
1227out:
1228 return ret;
1229}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001230
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001231int wl1271_plt_stop(struct wl1271 *wl)
1232{
1233 int ret;
1234
1235 mutex_lock(&wl->mutex);
1236 ret = __wl1271_plt_stop(wl);
1237 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 return ret;
1239}
1240
Johannes Berg7bb45682011-02-24 14:42:06 +01001241static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242{
1243 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001244 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001245 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001246 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001247
Ido Yarivb07d4032011-03-01 15:14:43 +02001248 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1249
1250 if (wl->bss_type == BSS_TYPE_AP_BSS)
1251 hlid = wl1271_tx_get_hlid(skb);
1252
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001253 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001254
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001255 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001256
1257 /*
1258 * The workqueue is slow to process the tx_queue and we need stop
1259 * the queue here, otherwise the queue will get too long.
1260 */
1261 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1262 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1263 ieee80211_stop_queues(wl->hw);
1264 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1265 }
1266
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001267 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001268 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001269 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1270 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1271 } else {
1272 skb_queue_tail(&wl->tx_queue[q], skb);
1273 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274
1275 /*
1276 * The chip specific setup must run before the first TX packet -
1277 * before that, the tx_work will not be initialized!
1278 */
1279
Ido Yarivb07d4032011-03-01 15:14:43 +02001280 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1281 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001282 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001283
1284 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285}
1286
Shahar Leviae47c452011-03-06 16:32:14 +02001287int wl1271_tx_dummy_packet(struct wl1271 *wl)
1288{
Ido Yariv990f5de2011-03-31 10:06:59 +02001289 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001290
Ido Yariv990f5de2011-03-31 10:06:59 +02001291 spin_lock_irqsave(&wl->wl_lock, flags);
1292 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1293 wl->tx_queue_count++;
1294 spin_unlock_irqrestore(&wl->wl_lock, flags);
1295
1296 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1297 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1298 wl1271_tx_work_locked(wl);
1299
1300 /*
1301 * If the FW TX is busy, TX work will be scheduled by the threaded
1302 * interrupt handler function
1303 */
1304 return 0;
1305}
1306
1307/*
1308 * The size of the dummy packet should be at least 1400 bytes. However, in
1309 * order to minimize the number of bus transactions, aligning it to 512 bytes
1310 * boundaries could be beneficial, performance wise
1311 */
1312#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1313
Luciano Coelhocf27d862011-04-01 21:08:23 +03001314static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001315{
1316 struct sk_buff *skb;
1317 struct ieee80211_hdr_3addr *hdr;
1318 unsigned int dummy_packet_size;
1319
1320 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1321 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1322
1323 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001324 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001325 wl1271_warning("Failed to allocate a dummy packet skb");
1326 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001327 }
1328
1329 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1330
1331 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1332 memset(hdr, 0, sizeof(*hdr));
1333 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001334 IEEE80211_STYPE_NULLFUNC |
1335 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001336
Ido Yariv990f5de2011-03-31 10:06:59 +02001337 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001338
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001339 /* Dummy packets require the TID to be management */
1340 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001341
1342 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001343 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001344 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001345
Ido Yariv990f5de2011-03-31 10:06:59 +02001346 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001347}
1348
Ido Yariv990f5de2011-03-31 10:06:59 +02001349
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001350static struct notifier_block wl1271_dev_notifier = {
1351 .notifier_call = wl1271_dev_notify,
1352};
1353
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001354#ifdef CONFIG_PM
Eliad Peller94390642011-05-13 11:57:13 +03001355static int wl1271_configure_suspend(struct wl1271 *wl)
1356{
1357 int ret;
1358
1359 if (wl->bss_type != BSS_TYPE_STA_BSS)
1360 return 0;
1361
1362 mutex_lock(&wl->mutex);
1363
1364 ret = wl1271_ps_elp_wakeup(wl);
1365 if (ret < 0)
1366 goto out_unlock;
1367
1368 /* enter psm if needed*/
1369 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1370 DECLARE_COMPLETION_ONSTACK(compl);
1371
1372 wl->ps_compl = &compl;
1373 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1374 wl->basic_rate, true);
1375 if (ret < 0)
1376 goto out_sleep;
1377
1378 /* we must unlock here so we will be able to get events */
1379 wl1271_ps_elp_sleep(wl);
1380 mutex_unlock(&wl->mutex);
1381
1382 ret = wait_for_completion_timeout(
1383 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1384 if (ret <= 0) {
1385 wl1271_warning("couldn't enter ps mode!");
1386 ret = -EBUSY;
1387 goto out;
1388 }
1389
1390 /* take mutex again, and wakeup */
1391 mutex_lock(&wl->mutex);
1392
1393 ret = wl1271_ps_elp_wakeup(wl);
1394 if (ret < 0)
1395 goto out_unlock;
1396 }
1397out_sleep:
1398 wl1271_ps_elp_sleep(wl);
1399out_unlock:
1400 mutex_unlock(&wl->mutex);
1401out:
1402 return ret;
1403
1404}
1405
1406static void wl1271_configure_resume(struct wl1271 *wl)
1407{
1408 int ret;
1409
1410 if (wl->bss_type != BSS_TYPE_STA_BSS)
1411 return;
1412
1413 mutex_lock(&wl->mutex);
1414 ret = wl1271_ps_elp_wakeup(wl);
1415 if (ret < 0)
1416 goto out;
1417
1418 /* exit psm if it wasn't configured */
1419 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1420 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1421 wl->basic_rate, true);
1422
1423 wl1271_ps_elp_sleep(wl);
1424out:
1425 mutex_unlock(&wl->mutex);
1426}
1427
Eliad Peller402e48612011-05-13 11:57:09 +03001428static int wl1271_op_suspend(struct ieee80211_hw *hw,
1429 struct cfg80211_wowlan *wow)
1430{
1431 struct wl1271 *wl = hw->priv;
1432 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1433 wl->wow_enabled = !!wow;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001434 if (wl->wow_enabled) {
Eliad Peller94390642011-05-13 11:57:13 +03001435 int ret;
1436 ret = wl1271_configure_suspend(wl);
1437 if (ret < 0) {
1438 wl1271_warning("couldn't prepare device to suspend");
1439 return ret;
1440 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001441 /* flush any remaining work */
1442 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1443 flush_delayed_work(&wl->scan_complete_work);
1444
1445 /*
1446 * disable and re-enable interrupts in order to flush
1447 * the threaded_irq
1448 */
1449 wl1271_disable_interrupts(wl);
1450
1451 /*
1452 * set suspended flag to avoid triggering a new threaded_irq
1453 * work. no need for spinlock as interrupts are disabled.
1454 */
1455 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1456
1457 wl1271_enable_interrupts(wl);
1458 flush_work(&wl->tx_work);
1459 flush_delayed_work(&wl->pspoll_work);
1460 flush_delayed_work(&wl->elp_work);
1461 }
Eliad Peller402e48612011-05-13 11:57:09 +03001462 return 0;
1463}
1464
1465static int wl1271_op_resume(struct ieee80211_hw *hw)
1466{
1467 struct wl1271 *wl = hw->priv;
1468 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1469 wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001470
1471 /*
1472 * re-enable irq_work enqueuing, and call irq_work directly if
1473 * there is a pending work.
1474 */
1475 if (wl->wow_enabled) {
1476 struct wl1271 *wl = hw->priv;
1477 unsigned long flags;
1478 bool run_irq_work = false;
1479
1480 spin_lock_irqsave(&wl->wl_lock, flags);
1481 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1482 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1483 run_irq_work = true;
1484 spin_unlock_irqrestore(&wl->wl_lock, flags);
1485
1486 if (run_irq_work) {
1487 wl1271_debug(DEBUG_MAC80211,
1488 "run postponed irq_work directly");
1489 wl1271_irq(0, wl);
1490 wl1271_enable_interrupts(wl);
1491 }
Eliad Peller94390642011-05-13 11:57:13 +03001492
1493 wl1271_configure_resume(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001494 }
1495
Eliad Peller402e48612011-05-13 11:57:09 +03001496 return 0;
1497}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001498#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001499
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001500static int wl1271_op_start(struct ieee80211_hw *hw)
1501{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001502 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1503
1504 /*
1505 * We have to delay the booting of the hardware because
1506 * we need to know the local MAC address before downloading and
1507 * initializing the firmware. The MAC address cannot be changed
1508 * after boot, and without the proper MAC address, the firmware
1509 * will not function properly.
1510 *
1511 * The MAC address is first known when the corresponding interface
1512 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001513 *
1514 * In addition, we currently have different firmwares for AP and managed
1515 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001516 */
1517
1518 return 0;
1519}
1520
1521static void wl1271_op_stop(struct ieee80211_hw *hw)
1522{
1523 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1524}
1525
1526static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1527 struct ieee80211_vif *vif)
1528{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001530 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001531 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001533 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001535 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1536 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001537
1538 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001539 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001540 wl1271_debug(DEBUG_MAC80211,
1541 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001542 ret = -EBUSY;
1543 goto out;
1544 }
1545
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001546 /*
1547 * in some very corner case HW recovery scenarios its possible to
1548 * get here before __wl1271_op_remove_interface is complete, so
1549 * opt out if that is the case.
1550 */
1551 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1552 ret = -EBUSY;
1553 goto out;
1554 }
1555
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001556 switch (vif->type) {
1557 case NL80211_IFTYPE_STATION:
1558 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001559 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001560 break;
1561 case NL80211_IFTYPE_ADHOC:
1562 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001563 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001564 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001565 case NL80211_IFTYPE_AP:
1566 wl->bss_type = BSS_TYPE_AP_BSS;
1567 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001568 default:
1569 ret = -EOPNOTSUPP;
1570 goto out;
1571 }
1572
1573 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574
1575 if (wl->state != WL1271_STATE_OFF) {
1576 wl1271_error("cannot start because not in off state: %d",
1577 wl->state);
1578 ret = -EBUSY;
1579 goto out;
1580 }
1581
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001582 while (retries) {
1583 retries--;
1584 ret = wl1271_chip_wakeup(wl);
1585 if (ret < 0)
1586 goto power_off;
1587
1588 ret = wl1271_boot(wl);
1589 if (ret < 0)
1590 goto power_off;
1591
1592 ret = wl1271_hw_init(wl);
1593 if (ret < 0)
1594 goto irq_disable;
1595
Eliad Peller71125ab2010-10-28 21:46:43 +02001596 booted = true;
1597 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001598
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001599irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001600 mutex_unlock(&wl->mutex);
1601 /* Unlocking the mutex in the middle of handling is
1602 inherently unsafe. In this case we deem it safe to do,
1603 because we need to let any possibly pending IRQ out of
1604 the system (and while we are WL1271_STATE_OFF the IRQ
1605 work function will not do anything.) Also, any other
1606 possible concurrent operations will fail due to the
1607 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001608 wl1271_disable_interrupts(wl);
1609 wl1271_flush_deferred_work(wl);
1610 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001611 mutex_lock(&wl->mutex);
1612power_off:
1613 wl1271_power_off(wl);
1614 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001615
Eliad Peller71125ab2010-10-28 21:46:43 +02001616 if (!booted) {
1617 wl1271_error("firmware boot failed despite %d retries",
1618 WL1271_BOOT_RETRIES);
1619 goto out;
1620 }
1621
1622 wl->vif = vif;
1623 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001624 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001625 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001626
1627 /* update hw/fw version info in wiphy struct */
1628 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001629 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001630 sizeof(wiphy->fw_version));
1631
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001632 /* Check if any quirks are needed with older fw versions */
1633 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1634
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001635 /*
1636 * Now we know if 11a is supported (info from the NVS), so disable
1637 * 11a channels if not supported
1638 */
1639 if (!wl->enable_11a)
1640 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1641
1642 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1643 wl->enable_11a ? "" : "not ");
1644
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001645out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001646 mutex_unlock(&wl->mutex);
1647
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001648 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001649 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001650 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001651 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653 return ret;
1654}
1655
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001656static void __wl1271_op_remove_interface(struct wl1271 *wl,
1657 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001658{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659 int i;
1660
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001661 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001662
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001663 /* because of hardware recovery, we may get here twice */
1664 if (wl->state != WL1271_STATE_ON)
1665 return;
1666
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001667 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001668
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001669 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001670 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001671 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001672
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001673 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001674 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001675 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001676
Luciano Coelho08688d62010-07-08 17:50:07 +03001677 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001678 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001679 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001680 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001681 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682 }
1683
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001684 /*
1685 * this must be before the cancel_work calls below, so that the work
1686 * functions don't perform further work.
1687 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001688 wl->state = WL1271_STATE_OFF;
1689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690 mutex_unlock(&wl->mutex);
1691
Ido Yariva6208652011-03-01 15:14:41 +02001692 wl1271_disable_interrupts(wl);
1693 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001694 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001695 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001697 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001698 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001699
1700 mutex_lock(&wl->mutex);
1701
1702 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001703 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001704 wl1271_power_off(wl);
1705
1706 memset(wl->bssid, 0, ETH_ALEN);
1707 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1708 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001710 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001711 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712
1713 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001714 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1716 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001717 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001718 wl->tx_results_count = 0;
1719 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001720 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001721 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001722 wl->time_offset = 0;
1723 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001724 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001725 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001726 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001727 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001728 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001729 wl->ap_fw_ps_map = 0;
1730 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001731 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001732
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001733 /*
1734 * this is performed after the cancel_work calls and the associated
1735 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1736 * get executed before all these vars have been reset.
1737 */
1738 wl->flags = 0;
1739
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001740 for (i = 0; i < NUM_TX_QUEUES; i++)
1741 wl->tx_blocks_freed[i] = 0;
1742
1743 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001744
1745 kfree(wl->fw_status);
1746 wl->fw_status = NULL;
1747 kfree(wl->tx_res_if);
1748 wl->tx_res_if = NULL;
1749 kfree(wl->target_mem_map);
1750 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001751}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001752
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001753static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1754 struct ieee80211_vif *vif)
1755{
1756 struct wl1271 *wl = hw->priv;
1757
1758 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001759 /*
1760 * wl->vif can be null here if someone shuts down the interface
1761 * just when hardware recovery has been started.
1762 */
1763 if (wl->vif) {
1764 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001765 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001766 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001767
Juuso Oikarinen67353292010-11-18 15:19:02 +02001768 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001769 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001770}
1771
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001772void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001773{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001774 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001775
1776 /* combine requested filters with current filter config */
1777 filters = wl->filters | filters;
1778
1779 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1780
1781 if (filters & FIF_PROMISC_IN_BSS) {
1782 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1783 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1784 wl->rx_config |= CFG_BSSID_FILTER_EN;
1785 }
1786 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1787 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1788 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1789 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1790 }
1791 if (filters & FIF_OTHER_BSS) {
1792 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1793 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1794 }
1795 if (filters & FIF_CONTROL) {
1796 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1797 wl->rx_filter |= CFG_RX_CTL_EN;
1798 }
1799 if (filters & FIF_FCSFAIL) {
1800 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1801 wl->rx_filter |= CFG_RX_FCS_ERROR;
1802 }
1803}
1804
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001805static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001806{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001807 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001808 /* we need to use a dummy BSSID for now */
1809 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1810 0xad, 0xbe, 0xef };
1811
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001812 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1813
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001814 /* pass through frames from all BSS */
1815 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1816
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001817 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001818 if (ret < 0)
1819 goto out;
1820
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001821 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001822
1823out:
1824 return ret;
1825}
1826
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001827static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001828{
1829 int ret;
1830
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001831 /*
1832 * One of the side effects of the JOIN command is that is clears
1833 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1834 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001835 * Currently the only valid scenario for JOIN during association
1836 * is on roaming, in which case we will also be given new keys.
1837 * Keep the below message for now, unless it starts bothering
1838 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001839 */
1840 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1841 wl1271_info("JOIN while associated.");
1842
1843 if (set_assoc)
1844 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1845
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001846 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1847 if (ret < 0)
1848 goto out;
1849
1850 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1851
1852 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1853 goto out;
1854
1855 /*
1856 * The join command disable the keep-alive mode, shut down its process,
1857 * and also clear the template config, so we need to reset it all after
1858 * the join. The acx_aid starts the keep-alive process, and the order
1859 * of the commands below is relevant.
1860 */
1861 ret = wl1271_acx_keep_alive_mode(wl, true);
1862 if (ret < 0)
1863 goto out;
1864
1865 ret = wl1271_acx_aid(wl, wl->aid);
1866 if (ret < 0)
1867 goto out;
1868
1869 ret = wl1271_cmd_build_klv_null_data(wl);
1870 if (ret < 0)
1871 goto out;
1872
1873 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1874 ACX_KEEP_ALIVE_TPL_VALID);
1875 if (ret < 0)
1876 goto out;
1877
1878out:
1879 return ret;
1880}
1881
1882static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001883{
1884 int ret;
1885
1886 /* to stop listening to a channel, we disconnect */
1887 ret = wl1271_cmd_disconnect(wl);
1888 if (ret < 0)
1889 goto out;
1890
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001891 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001892 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001893
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001894 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001895 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001896
1897out:
1898 return ret;
1899}
1900
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001901static void wl1271_set_band_rate(struct wl1271 *wl)
1902{
1903 if (wl->band == IEEE80211_BAND_2GHZ)
1904 wl->basic_rate_set = wl->conf.tx.basic_rate;
1905 else
1906 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1907}
1908
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001909static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001910{
1911 int ret;
1912
1913 if (idle) {
1914 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1915 ret = wl1271_unjoin(wl);
1916 if (ret < 0)
1917 goto out;
1918 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001919 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001920 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001921 if (ret < 0)
1922 goto out;
1923 ret = wl1271_acx_keep_alive_config(
1924 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1925 ACX_KEEP_ALIVE_TPL_INVALID);
1926 if (ret < 0)
1927 goto out;
1928 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1929 } else {
1930 /* increment the session counter */
1931 wl->session_counter++;
1932 if (wl->session_counter >= SESSION_COUNTER_MAX)
1933 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001934
1935 /* The current firmware only supports sched_scan in idle */
1936 if (wl->sched_scanning) {
1937 wl1271_scan_sched_scan_stop(wl);
1938 ieee80211_sched_scan_stopped(wl->hw);
1939 }
1940
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001941 ret = wl1271_dummy_join(wl);
1942 if (ret < 0)
1943 goto out;
1944 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1945 }
1946
1947out:
1948 return ret;
1949}
1950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1952{
1953 struct wl1271 *wl = hw->priv;
1954 struct ieee80211_conf *conf = &hw->conf;
1955 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001956 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957
1958 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1959
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001960 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1961 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962 channel,
1963 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001964 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001965 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1966 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001967
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001968 /*
1969 * mac80211 will go to idle nearly immediately after transmitting some
1970 * frames, such as the deauth. To make sure those frames reach the air,
1971 * wait here until the TX queue is fully flushed.
1972 */
1973 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1974 (conf->flags & IEEE80211_CONF_IDLE))
1975 wl1271_tx_flush(wl);
1976
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977 mutex_lock(&wl->mutex);
1978
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001979 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001980 /* we support configuring the channel and band while off */
1981 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1982 wl->band = conf->channel->band;
1983 wl->channel = channel;
1984 }
1985
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001986 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001987 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001988
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001989 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1990
Ido Yariva6208652011-03-01 15:14:41 +02001991 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992 if (ret < 0)
1993 goto out;
1994
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001995 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001996 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1997 ((wl->band != conf->channel->band) ||
1998 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001999 wl->band = conf->channel->band;
2000 wl->channel = channel;
2001
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002002 if (!is_ap) {
2003 /*
2004 * FIXME: the mac80211 should really provide a fixed
2005 * rate to use here. for now, just use the smallest
2006 * possible rate for the band as a fixed rate for
2007 * association frames and other control messages.
2008 */
2009 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2010 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002011
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002012 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2013 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002014 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002015 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002016 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002017
2018 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2019 ret = wl1271_join(wl, false);
2020 if (ret < 0)
2021 wl1271_warning("cmd join on channel "
2022 "failed %d", ret);
2023 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002024 }
2025 }
2026
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002027 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2028 ret = wl1271_sta_handle_idle(wl,
2029 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002030 if (ret < 0)
2031 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002032 }
2033
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002034 /*
2035 * if mac80211 changes the PSM mode, make sure the mode is not
2036 * incorrectly changed after the pspoll failure active window.
2037 */
2038 if (changed & IEEE80211_CONF_CHANGE_PS)
2039 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2040
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002041 if (conf->flags & IEEE80211_CONF_PS &&
2042 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2043 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044
2045 /*
2046 * We enter PSM only if we're already associated.
2047 * If we're not, we'll enter it when joining an SSID,
2048 * through the bss_info_changed() hook.
2049 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002050 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002051 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002052 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002053 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002054 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002056 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002057 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002059 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002060
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002061 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002062 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002063 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 }
2065
2066 if (conf->power_level != wl->power_level) {
2067 ret = wl1271_acx_tx_power(wl, conf->power_level);
2068 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002069 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070
2071 wl->power_level = conf->power_level;
2072 }
2073
2074out_sleep:
2075 wl1271_ps_elp_sleep(wl);
2076
2077out:
2078 mutex_unlock(&wl->mutex);
2079
2080 return ret;
2081}
2082
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002083struct wl1271_filter_params {
2084 bool enabled;
2085 int mc_list_length;
2086 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2087};
2088
Jiri Pirko22bedad2010-04-01 21:22:57 +00002089static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2090 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002091{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002092 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002093 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002094 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002095
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002096 if (unlikely(wl->state == WL1271_STATE_OFF))
2097 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002098
Juuso Oikarinen74441132009-10-13 12:47:53 +03002099 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002100 if (!fp) {
2101 wl1271_error("Out of memory setting filters.");
2102 return 0;
2103 }
2104
2105 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002106 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002107 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2108 fp->enabled = false;
2109 } else {
2110 fp->enabled = true;
2111 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002112 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002113 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002114 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002115 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002116 }
2117
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002118 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002119}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002120
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002121#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2122 FIF_ALLMULTI | \
2123 FIF_FCSFAIL | \
2124 FIF_BCN_PRBRESP_PROMISC | \
2125 FIF_CONTROL | \
2126 FIF_OTHER_BSS)
2127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2129 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002130 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002131{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002132 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002134 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135
Arik Nemtsov7d057862010-10-16 19:25:35 +02002136 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2137 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002139 mutex_lock(&wl->mutex);
2140
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002141 *total &= WL1271_SUPPORTED_FILTERS;
2142 changed &= WL1271_SUPPORTED_FILTERS;
2143
2144 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002145 goto out;
2146
Ido Yariva6208652011-03-01 15:14:41 +02002147 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002148 if (ret < 0)
2149 goto out;
2150
Arik Nemtsov7d057862010-10-16 19:25:35 +02002151 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2152 if (*total & FIF_ALLMULTI)
2153 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2154 else if (fp)
2155 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2156 fp->mc_list,
2157 fp->mc_list_length);
2158 if (ret < 0)
2159 goto out_sleep;
2160 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002161
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002162 /* determine, whether supported filter values have changed */
2163 if (changed == 0)
2164 goto out_sleep;
2165
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002166 /* configure filters */
2167 wl->filters = *total;
2168 wl1271_configure_filters(wl, 0);
2169
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002170 /* apply configured filters */
2171 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2172 if (ret < 0)
2173 goto out_sleep;
2174
2175out_sleep:
2176 wl1271_ps_elp_sleep(wl);
2177
2178out:
2179 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002180 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181}
2182
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002183static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2184 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2185 u16 tx_seq_16)
2186{
2187 struct wl1271_ap_key *ap_key;
2188 int i;
2189
2190 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2191
2192 if (key_size > MAX_KEY_SIZE)
2193 return -EINVAL;
2194
2195 /*
2196 * Find next free entry in ap_keys. Also check we are not replacing
2197 * an existing key.
2198 */
2199 for (i = 0; i < MAX_NUM_KEYS; i++) {
2200 if (wl->recorded_ap_keys[i] == NULL)
2201 break;
2202
2203 if (wl->recorded_ap_keys[i]->id == id) {
2204 wl1271_warning("trying to record key replacement");
2205 return -EINVAL;
2206 }
2207 }
2208
2209 if (i == MAX_NUM_KEYS)
2210 return -EBUSY;
2211
2212 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2213 if (!ap_key)
2214 return -ENOMEM;
2215
2216 ap_key->id = id;
2217 ap_key->key_type = key_type;
2218 ap_key->key_size = key_size;
2219 memcpy(ap_key->key, key, key_size);
2220 ap_key->hlid = hlid;
2221 ap_key->tx_seq_32 = tx_seq_32;
2222 ap_key->tx_seq_16 = tx_seq_16;
2223
2224 wl->recorded_ap_keys[i] = ap_key;
2225 return 0;
2226}
2227
2228static void wl1271_free_ap_keys(struct wl1271 *wl)
2229{
2230 int i;
2231
2232 for (i = 0; i < MAX_NUM_KEYS; i++) {
2233 kfree(wl->recorded_ap_keys[i]);
2234 wl->recorded_ap_keys[i] = NULL;
2235 }
2236}
2237
2238static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2239{
2240 int i, ret = 0;
2241 struct wl1271_ap_key *key;
2242 bool wep_key_added = false;
2243
2244 for (i = 0; i < MAX_NUM_KEYS; i++) {
2245 if (wl->recorded_ap_keys[i] == NULL)
2246 break;
2247
2248 key = wl->recorded_ap_keys[i];
2249 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2250 key->id, key->key_type,
2251 key->key_size, key->key,
2252 key->hlid, key->tx_seq_32,
2253 key->tx_seq_16);
2254 if (ret < 0)
2255 goto out;
2256
2257 if (key->key_type == KEY_WEP)
2258 wep_key_added = true;
2259 }
2260
2261 if (wep_key_added) {
2262 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2263 if (ret < 0)
2264 goto out;
2265 }
2266
2267out:
2268 wl1271_free_ap_keys(wl);
2269 return ret;
2270}
2271
2272static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2273 u8 key_size, const u8 *key, u32 tx_seq_32,
2274 u16 tx_seq_16, struct ieee80211_sta *sta)
2275{
2276 int ret;
2277 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2278
2279 if (is_ap) {
2280 struct wl1271_station *wl_sta;
2281 u8 hlid;
2282
2283 if (sta) {
2284 wl_sta = (struct wl1271_station *)sta->drv_priv;
2285 hlid = wl_sta->hlid;
2286 } else {
2287 hlid = WL1271_AP_BROADCAST_HLID;
2288 }
2289
2290 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2291 /*
2292 * We do not support removing keys after AP shutdown.
2293 * Pretend we do to make mac80211 happy.
2294 */
2295 if (action != KEY_ADD_OR_REPLACE)
2296 return 0;
2297
2298 ret = wl1271_record_ap_key(wl, id,
2299 key_type, key_size,
2300 key, hlid, tx_seq_32,
2301 tx_seq_16);
2302 } else {
2303 ret = wl1271_cmd_set_ap_key(wl, action,
2304 id, key_type, key_size,
2305 key, hlid, tx_seq_32,
2306 tx_seq_16);
2307 }
2308
2309 if (ret < 0)
2310 return ret;
2311 } else {
2312 const u8 *addr;
2313 static const u8 bcast_addr[ETH_ALEN] = {
2314 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2315 };
2316
2317 addr = sta ? sta->addr : bcast_addr;
2318
2319 if (is_zero_ether_addr(addr)) {
2320 /* We dont support TX only encryption */
2321 return -EOPNOTSUPP;
2322 }
2323
2324 /* The wl1271 does not allow to remove unicast keys - they
2325 will be cleared automatically on next CMD_JOIN. Ignore the
2326 request silently, as we dont want the mac80211 to emit
2327 an error message. */
2328 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2329 return 0;
2330
2331 ret = wl1271_cmd_set_sta_key(wl, action,
2332 id, key_type, key_size,
2333 key, addr, tx_seq_32,
2334 tx_seq_16);
2335 if (ret < 0)
2336 return ret;
2337
2338 /* the default WEP key needs to be configured at least once */
2339 if (key_type == KEY_WEP) {
2340 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2341 wl->default_key);
2342 if (ret < 0)
2343 return ret;
2344 }
2345 }
2346
2347 return 0;
2348}
2349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2351 struct ieee80211_vif *vif,
2352 struct ieee80211_sta *sta,
2353 struct ieee80211_key_conf *key_conf)
2354{
2355 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002357 u32 tx_seq_32 = 0;
2358 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002359 u8 key_type;
2360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2362
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002363 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002365 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 key_conf->keylen, key_conf->flags);
2367 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2368
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369 mutex_lock(&wl->mutex);
2370
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002371 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2372 ret = -EAGAIN;
2373 goto out_unlock;
2374 }
2375
Ido Yariva6208652011-03-01 15:14:41 +02002376 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377 if (ret < 0)
2378 goto out_unlock;
2379
Johannes Berg97359d12010-08-10 09:46:38 +02002380 switch (key_conf->cipher) {
2381 case WLAN_CIPHER_SUITE_WEP40:
2382 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002383 key_type = KEY_WEP;
2384
2385 key_conf->hw_key_idx = key_conf->keyidx;
2386 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002387 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 key_type = KEY_TKIP;
2389
2390 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002391 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2392 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002394 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002395 key_type = KEY_AES;
2396
2397 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002398 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2399 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002400 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002401 case WL1271_CIPHER_SUITE_GEM:
2402 key_type = KEY_GEM;
2403 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2404 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2405 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002406 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002407 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002408
2409 ret = -EOPNOTSUPP;
2410 goto out_sleep;
2411 }
2412
2413 switch (cmd) {
2414 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002415 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2416 key_conf->keyidx, key_type,
2417 key_conf->keylen, key_conf->key,
2418 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002419 if (ret < 0) {
2420 wl1271_error("Could not add or replace key");
2421 goto out_sleep;
2422 }
2423 break;
2424
2425 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002426 ret = wl1271_set_key(wl, KEY_REMOVE,
2427 key_conf->keyidx, key_type,
2428 key_conf->keylen, key_conf->key,
2429 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002430 if (ret < 0) {
2431 wl1271_error("Could not remove key");
2432 goto out_sleep;
2433 }
2434 break;
2435
2436 default:
2437 wl1271_error("Unsupported key cmd 0x%x", cmd);
2438 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439 break;
2440 }
2441
2442out_sleep:
2443 wl1271_ps_elp_sleep(wl);
2444
2445out_unlock:
2446 mutex_unlock(&wl->mutex);
2447
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448 return ret;
2449}
2450
2451static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002452 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453 struct cfg80211_scan_request *req)
2454{
2455 struct wl1271 *wl = hw->priv;
2456 int ret;
2457 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002458 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002459
2460 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2461
2462 if (req->n_ssids) {
2463 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002464 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002465 }
2466
2467 mutex_lock(&wl->mutex);
2468
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002469 if (wl->state == WL1271_STATE_OFF) {
2470 /*
2471 * We cannot return -EBUSY here because cfg80211 will expect
2472 * a call to ieee80211_scan_completed if we do - in this case
2473 * there won't be any call.
2474 */
2475 ret = -EAGAIN;
2476 goto out;
2477 }
2478
Ido Yariva6208652011-03-01 15:14:41 +02002479 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480 if (ret < 0)
2481 goto out;
2482
Luciano Coelho5924f892010-08-04 03:46:22 +03002483 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002484
2485 wl1271_ps_elp_sleep(wl);
2486
2487out:
2488 mutex_unlock(&wl->mutex);
2489
2490 return ret;
2491}
2492
Luciano Coelho33c2c062011-05-10 14:46:02 +03002493static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2494 struct ieee80211_vif *vif,
2495 struct cfg80211_sched_scan_request *req,
2496 struct ieee80211_sched_scan_ies *ies)
2497{
2498 struct wl1271 *wl = hw->priv;
2499 int ret;
2500
2501 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2502
2503 mutex_lock(&wl->mutex);
2504
2505 ret = wl1271_ps_elp_wakeup(wl);
2506 if (ret < 0)
2507 goto out;
2508
2509 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2510 if (ret < 0)
2511 goto out_sleep;
2512
2513 ret = wl1271_scan_sched_scan_start(wl);
2514 if (ret < 0)
2515 goto out_sleep;
2516
2517 wl->sched_scanning = true;
2518
2519out_sleep:
2520 wl1271_ps_elp_sleep(wl);
2521out:
2522 mutex_unlock(&wl->mutex);
2523 return ret;
2524}
2525
2526static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2527 struct ieee80211_vif *vif)
2528{
2529 struct wl1271 *wl = hw->priv;
2530 int ret;
2531
2532 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2533
2534 mutex_lock(&wl->mutex);
2535
2536 ret = wl1271_ps_elp_wakeup(wl);
2537 if (ret < 0)
2538 goto out;
2539
2540 wl1271_scan_sched_scan_stop(wl);
2541
2542 wl1271_ps_elp_sleep(wl);
2543out:
2544 mutex_unlock(&wl->mutex);
2545}
2546
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002547static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2548{
2549 struct wl1271 *wl = hw->priv;
2550 int ret = 0;
2551
2552 mutex_lock(&wl->mutex);
2553
2554 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2555 ret = -EAGAIN;
2556 goto out;
2557 }
2558
Ido Yariva6208652011-03-01 15:14:41 +02002559 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002560 if (ret < 0)
2561 goto out;
2562
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002563 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002564 if (ret < 0)
2565 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2566
2567 wl1271_ps_elp_sleep(wl);
2568
2569out:
2570 mutex_unlock(&wl->mutex);
2571
2572 return ret;
2573}
2574
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2576{
2577 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002578 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002579
2580 mutex_lock(&wl->mutex);
2581
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002582 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2583 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002584 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002585 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002586
Ido Yariva6208652011-03-01 15:14:41 +02002587 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002588 if (ret < 0)
2589 goto out;
2590
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002591 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592 if (ret < 0)
2593 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2594
2595 wl1271_ps_elp_sleep(wl);
2596
2597out:
2598 mutex_unlock(&wl->mutex);
2599
2600 return ret;
2601}
2602
Arik Nemtsove78a2872010-10-16 19:07:21 +02002603static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002604 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002605{
Eliad Peller889cb362011-05-01 09:56:45 +03002606 u8 ssid_len;
2607 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2608 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002609
Eliad Peller889cb362011-05-01 09:56:45 +03002610 if (!ptr) {
2611 wl1271_error("No SSID in IEs!");
2612 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002613 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002614
Eliad Peller889cb362011-05-01 09:56:45 +03002615 ssid_len = ptr[1];
2616 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2617 wl1271_error("SSID is too long!");
2618 return -EINVAL;
2619 }
2620
2621 wl->ssid_len = ssid_len;
2622 memcpy(wl->ssid, ptr+2, ssid_len);
2623 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002624}
2625
Arik Nemtsove78a2872010-10-16 19:07:21 +02002626static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2627 struct ieee80211_bss_conf *bss_conf,
2628 u32 changed)
2629{
2630 int ret = 0;
2631
2632 if (changed & BSS_CHANGED_ERP_SLOT) {
2633 if (bss_conf->use_short_slot)
2634 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2635 else
2636 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2637 if (ret < 0) {
2638 wl1271_warning("Set slot time failed %d", ret);
2639 goto out;
2640 }
2641 }
2642
2643 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2644 if (bss_conf->use_short_preamble)
2645 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2646 else
2647 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2648 }
2649
2650 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2651 if (bss_conf->use_cts_prot)
2652 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2653 else
2654 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2655 if (ret < 0) {
2656 wl1271_warning("Set ctsprotect failed %d", ret);
2657 goto out;
2658 }
2659 }
2660
2661out:
2662 return ret;
2663}
2664
2665static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2666 struct ieee80211_vif *vif,
2667 struct ieee80211_bss_conf *bss_conf,
2668 u32 changed)
2669{
2670 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2671 int ret = 0;
2672
2673 if ((changed & BSS_CHANGED_BEACON_INT)) {
2674 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2675 bss_conf->beacon_int);
2676
2677 wl->beacon_int = bss_conf->beacon_int;
2678 }
2679
2680 if ((changed & BSS_CHANGED_BEACON)) {
2681 struct ieee80211_hdr *hdr;
2682 int ieoffset = offsetof(struct ieee80211_mgmt,
2683 u.beacon.variable);
2684 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2685 u16 tmpl_id;
2686
2687 if (!beacon)
2688 goto out;
2689
2690 wl1271_debug(DEBUG_MASTER, "beacon updated");
2691
2692 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2693 if (ret < 0) {
2694 dev_kfree_skb(beacon);
2695 goto out;
2696 }
2697 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2698 CMD_TEMPL_BEACON;
2699 ret = wl1271_cmd_template_set(wl, tmpl_id,
2700 beacon->data,
2701 beacon->len, 0,
2702 wl1271_tx_min_rate_get(wl));
2703 if (ret < 0) {
2704 dev_kfree_skb(beacon);
2705 goto out;
2706 }
2707
2708 hdr = (struct ieee80211_hdr *) beacon->data;
2709 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2710 IEEE80211_STYPE_PROBE_RESP);
2711
2712 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2713 CMD_TEMPL_PROBE_RESPONSE;
2714 ret = wl1271_cmd_template_set(wl,
2715 tmpl_id,
2716 beacon->data,
2717 beacon->len, 0,
2718 wl1271_tx_min_rate_get(wl));
2719 dev_kfree_skb(beacon);
2720 if (ret < 0)
2721 goto out;
2722 }
2723
2724out:
2725 return ret;
2726}
2727
2728/* AP mode changes */
2729static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002730 struct ieee80211_vif *vif,
2731 struct ieee80211_bss_conf *bss_conf,
2732 u32 changed)
2733{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002734 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735
Arik Nemtsove78a2872010-10-16 19:07:21 +02002736 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2737 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738
Arik Nemtsove78a2872010-10-16 19:07:21 +02002739 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2740 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002741
Arik Nemtsov70f47422011-04-18 14:15:25 +03002742 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002743 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002744 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002745 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002746 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002747
2748 ret = wl1271_ap_init_templates(wl);
2749 if (ret < 0)
2750 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002751 }
2752
Arik Nemtsove78a2872010-10-16 19:07:21 +02002753 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2754 if (ret < 0)
2755 goto out;
2756
2757 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2758 if (bss_conf->enable_beacon) {
2759 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2760 ret = wl1271_cmd_start_bss(wl);
2761 if (ret < 0)
2762 goto out;
2763
2764 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2765 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002766
2767 ret = wl1271_ap_init_hwenc(wl);
2768 if (ret < 0)
2769 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002770 }
2771 } else {
2772 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2773 ret = wl1271_cmd_stop_bss(wl);
2774 if (ret < 0)
2775 goto out;
2776
2777 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2778 wl1271_debug(DEBUG_AP, "stopped AP");
2779 }
2780 }
2781 }
2782
Eliad Pellercb5ae052011-04-07 15:52:05 +03002783 if (changed & BSS_CHANGED_IBSS) {
2784 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2785 bss_conf->ibss_joined);
2786
2787 if (bss_conf->ibss_joined) {
2788 u32 rates = bss_conf->basic_rates;
2789 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2790 rates);
2791 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2792
2793 /* by default, use 11b rates */
2794 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2795 ret = wl1271_acx_sta_rate_policies(wl);
2796 if (ret < 0)
2797 goto out;
2798 }
2799 }
2800
Arik Nemtsove78a2872010-10-16 19:07:21 +02002801 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2802 if (ret < 0)
2803 goto out;
2804out:
2805 return;
2806}
2807
2808/* STA/IBSS mode changes */
2809static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2810 struct ieee80211_vif *vif,
2811 struct ieee80211_bss_conf *bss_conf,
2812 u32 changed)
2813{
2814 bool do_join = false, set_assoc = false;
2815 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002816 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002817 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002818 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002819 bool sta_exists = false;
2820 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002821
2822 if (is_ibss) {
2823 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2824 changed);
2825 if (ret < 0)
2826 goto out;
2827 }
2828
2829 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2830 do_join = true;
2831
2832 /* Need to update the SSID (for filtering etc) */
2833 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2834 do_join = true;
2835
2836 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002837 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2838 bss_conf->enable_beacon ? "enabled" : "disabled");
2839
2840 if (bss_conf->enable_beacon)
2841 wl->set_bss_type = BSS_TYPE_IBSS;
2842 else
2843 wl->set_bss_type = BSS_TYPE_STA_BSS;
2844 do_join = true;
2845 }
2846
Arik Nemtsove78a2872010-10-16 19:07:21 +02002847 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002848 bool enable = false;
2849 if (bss_conf->cqm_rssi_thold)
2850 enable = true;
2851 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2852 bss_conf->cqm_rssi_thold,
2853 bss_conf->cqm_rssi_hyst);
2854 if (ret < 0)
2855 goto out;
2856 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2857 }
2858
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002859 if ((changed & BSS_CHANGED_BSSID) &&
2860 /*
2861 * Now we know the correct bssid, so we send a new join command
2862 * and enable the BSSID filter
2863 */
2864 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002865 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002866
Eliad Pellerfa287b82010-12-26 09:27:50 +01002867 if (!is_zero_ether_addr(wl->bssid)) {
2868 ret = wl1271_cmd_build_null_data(wl);
2869 if (ret < 0)
2870 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002871
Eliad Pellerfa287b82010-12-26 09:27:50 +01002872 ret = wl1271_build_qos_null_data(wl);
2873 if (ret < 0)
2874 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002875
Eliad Pellerfa287b82010-12-26 09:27:50 +01002876 /* filter out all packets not from this BSSID */
2877 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002878
Eliad Pellerfa287b82010-12-26 09:27:50 +01002879 /* Need to update the BSSID (for filtering etc) */
2880 do_join = true;
2881 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002882 }
2883
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002884 rcu_read_lock();
2885 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2886 if (sta) {
2887 /* save the supp_rates of the ap */
2888 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2889 if (sta->ht_cap.ht_supported)
2890 sta_rate_set |=
2891 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002892 sta_ht_cap = sta->ht_cap;
2893 sta_exists = true;
2894 }
2895 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002896
Arik Nemtsova1008852011-02-12 23:24:20 +02002897 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002898 /* handle new association with HT and HT information change */
2899 if ((changed & BSS_CHANGED_HT) &&
2900 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002901 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002902 true);
2903 if (ret < 0) {
2904 wl1271_warning("Set ht cap true failed %d",
2905 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002906 goto out;
2907 }
2908 ret = wl1271_acx_set_ht_information(wl,
2909 bss_conf->ht_operation_mode);
2910 if (ret < 0) {
2911 wl1271_warning("Set ht information failed %d",
2912 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002913 goto out;
2914 }
2915 }
2916 /* handle new association without HT and disassociation */
2917 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002918 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002919 false);
2920 if (ret < 0) {
2921 wl1271_warning("Set ht cap false failed %d",
2922 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002923 goto out;
2924 }
2925 }
2926 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002927
Arik Nemtsove78a2872010-10-16 19:07:21 +02002928 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002930 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002931 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002932 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002933 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002935 wl->ps_poll_failures = 0;
2936
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002937 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002938 * use basic rates from AP, and determine lowest rate
2939 * to use with control frames.
2940 */
2941 rates = bss_conf->basic_rates;
2942 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2943 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002944 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002945 if (sta_rate_set)
2946 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2947 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002948 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002949 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002950 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002951
2952 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002953 * with wl1271, we don't need to update the
2954 * beacon_int and dtim_period, because the firmware
2955 * updates it by itself when the first beacon is
2956 * received after a join.
2957 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2959 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002960 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002962 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002963 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002964 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002965 dev_kfree_skb(wl->probereq);
2966 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2967 ieoffset = offsetof(struct ieee80211_mgmt,
2968 u.probe_req.variable);
2969 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002970
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002971 /* enable the connection monitoring feature */
2972 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002974 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002975
2976 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002977 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2978 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002979 enum wl1271_cmd_ps_mode mode;
2980
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002981 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002982 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002983 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002984 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002986 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002988 } else {
2989 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002990 bool was_assoc =
2991 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2992 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002993 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002994 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002995
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002996 /* free probe-request template */
2997 dev_kfree_skb(wl->probereq);
2998 wl->probereq = NULL;
2999
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003000 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003001 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003002
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003003 /* revert back to minimum rates for the current band */
3004 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003005 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003006 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003007 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003008 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003009
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003010 /* disable connection monitor features */
3011 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003012
3013 /* Disable the keep-alive feature */
3014 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003015 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003016 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003017
3018 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003019 if (was_assoc) {
3020 wl1271_unjoin(wl);
3021 wl1271_dummy_join(wl);
3022 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003023 }
3024 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003025
Arik Nemtsove78a2872010-10-16 19:07:21 +02003026 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3027 if (ret < 0)
3028 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003029
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003030 if (changed & BSS_CHANGED_ARP_FILTER) {
3031 __be32 addr = bss_conf->arp_addr_list[0];
3032 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3033
Eliad Pellerc5312772010-12-09 11:31:27 +02003034 if (bss_conf->arp_addr_cnt == 1 &&
3035 bss_conf->arp_filter_enabled) {
3036 /*
3037 * The template should have been configured only upon
3038 * association. however, it seems that the correct ip
3039 * isn't being set (when sending), so we have to
3040 * reconfigure the template upon every ip change.
3041 */
3042 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3043 if (ret < 0) {
3044 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003045 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003046 }
3047
3048 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003049 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003050 addr);
3051 } else
3052 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003053
3054 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003055 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003056 }
3057
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003058 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003059 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003060 if (ret < 0) {
3061 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003062 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003063 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003064 }
3065
Arik Nemtsove78a2872010-10-16 19:07:21 +02003066out:
3067 return;
3068}
3069
3070static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3071 struct ieee80211_vif *vif,
3072 struct ieee80211_bss_conf *bss_conf,
3073 u32 changed)
3074{
3075 struct wl1271 *wl = hw->priv;
3076 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3077 int ret;
3078
3079 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3080 (int)changed);
3081
3082 mutex_lock(&wl->mutex);
3083
3084 if (unlikely(wl->state == WL1271_STATE_OFF))
3085 goto out;
3086
Ido Yariva6208652011-03-01 15:14:41 +02003087 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003088 if (ret < 0)
3089 goto out;
3090
3091 if (is_ap)
3092 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3093 else
3094 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3095
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003096 wl1271_ps_elp_sleep(wl);
3097
3098out:
3099 mutex_unlock(&wl->mutex);
3100}
3101
Kalle Valoc6999d82010-02-18 13:25:41 +02003102static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3103 const struct ieee80211_tx_queue_params *params)
3104{
3105 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003106 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003107 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003108
3109 mutex_lock(&wl->mutex);
3110
3111 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3112
Kalle Valo4695dc92010-03-18 12:26:38 +02003113 if (params->uapsd)
3114 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3115 else
3116 ps_scheme = CONF_PS_SCHEME_LEGACY;
3117
Arik Nemtsov488fc542010-10-16 20:33:45 +02003118 if (wl->state == WL1271_STATE_OFF) {
3119 /*
3120 * If the state is off, the parameters will be recorded and
3121 * configured on init. This happens in AP-mode.
3122 */
3123 struct conf_tx_ac_category *conf_ac =
3124 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3125 struct conf_tx_tid *conf_tid =
3126 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3127
3128 conf_ac->ac = wl1271_tx_get_queue(queue);
3129 conf_ac->cw_min = (u8)params->cw_min;
3130 conf_ac->cw_max = params->cw_max;
3131 conf_ac->aifsn = params->aifs;
3132 conf_ac->tx_op_limit = params->txop << 5;
3133
3134 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3135 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3136 conf_tid->tsid = wl1271_tx_get_queue(queue);
3137 conf_tid->ps_scheme = ps_scheme;
3138 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3139 conf_tid->apsd_conf[0] = 0;
3140 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003141 goto out;
3142 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003143
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003144 ret = wl1271_ps_elp_wakeup(wl);
3145 if (ret < 0)
3146 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003147
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003148 /*
3149 * the txop is confed in units of 32us by the mac80211,
3150 * we need us
3151 */
3152 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3153 params->cw_min, params->cw_max,
3154 params->aifs, params->txop << 5);
3155 if (ret < 0)
3156 goto out_sleep;
3157
3158 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3159 CONF_CHANNEL_TYPE_EDCF,
3160 wl1271_tx_get_queue(queue),
3161 ps_scheme, CONF_ACK_POLICY_LEGACY,
3162 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003163
3164out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003165 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003166
3167out:
3168 mutex_unlock(&wl->mutex);
3169
3170 return ret;
3171}
3172
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003173static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3174{
3175
3176 struct wl1271 *wl = hw->priv;
3177 u64 mactime = ULLONG_MAX;
3178 int ret;
3179
3180 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3181
3182 mutex_lock(&wl->mutex);
3183
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003184 if (unlikely(wl->state == WL1271_STATE_OFF))
3185 goto out;
3186
Ido Yariva6208652011-03-01 15:14:41 +02003187 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003188 if (ret < 0)
3189 goto out;
3190
3191 ret = wl1271_acx_tsf_info(wl, &mactime);
3192 if (ret < 0)
3193 goto out_sleep;
3194
3195out_sleep:
3196 wl1271_ps_elp_sleep(wl);
3197
3198out:
3199 mutex_unlock(&wl->mutex);
3200 return mactime;
3201}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003202
John W. Linvilleece550d2010-07-28 16:41:06 -04003203static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3204 struct survey_info *survey)
3205{
3206 struct wl1271 *wl = hw->priv;
3207 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003208
John W. Linvilleece550d2010-07-28 16:41:06 -04003209 if (idx != 0)
3210 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003211
John W. Linvilleece550d2010-07-28 16:41:06 -04003212 survey->channel = conf->channel;
3213 survey->filled = SURVEY_INFO_NOISE_DBM;
3214 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003215
John W. Linvilleece550d2010-07-28 16:41:06 -04003216 return 0;
3217}
3218
Arik Nemtsov409622e2011-02-23 00:22:29 +02003219static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003220 struct ieee80211_sta *sta,
3221 u8 *hlid)
3222{
3223 struct wl1271_station *wl_sta;
3224 int id;
3225
3226 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3227 if (id >= AP_MAX_STATIONS) {
3228 wl1271_warning("could not allocate HLID - too much stations");
3229 return -EBUSY;
3230 }
3231
3232 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003233 __set_bit(id, wl->ap_hlid_map);
3234 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3235 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003236 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003237 return 0;
3238}
3239
Arik Nemtsov409622e2011-02-23 00:22:29 +02003240static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003241{
3242 int id = hlid - WL1271_AP_STA_HLID_START;
3243
Arik Nemtsov409622e2011-02-23 00:22:29 +02003244 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3245 return;
3246
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003247 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003248 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003249 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003250 __clear_bit(hlid, &wl->ap_ps_map);
3251 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003252}
3253
3254static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3255 struct ieee80211_vif *vif,
3256 struct ieee80211_sta *sta)
3257{
3258 struct wl1271 *wl = hw->priv;
3259 int ret = 0;
3260 u8 hlid;
3261
3262 mutex_lock(&wl->mutex);
3263
3264 if (unlikely(wl->state == WL1271_STATE_OFF))
3265 goto out;
3266
3267 if (wl->bss_type != BSS_TYPE_AP_BSS)
3268 goto out;
3269
3270 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3271
Arik Nemtsov409622e2011-02-23 00:22:29 +02003272 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003273 if (ret < 0)
3274 goto out;
3275
Ido Yariva6208652011-03-01 15:14:41 +02003276 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003277 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003278 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003279
3280 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3281 if (ret < 0)
3282 goto out_sleep;
3283
3284out_sleep:
3285 wl1271_ps_elp_sleep(wl);
3286
Arik Nemtsov409622e2011-02-23 00:22:29 +02003287out_free_sta:
3288 if (ret < 0)
3289 wl1271_free_sta(wl, hlid);
3290
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003291out:
3292 mutex_unlock(&wl->mutex);
3293 return ret;
3294}
3295
3296static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3297 struct ieee80211_vif *vif,
3298 struct ieee80211_sta *sta)
3299{
3300 struct wl1271 *wl = hw->priv;
3301 struct wl1271_station *wl_sta;
3302 int ret = 0, id;
3303
3304 mutex_lock(&wl->mutex);
3305
3306 if (unlikely(wl->state == WL1271_STATE_OFF))
3307 goto out;
3308
3309 if (wl->bss_type != BSS_TYPE_AP_BSS)
3310 goto out;
3311
3312 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3313
3314 wl_sta = (struct wl1271_station *)sta->drv_priv;
3315 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3316 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3317 goto out;
3318
Ido Yariva6208652011-03-01 15:14:41 +02003319 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003320 if (ret < 0)
3321 goto out;
3322
3323 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3324 if (ret < 0)
3325 goto out_sleep;
3326
Arik Nemtsov409622e2011-02-23 00:22:29 +02003327 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003328
3329out_sleep:
3330 wl1271_ps_elp_sleep(wl);
3331
3332out:
3333 mutex_unlock(&wl->mutex);
3334 return ret;
3335}
3336
Luciano Coelho4623ec72011-03-21 19:26:41 +02003337static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3338 struct ieee80211_vif *vif,
3339 enum ieee80211_ampdu_mlme_action action,
3340 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3341 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003342{
3343 struct wl1271 *wl = hw->priv;
3344 int ret;
3345
3346 mutex_lock(&wl->mutex);
3347
3348 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3349 ret = -EAGAIN;
3350 goto out;
3351 }
3352
Ido Yariva6208652011-03-01 15:14:41 +02003353 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003354 if (ret < 0)
3355 goto out;
3356
3357 switch (action) {
3358 case IEEE80211_AMPDU_RX_START:
3359 if (wl->ba_support) {
3360 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3361 true);
3362 if (!ret)
3363 wl->ba_rx_bitmap |= BIT(tid);
3364 } else {
3365 ret = -ENOTSUPP;
3366 }
3367 break;
3368
3369 case IEEE80211_AMPDU_RX_STOP:
3370 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3371 if (!ret)
3372 wl->ba_rx_bitmap &= ~BIT(tid);
3373 break;
3374
3375 /*
3376 * The BA initiator session management in FW independently.
3377 * Falling break here on purpose for all TX APDU commands.
3378 */
3379 case IEEE80211_AMPDU_TX_START:
3380 case IEEE80211_AMPDU_TX_STOP:
3381 case IEEE80211_AMPDU_TX_OPERATIONAL:
3382 ret = -EINVAL;
3383 break;
3384
3385 default:
3386 wl1271_error("Incorrect ampdu action id=%x\n", action);
3387 ret = -EINVAL;
3388 }
3389
3390 wl1271_ps_elp_sleep(wl);
3391
3392out:
3393 mutex_unlock(&wl->mutex);
3394
3395 return ret;
3396}
3397
Arik Nemtsov33437892011-04-26 23:35:39 +03003398static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3399{
3400 struct wl1271 *wl = hw->priv;
3401 bool ret = false;
3402
3403 mutex_lock(&wl->mutex);
3404
3405 if (unlikely(wl->state == WL1271_STATE_OFF))
3406 goto out;
3407
3408 /* packets are considered pending if in the TX queue or the FW */
3409 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3410
3411 /* the above is appropriate for STA mode for PS purposes */
3412 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3413
3414out:
3415 mutex_unlock(&wl->mutex);
3416
3417 return ret;
3418}
3419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003420/* can't be const, mac80211 writes to this */
3421static struct ieee80211_rate wl1271_rates[] = {
3422 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003423 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3424 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003425 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003426 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3427 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3429 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003430 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3431 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003432 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3433 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003434 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3435 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003436 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3437 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003438 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3439 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003441 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3442 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003443 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003444 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3445 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003447 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3448 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003450 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3451 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003452 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003453 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3454 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003455 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003456 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3457 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003458 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003459 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3460 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461};
3462
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003463/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003464static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003465 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003466 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003467 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3468 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3469 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003470 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003471 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3472 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3473 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003474 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003475 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3476 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3477 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003478 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003479};
3480
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003481/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003482static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003483 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003484 7, /* CONF_HW_RXTX_RATE_MCS7 */
3485 6, /* CONF_HW_RXTX_RATE_MCS6 */
3486 5, /* CONF_HW_RXTX_RATE_MCS5 */
3487 4, /* CONF_HW_RXTX_RATE_MCS4 */
3488 3, /* CONF_HW_RXTX_RATE_MCS3 */
3489 2, /* CONF_HW_RXTX_RATE_MCS2 */
3490 1, /* CONF_HW_RXTX_RATE_MCS1 */
3491 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003492
3493 11, /* CONF_HW_RXTX_RATE_54 */
3494 10, /* CONF_HW_RXTX_RATE_48 */
3495 9, /* CONF_HW_RXTX_RATE_36 */
3496 8, /* CONF_HW_RXTX_RATE_24 */
3497
3498 /* TI-specific rate */
3499 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3500
3501 7, /* CONF_HW_RXTX_RATE_18 */
3502 6, /* CONF_HW_RXTX_RATE_12 */
3503 3, /* CONF_HW_RXTX_RATE_11 */
3504 5, /* CONF_HW_RXTX_RATE_9 */
3505 4, /* CONF_HW_RXTX_RATE_6 */
3506 2, /* CONF_HW_RXTX_RATE_5_5 */
3507 1, /* CONF_HW_RXTX_RATE_2 */
3508 0 /* CONF_HW_RXTX_RATE_1 */
3509};
3510
Shahar Levie8b03a22010-10-13 16:09:39 +02003511/* 11n STA capabilities */
3512#define HW_RX_HIGHEST_RATE 72
3513
Shahar Levi00d20102010-11-08 11:20:10 +00003514#ifdef CONFIG_WL12XX_HT
3515#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003516 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3517 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003518 .ht_supported = true, \
3519 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3520 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3521 .mcs = { \
3522 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3523 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3524 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3525 }, \
3526}
Shahar Levi18357852010-10-13 16:09:41 +02003527#else
Shahar Levi00d20102010-11-08 11:20:10 +00003528#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003529 .ht_supported = false, \
3530}
3531#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003532
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003533/* can't be const, mac80211 writes to this */
3534static struct ieee80211_supported_band wl1271_band_2ghz = {
3535 .channels = wl1271_channels,
3536 .n_channels = ARRAY_SIZE(wl1271_channels),
3537 .bitrates = wl1271_rates,
3538 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003539 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540};
3541
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003542/* 5 GHz data rates for WL1273 */
3543static struct ieee80211_rate wl1271_rates_5ghz[] = {
3544 { .bitrate = 60,
3545 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3546 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3547 { .bitrate = 90,
3548 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3549 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3550 { .bitrate = 120,
3551 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3552 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3553 { .bitrate = 180,
3554 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3555 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3556 { .bitrate = 240,
3557 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3558 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3559 { .bitrate = 360,
3560 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3561 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3562 { .bitrate = 480,
3563 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3564 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3565 { .bitrate = 540,
3566 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3567 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3568};
3569
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003570/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003571static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003572 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003573 { .hw_value = 8, .center_freq = 5040},
3574 { .hw_value = 9, .center_freq = 5045},
3575 { .hw_value = 11, .center_freq = 5055},
3576 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003577 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003578 { .hw_value = 34, .center_freq = 5170},
3579 { .hw_value = 36, .center_freq = 5180},
3580 { .hw_value = 38, .center_freq = 5190},
3581 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003582 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003583 { .hw_value = 44, .center_freq = 5220},
3584 { .hw_value = 46, .center_freq = 5230},
3585 { .hw_value = 48, .center_freq = 5240},
3586 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003587 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003588 { .hw_value = 60, .center_freq = 5300},
3589 { .hw_value = 64, .center_freq = 5320},
3590 { .hw_value = 100, .center_freq = 5500},
3591 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003592 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003593 { .hw_value = 112, .center_freq = 5560},
3594 { .hw_value = 116, .center_freq = 5580},
3595 { .hw_value = 120, .center_freq = 5600},
3596 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003597 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003598 { .hw_value = 132, .center_freq = 5660},
3599 { .hw_value = 136, .center_freq = 5680},
3600 { .hw_value = 140, .center_freq = 5700},
3601 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003602 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003603 { .hw_value = 157, .center_freq = 5785},
3604 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003605 { .hw_value = 165, .center_freq = 5825},
3606};
3607
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003608/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003609static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003610 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003611 7, /* CONF_HW_RXTX_RATE_MCS7 */
3612 6, /* CONF_HW_RXTX_RATE_MCS6 */
3613 5, /* CONF_HW_RXTX_RATE_MCS5 */
3614 4, /* CONF_HW_RXTX_RATE_MCS4 */
3615 3, /* CONF_HW_RXTX_RATE_MCS3 */
3616 2, /* CONF_HW_RXTX_RATE_MCS2 */
3617 1, /* CONF_HW_RXTX_RATE_MCS1 */
3618 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003619
3620 7, /* CONF_HW_RXTX_RATE_54 */
3621 6, /* CONF_HW_RXTX_RATE_48 */
3622 5, /* CONF_HW_RXTX_RATE_36 */
3623 4, /* CONF_HW_RXTX_RATE_24 */
3624
3625 /* TI-specific rate */
3626 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3627
3628 3, /* CONF_HW_RXTX_RATE_18 */
3629 2, /* CONF_HW_RXTX_RATE_12 */
3630 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3631 1, /* CONF_HW_RXTX_RATE_9 */
3632 0, /* CONF_HW_RXTX_RATE_6 */
3633 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3634 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3635 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3636};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003637
3638static struct ieee80211_supported_band wl1271_band_5ghz = {
3639 .channels = wl1271_channels_5ghz,
3640 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3641 .bitrates = wl1271_rates_5ghz,
3642 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003643 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003644};
3645
Tobias Klausera0ea9492010-05-20 10:38:11 +02003646static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003647 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3648 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3649};
3650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003651static const struct ieee80211_ops wl1271_ops = {
3652 .start = wl1271_op_start,
3653 .stop = wl1271_op_stop,
3654 .add_interface = wl1271_op_add_interface,
3655 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003656#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003657 .suspend = wl1271_op_suspend,
3658 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003659#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003660 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003661 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003662 .configure_filter = wl1271_op_configure_filter,
3663 .tx = wl1271_op_tx,
3664 .set_key = wl1271_op_set_key,
3665 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003666 .sched_scan_start = wl1271_op_sched_scan_start,
3667 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003668 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003669 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003670 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003671 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003672 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003673 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003674 .sta_add = wl1271_op_sta_add,
3675 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003676 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003677 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003678 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003679};
3680
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003681
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003682u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003683{
3684 u8 idx;
3685
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003686 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003687
3688 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3689 wl1271_error("Illegal RX rate from HW: %d", rate);
3690 return 0;
3691 }
3692
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003693 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003694 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3695 wl1271_error("Unsupported RX rate from HW: %d", rate);
3696 return 0;
3697 }
3698
3699 return idx;
3700}
3701
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003702static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3703 struct device_attribute *attr,
3704 char *buf)
3705{
3706 struct wl1271 *wl = dev_get_drvdata(dev);
3707 ssize_t len;
3708
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003709 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003710
3711 mutex_lock(&wl->mutex);
3712 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3713 wl->sg_enabled);
3714 mutex_unlock(&wl->mutex);
3715
3716 return len;
3717
3718}
3719
3720static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3721 struct device_attribute *attr,
3722 const char *buf, size_t count)
3723{
3724 struct wl1271 *wl = dev_get_drvdata(dev);
3725 unsigned long res;
3726 int ret;
3727
Luciano Coelho6277ed62011-04-01 17:49:54 +03003728 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003729 if (ret < 0) {
3730 wl1271_warning("incorrect value written to bt_coex_mode");
3731 return count;
3732 }
3733
3734 mutex_lock(&wl->mutex);
3735
3736 res = !!res;
3737
3738 if (res == wl->sg_enabled)
3739 goto out;
3740
3741 wl->sg_enabled = res;
3742
3743 if (wl->state == WL1271_STATE_OFF)
3744 goto out;
3745
Ido Yariva6208652011-03-01 15:14:41 +02003746 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003747 if (ret < 0)
3748 goto out;
3749
3750 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3751 wl1271_ps_elp_sleep(wl);
3752
3753 out:
3754 mutex_unlock(&wl->mutex);
3755 return count;
3756}
3757
3758static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3759 wl1271_sysfs_show_bt_coex_state,
3760 wl1271_sysfs_store_bt_coex_state);
3761
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003762static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3763 struct device_attribute *attr,
3764 char *buf)
3765{
3766 struct wl1271 *wl = dev_get_drvdata(dev);
3767 ssize_t len;
3768
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003769 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003770
3771 mutex_lock(&wl->mutex);
3772 if (wl->hw_pg_ver >= 0)
3773 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3774 else
3775 len = snprintf(buf, len, "n/a\n");
3776 mutex_unlock(&wl->mutex);
3777
3778 return len;
3779}
3780
3781static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3782 wl1271_sysfs_show_hw_pg_ver, NULL);
3783
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003784int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003785{
3786 int ret;
3787
3788 if (wl->mac80211_registered)
3789 return 0;
3790
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003791 ret = wl1271_fetch_nvs(wl);
3792 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003793 /* NOTE: The wl->nvs->nvs element must be first, in
3794 * order to simplify the casting, we assume it is at
3795 * the beginning of the wl->nvs structure.
3796 */
3797 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003798
3799 wl->mac_addr[0] = nvs_ptr[11];
3800 wl->mac_addr[1] = nvs_ptr[10];
3801 wl->mac_addr[2] = nvs_ptr[6];
3802 wl->mac_addr[3] = nvs_ptr[5];
3803 wl->mac_addr[4] = nvs_ptr[4];
3804 wl->mac_addr[5] = nvs_ptr[3];
3805 }
3806
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003807 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3808
3809 ret = ieee80211_register_hw(wl->hw);
3810 if (ret < 0) {
3811 wl1271_error("unable to register mac80211 hw: %d", ret);
3812 return ret;
3813 }
3814
3815 wl->mac80211_registered = true;
3816
Eliad Pellerd60080a2010-11-24 12:53:16 +02003817 wl1271_debugfs_init(wl);
3818
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003819 register_netdevice_notifier(&wl1271_dev_notifier);
3820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003821 wl1271_notice("loaded");
3822
3823 return 0;
3824}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003825EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003826
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003827void wl1271_unregister_hw(struct wl1271 *wl)
3828{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003829 if (wl->state == WL1271_STATE_PLT)
3830 __wl1271_plt_stop(wl);
3831
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003832 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003833 ieee80211_unregister_hw(wl->hw);
3834 wl->mac80211_registered = false;
3835
3836}
3837EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3838
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003839int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003840{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003841 static const u32 cipher_suites[] = {
3842 WLAN_CIPHER_SUITE_WEP40,
3843 WLAN_CIPHER_SUITE_WEP104,
3844 WLAN_CIPHER_SUITE_TKIP,
3845 WLAN_CIPHER_SUITE_CCMP,
3846 WL1271_CIPHER_SUITE_GEM,
3847 };
3848
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003849 /* The tx descriptor buffer and the TKIP space. */
3850 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3851 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003852
3853 /* unit us */
3854 /* FIXME: find a proper value */
3855 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003856 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003857
3858 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003859 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003860 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003861 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003862 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003863 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003864 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003865 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003866 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003867 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003868
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003869 wl->hw->wiphy->cipher_suites = cipher_suites;
3870 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3871
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003872 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003873 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003874 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003875 /*
3876 * Maximum length of elements in scanning probe request templates
3877 * should be the maximum length possible for a template, without
3878 * the IEEE80211 header of the template
3879 */
3880 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3881 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003882
Luciano Coelho4a31c112011-03-21 23:16:14 +02003883 /* make sure all our channels fit in the scanned_ch bitmask */
3884 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3885 ARRAY_SIZE(wl1271_channels_5ghz) >
3886 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003887 /*
3888 * We keep local copies of the band structs because we need to
3889 * modify them on a per-device basis.
3890 */
3891 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3892 sizeof(wl1271_band_2ghz));
3893 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3894 sizeof(wl1271_band_5ghz));
3895
3896 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3897 &wl->bands[IEEE80211_BAND_2GHZ];
3898 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3899 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003900
Kalle Valo12bd8942010-03-18 12:26:33 +02003901 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003902 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003903
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003904 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3905
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003906 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003907
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003908 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3909
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003910 wl->hw->max_rx_aggregation_subframes = 8;
3911
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003912 return 0;
3913}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003914EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003915
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003916#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003917
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003918struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003919{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003920 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003921 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003922 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003923 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003924 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003925
3926 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3927 if (!hw) {
3928 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003929 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003930 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003931 }
3932
Julia Lawall929ebd32010-05-15 23:16:39 +02003933 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003934 if (!plat_dev) {
3935 wl1271_error("could not allocate platform_device");
3936 ret = -ENOMEM;
3937 goto err_plat_alloc;
3938 }
3939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003940 wl = hw->priv;
3941 memset(wl, 0, sizeof(*wl));
3942
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003943 INIT_LIST_HEAD(&wl->list);
3944
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003945 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003946 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003947
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003948 for (i = 0; i < NUM_TX_QUEUES; i++)
3949 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003950
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003951 for (i = 0; i < NUM_TX_QUEUES; i++)
3952 for (j = 0; j < AP_MAX_LINKS; j++)
3953 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3954
Ido Yariva6208652011-03-01 15:14:41 +02003955 skb_queue_head_init(&wl->deferred_rx_queue);
3956 skb_queue_head_init(&wl->deferred_tx_queue);
3957
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003958 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003959 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003960 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003961 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3962 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3963 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003964 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003965 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003966 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003967 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003968 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3969 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003970 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003972 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003973 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003974 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003975 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003976 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003977 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003978 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003979 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003980 wl->bss_type = MAX_BSS_TYPE;
3981 wl->set_bss_type = MAX_BSS_TYPE;
3982 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003983 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003984 wl->ap_ps_map = 0;
3985 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003986 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003987 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003988 wl->sched_scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003989
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003990 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003991 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003992 wl->tx_frames[i] = NULL;
3993
3994 spin_lock_init(&wl->wl_lock);
3995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003996 wl->state = WL1271_STATE_OFF;
3997 mutex_init(&wl->mutex);
3998
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003999 /* Apply default driver configuration. */
4000 wl1271_conf_init(wl);
4001
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004002 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4003 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4004 if (!wl->aggr_buf) {
4005 ret = -ENOMEM;
4006 goto err_hw;
4007 }
4008
Ido Yariv990f5de2011-03-31 10:06:59 +02004009 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4010 if (!wl->dummy_packet) {
4011 ret = -ENOMEM;
4012 goto err_aggr;
4013 }
4014
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004015 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004016 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004017 if (ret) {
4018 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004019 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004020 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004021 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004022
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004023 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004024 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004025 if (ret < 0) {
4026 wl1271_error("failed to create sysfs file bt_coex_state");
4027 goto err_platform;
4028 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004029
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004030 /* Create sysfs file to get HW PG version */
4031 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4032 if (ret < 0) {
4033 wl1271_error("failed to create sysfs file hw_pg_ver");
4034 goto err_bt_coex_state;
4035 }
4036
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004037 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004038
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004039err_bt_coex_state:
4040 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4041
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004042err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004043 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004044
Ido Yariv990f5de2011-03-31 10:06:59 +02004045err_dummy_packet:
4046 dev_kfree_skb(wl->dummy_packet);
4047
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004048err_aggr:
4049 free_pages((unsigned long)wl->aggr_buf, order);
4050
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004051err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004052 wl1271_debugfs_exit(wl);
4053 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004054
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004055err_plat_alloc:
4056 ieee80211_free_hw(hw);
4057
4058err_hw_alloc:
4059
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004060 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004061}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004062EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004063
4064int wl1271_free_hw(struct wl1271 *wl)
4065{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004066 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004067 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004068 free_pages((unsigned long)wl->aggr_buf,
4069 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004070 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004071
4072 wl1271_debugfs_exit(wl);
4073
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004074 vfree(wl->fw);
4075 wl->fw = NULL;
4076 kfree(wl->nvs);
4077 wl->nvs = NULL;
4078
4079 kfree(wl->fw_status);
4080 kfree(wl->tx_res_if);
4081
4082 ieee80211_free_hw(wl->hw);
4083
4084 return 0;
4085}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004086EXPORT_SYMBOL_GPL(wl1271_free_hw);
4087
Guy Eilam491bbd62011-01-12 10:33:29 +01004088u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004089EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004090module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004091MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4092
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004093MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004094MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004095MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");