blob: 00ee01e7d4a40538f8b78085148d225f893ccc54 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300314 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300315 .num_probe_reqs = 2,
316 .rssi_threshold = -90,
317 .snr_threshold = 0,
318 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200319 .rf = {
320 .tx_per_channel_power_compensation_2 = {
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 },
323 .tx_per_channel_power_compensation_5 = {
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 },
328 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100329 .ht = {
330 .tx_ba_win_size = 64,
331 .inactivity_timeout = 10000,
332 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200333 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200334 .num_stations = 1,
335 .ssid_profiles = 1,
336 .rx_block_num = 70,
337 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300338 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200339 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200340 .min_req_rx_blocks = 22,
341 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200342 },
343 .mem_wl128x = {
344 .num_stations = 1,
345 .ssid_profiles = 1,
346 .rx_block_num = 40,
347 .tx_min_block_num = 40,
348 .dynamic_memory = 1,
349 .min_req_tx_blocks = 45,
350 .min_req_rx_blocks = 22,
351 .tx_min = 27,
352 },
Shahar Leviff868432011-04-11 15:41:46 +0300353 .fm_coex = {
354 .enable = true,
355 .swallow_period = 5,
356 .n_divider_fref_set_1 = 0xff, /* default */
357 .n_divider_fref_set_2 = 12,
358 .m_divider_fref_set_1 = 148,
359 .m_divider_fref_set_2 = 0xffff, /* default */
360 .coex_pll_stabilization_time = 0xffffffff, /* default */
361 .ldo_stabilization_time = 0xffff, /* default */
362 .fm_disturbed_band_margin = 0xff, /* default */
363 .swallow_clk_diff = 0xff, /* default */
364 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300365 .rx_streaming = {
366 .duration = 150,
367 .queues = 0x1,
368 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300369 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300370 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300371 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300372};
373
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300374static void __wl1271_op_remove_interface(struct wl1271 *wl,
375 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200376static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200377
378
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200379static void wl1271_device_release(struct device *dev)
380{
381
382}
383
384static struct platform_device wl1271_device = {
385 .name = "wl1271",
386 .id = -1,
387
388 /* device model insists to have a release function */
389 .dev = {
390 .release = wl1271_device_release,
391 },
392};
393
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200394static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300395static LIST_HEAD(wl_list);
396
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300397static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
398 void *arg)
399{
400 struct net_device *dev = arg;
401 struct wireless_dev *wdev;
402 struct wiphy *wiphy;
403 struct ieee80211_hw *hw;
404 struct wl1271 *wl;
405 struct wl1271 *wl_temp;
406 int ret = 0;
407
408 /* Check that this notification is for us. */
409 if (what != NETDEV_CHANGE)
410 return NOTIFY_DONE;
411
412 wdev = dev->ieee80211_ptr;
413 if (wdev == NULL)
414 return NOTIFY_DONE;
415
416 wiphy = wdev->wiphy;
417 if (wiphy == NULL)
418 return NOTIFY_DONE;
419
420 hw = wiphy_priv(wiphy);
421 if (hw == NULL)
422 return NOTIFY_DONE;
423
424 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200425 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300426 list_for_each_entry(wl, &wl_list, list) {
427 if (wl == wl_temp)
428 break;
429 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200430 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300431 if (wl != wl_temp)
432 return NOTIFY_DONE;
433
434 mutex_lock(&wl->mutex);
435
436 if (wl->state == WL1271_STATE_OFF)
437 goto out;
438
439 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
440 goto out;
441
Ido Yariva6208652011-03-01 15:14:41 +0200442 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300443 if (ret < 0)
444 goto out;
445
446 if ((dev->operstate == IF_OPER_UP) &&
447 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
448 wl1271_cmd_set_sta_state(wl);
449 wl1271_info("Association completed.");
450 }
451
452 wl1271_ps_elp_sleep(wl);
453
454out:
455 mutex_unlock(&wl->mutex);
456
457 return NOTIFY_OK;
458}
459
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100460static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200461 struct regulatory_request *request)
462{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100463 struct ieee80211_supported_band *band;
464 struct ieee80211_channel *ch;
465 int i;
466
467 band = wiphy->bands[IEEE80211_BAND_5GHZ];
468 for (i = 0; i < band->n_channels; i++) {
469 ch = &band->channels[i];
470 if (ch->flags & IEEE80211_CHAN_DISABLED)
471 continue;
472
473 if (ch->flags & IEEE80211_CHAN_RADAR)
474 ch->flags |= IEEE80211_CHAN_NO_IBSS |
475 IEEE80211_CHAN_PASSIVE_SCAN;
476
477 }
478
479 return 0;
480}
481
Eliad Peller77ddaa12011-05-15 11:10:29 +0300482static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
483{
484 int ret = 0;
485
486 /* we should hold wl->mutex */
487 ret = wl1271_acx_ps_rx_streaming(wl, enable);
488 if (ret < 0)
489 goto out;
490
491 if (enable)
492 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
493 else
494 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
495out:
496 return ret;
497}
498
499/*
500 * this function is being called when the rx_streaming interval
501 * has beed changed or rx_streaming should be disabled
502 */
503int wl1271_recalc_rx_streaming(struct wl1271 *wl)
504{
505 int ret = 0;
506 int period = wl->conf.rx_streaming.interval;
507
508 /* don't reconfigure if rx_streaming is disabled */
509 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
510 goto out;
511
512 /* reconfigure/disable according to new streaming_period */
513 if (period &&
514 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
515 (wl->conf.rx_streaming.always ||
516 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
517 ret = wl1271_set_rx_streaming(wl, true);
518 else {
519 ret = wl1271_set_rx_streaming(wl, false);
520 /* don't cancel_work_sync since we might deadlock */
521 del_timer_sync(&wl->rx_streaming_timer);
522 }
523out:
524 return ret;
525}
526
527static void wl1271_rx_streaming_enable_work(struct work_struct *work)
528{
529 int ret;
530 struct wl1271 *wl =
531 container_of(work, struct wl1271, rx_streaming_enable_work);
532
533 mutex_lock(&wl->mutex);
534
535 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
536 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
537 (!wl->conf.rx_streaming.always &&
538 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
539 goto out;
540
541 if (!wl->conf.rx_streaming.interval)
542 goto out;
543
544 ret = wl1271_ps_elp_wakeup(wl);
545 if (ret < 0)
546 goto out;
547
548 ret = wl1271_set_rx_streaming(wl, true);
549 if (ret < 0)
550 goto out_sleep;
551
552 /* stop it after some time of inactivity */
553 mod_timer(&wl->rx_streaming_timer,
554 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
555
556out_sleep:
557 wl1271_ps_elp_sleep(wl);
558out:
559 mutex_unlock(&wl->mutex);
560}
561
562static void wl1271_rx_streaming_disable_work(struct work_struct *work)
563{
564 int ret;
565 struct wl1271 *wl =
566 container_of(work, struct wl1271, rx_streaming_disable_work);
567
568 mutex_lock(&wl->mutex);
569
570 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
571 goto out;
572
573 ret = wl1271_ps_elp_wakeup(wl);
574 if (ret < 0)
575 goto out;
576
577 ret = wl1271_set_rx_streaming(wl, false);
578 if (ret)
579 goto out_sleep;
580
581out_sleep:
582 wl1271_ps_elp_sleep(wl);
583out:
584 mutex_unlock(&wl->mutex);
585}
586
587static void wl1271_rx_streaming_timer(unsigned long data)
588{
589 struct wl1271 *wl = (struct wl1271 *)data;
590 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
591}
592
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300593static void wl1271_conf_init(struct wl1271 *wl)
594{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300595
596 /*
597 * This function applies the default configuration to the driver. This
598 * function is invoked upon driver load (spi probe.)
599 *
600 * The configuration is stored in a run-time structure in order to
601 * facilitate for run-time adjustment of any of the parameters. Making
602 * changes to the configuration structure will apply the new values on
603 * the next interface up (wl1271_op_start.)
604 */
605
606 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300607 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300608}
609
610
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300611static int wl1271_plt_init(struct wl1271 *wl)
612{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200613 struct conf_tx_ac_category *conf_ac;
614 struct conf_tx_tid *conf_tid;
615 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300616
Shahar Levi49d750ca2011-03-06 16:32:09 +0200617 if (wl->chip.id == CHIP_ID_1283_PG20)
618 ret = wl128x_cmd_general_parms(wl);
619 else
620 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200621 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200622 return ret;
623
Shahar Levi49d750ca2011-03-06 16:32:09 +0200624 if (wl->chip.id == CHIP_ID_1283_PG20)
625 ret = wl128x_cmd_radio_parms(wl);
626 else
627 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200628 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200629 return ret;
630
Shahar Levi49d750ca2011-03-06 16:32:09 +0200631 if (wl->chip.id != CHIP_ID_1283_PG20) {
632 ret = wl1271_cmd_ext_radio_parms(wl);
633 if (ret < 0)
634 return ret;
635 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200636 if (ret < 0)
637 return ret;
638
Shahar Levi48a61472011-03-06 16:32:08 +0200639 /* Chip-specific initializations */
640 ret = wl1271_chip_specific_init(wl);
641 if (ret < 0)
642 return ret;
643
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200644 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200645 if (ret < 0)
646 return ret;
647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300648 ret = wl1271_acx_init_mem_config(wl);
649 if (ret < 0)
650 return ret;
651
Luciano Coelho12419cc2010-02-18 13:25:44 +0200652 /* PHY layer config */
653 ret = wl1271_init_phy_config(wl);
654 if (ret < 0)
655 goto out_free_memmap;
656
657 ret = wl1271_acx_dco_itrim_params(wl);
658 if (ret < 0)
659 goto out_free_memmap;
660
661 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200662 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200663 if (ret < 0)
664 goto out_free_memmap;
665
666 /* Bluetooth WLAN coexistence */
667 ret = wl1271_init_pta(wl);
668 if (ret < 0)
669 goto out_free_memmap;
670
Shahar Leviff868432011-04-11 15:41:46 +0300671 /* FM WLAN coexistence */
672 ret = wl1271_acx_fm_coex(wl);
673 if (ret < 0)
674 goto out_free_memmap;
675
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 /* Energy detection */
677 ret = wl1271_init_energy_detection(wl);
678 if (ret < 0)
679 goto out_free_memmap;
680
Gery Kahn1ec610e2011-02-01 03:03:08 -0600681 ret = wl1271_acx_sta_mem_cfg(wl);
682 if (ret < 0)
683 goto out_free_memmap;
684
Luciano Coelho12419cc2010-02-18 13:25:44 +0200685 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100686 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200687 if (ret < 0)
688 goto out_free_memmap;
689
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200690 /* Default TID/AC configuration */
691 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200692 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200693 conf_ac = &wl->conf.tx.ac_conf[i];
694 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
695 conf_ac->cw_max, conf_ac->aifsn,
696 conf_ac->tx_op_limit);
697 if (ret < 0)
698 goto out_free_memmap;
699
Luciano Coelho12419cc2010-02-18 13:25:44 +0200700 conf_tid = &wl->conf.tx.tid_conf[i];
701 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
702 conf_tid->channel_type,
703 conf_tid->tsid,
704 conf_tid->ps_scheme,
705 conf_tid->ack_policy,
706 conf_tid->apsd_conf[0],
707 conf_tid->apsd_conf[1]);
708 if (ret < 0)
709 goto out_free_memmap;
710 }
711
Luciano Coelho12419cc2010-02-18 13:25:44 +0200712 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200713 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300714 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715 goto out_free_memmap;
716
717 /* Configure for CAM power saving (ie. always active) */
718 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
719 if (ret < 0)
720 goto out_free_memmap;
721
722 /* configure PM */
723 ret = wl1271_acx_pm_config(wl);
724 if (ret < 0)
725 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726
727 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200728
729 out_free_memmap:
730 kfree(wl->target_mem_map);
731 wl->target_mem_map = NULL;
732
733 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300734}
735
Arik Nemtsovb622d992011-02-23 00:22:31 +0200736static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
737{
738 bool fw_ps;
739
740 /* only regulate station links */
741 if (hlid < WL1271_AP_STA_HLID_START)
742 return;
743
744 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
745
746 /*
747 * Wake up from high level PS if the STA is asleep with too little
748 * blocks in FW or if the STA is awake.
749 */
750 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
751 wl1271_ps_link_end(wl, hlid);
752
753 /* Start high-level PS if the STA is asleep with enough blocks in FW */
754 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
755 wl1271_ps_link_start(wl, hlid, true);
756}
757
758static void wl1271_irq_update_links_status(struct wl1271 *wl,
759 struct wl1271_fw_ap_status *status)
760{
761 u32 cur_fw_ps_map;
762 u8 hlid;
763
764 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
765 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
766 wl1271_debug(DEBUG_PSM,
767 "link ps prev 0x%x cur 0x%x changed 0x%x",
768 wl->ap_fw_ps_map, cur_fw_ps_map,
769 wl->ap_fw_ps_map ^ cur_fw_ps_map);
770
771 wl->ap_fw_ps_map = cur_fw_ps_map;
772 }
773
774 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
775 u8 cnt = status->tx_lnk_free_blks[hlid] -
776 wl->links[hlid].prev_freed_blks;
777
778 wl->links[hlid].prev_freed_blks =
779 status->tx_lnk_free_blks[hlid];
780 wl->links[hlid].allocated_blks -= cnt;
781
782 wl1271_irq_ps_regulate_link(wl, hlid,
783 wl->links[hlid].allocated_blks);
784 }
785}
786
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300787static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200788 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200790 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200791 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200792 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200793 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300794 int i;
795
Shahar Levi13b107d2011-03-06 16:32:12 +0200796 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200797 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
798 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200799 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200800 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
801 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200802 }
803
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300804 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
805 "drv_rx_counter = %d, tx_results_counter = %d)",
806 status->intr,
807 status->fw_rx_counter,
808 status->drv_rx_counter,
809 status->tx_results_counter);
810
811 /* update number of available TX blocks */
812 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
814 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300815
816 wl->tx_blocks_freed[i] =
817 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200818 }
819
Ido Yarivd2f4d472011-03-31 10:07:00 +0200820 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200821
Ido Yarivd2f4d472011-03-31 10:07:00 +0200822 if (wl->bss_type == BSS_TYPE_AP_BSS) {
823 /* Update num of allocated TX blocks per link and ps status */
824 wl1271_irq_update_links_status(wl, &full_status->ap);
825 wl->tx_blocks_available += freed_blocks;
826 } else {
827 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
828
829 /*
830 * The FW might change the total number of TX memblocks before
831 * we get a notification about blocks being released. Thus, the
832 * available blocks calculation might yield a temporary result
833 * which is lower than the actual available blocks. Keeping in
834 * mind that only blocks that were allocated can be moved from
835 * TX to RX, tx_blocks_available should never decrease here.
836 */
837 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
838 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300839 }
840
Ido Yariva5225502010-10-12 14:49:10 +0200841 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200842 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200843 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844
845 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200846 getnstimeofday(&ts);
847 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
848 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300849}
850
Ido Yariva6208652011-03-01 15:14:41 +0200851static void wl1271_flush_deferred_work(struct wl1271 *wl)
852{
853 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200854
Ido Yariva6208652011-03-01 15:14:41 +0200855 /* Pass all received frames to the network stack */
856 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
857 ieee80211_rx_ni(wl->hw, skb);
858
859 /* Return sent skbs to the network stack */
860 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
861 ieee80211_tx_status(wl->hw, skb);
862}
863
864static void wl1271_netstack_work(struct work_struct *work)
865{
866 struct wl1271 *wl =
867 container_of(work, struct wl1271, netstack_work);
868
869 do {
870 wl1271_flush_deferred_work(wl);
871 } while (skb_queue_len(&wl->deferred_rx_queue));
872}
873
874#define WL1271_IRQ_MAX_LOOPS 256
875
876irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300879 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200880 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200881 struct wl1271 *wl = (struct wl1271 *)cookie;
882 bool done = false;
883 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200884 unsigned long flags;
885
886 /* TX might be handled here, avoid redundant work */
887 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
888 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300889
Ido Yariv341b7cd2011-03-31 10:07:01 +0200890 /*
891 * In case edge triggered interrupt must be used, we cannot iterate
892 * more than once without introducing race conditions with the hardirq.
893 */
894 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
895 loopcount = 1;
896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 mutex_lock(&wl->mutex);
898
899 wl1271_debug(DEBUG_IRQ, "IRQ work");
900
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200901 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 goto out;
903
Ido Yariva6208652011-03-01 15:14:41 +0200904 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300905 if (ret < 0)
906 goto out;
907
Ido Yariva6208652011-03-01 15:14:41 +0200908 while (!done && loopcount--) {
909 /*
910 * In order to avoid a race with the hardirq, clear the flag
911 * before acknowledging the chip. Since the mutex is held,
912 * wl1271_ps_elp_wakeup cannot be called concurrently.
913 */
914 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
915 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200916
917 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200918 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200919 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200920 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200921 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200922 continue;
923 }
924
Eliad Pellerccc83b02010-10-27 14:09:57 +0200925 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
926 wl1271_error("watchdog interrupt received! "
927 "starting recovery.");
928 ieee80211_queue_work(wl->hw, &wl->recovery_work);
929
930 /* restarting the chip. ignore any other interrupt. */
931 goto out;
932 }
933
Ido Yariva6208652011-03-01 15:14:41 +0200934 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200935 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
936
Ido Yariv8aad2462011-03-01 15:14:38 +0200937 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200938
Ido Yariva5225502010-10-12 14:49:10 +0200939 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200941 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200942 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200943 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200944 /*
945 * In order to avoid starvation of the TX path,
946 * call the work function directly.
947 */
948 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200949 } else {
950 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200951 }
952
Ido Yariv8aad2462011-03-01 15:14:38 +0200953 /* check for tx results */
954 if (wl->fw_status->common.tx_results_counter !=
955 (wl->tx_results_count & 0xff))
956 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200957
958 /* Make sure the deferred queues don't get too long */
959 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
960 skb_queue_len(&wl->deferred_rx_queue);
961 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
962 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200963 }
964
965 if (intr & WL1271_ACX_INTR_EVENT_A) {
966 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
967 wl1271_event_handle(wl, 0);
968 }
969
970 if (intr & WL1271_ACX_INTR_EVENT_B) {
971 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
972 wl1271_event_handle(wl, 1);
973 }
974
975 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
976 wl1271_debug(DEBUG_IRQ,
977 "WL1271_ACX_INTR_INIT_COMPLETE");
978
979 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
980 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300981 }
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 wl1271_ps_elp_sleep(wl);
984
985out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 spin_lock_irqsave(&wl->wl_lock, flags);
987 /* In case TX was not handled here, queue TX work */
988 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
989 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
990 wl->tx_queue_count)
991 ieee80211_queue_work(wl->hw, &wl->tx_work);
992 spin_unlock_irqrestore(&wl->wl_lock, flags);
993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200995
996 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300997}
Ido Yariva6208652011-03-01 15:14:41 +0200998EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000static int wl1271_fetch_firmware(struct wl1271 *wl)
1001{
1002 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001003 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001004 int ret;
1005
Arik Nemtsov166d5042010-10-16 21:44:57 +02001006 switch (wl->bss_type) {
1007 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +02001008 if (wl->chip.id == CHIP_ID_1283_PG20)
1009 fw_name = WL128X_AP_FW_NAME;
1010 else
1011 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001012 break;
1013 case BSS_TYPE_IBSS:
1014 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +02001015 if (wl->chip.id == CHIP_ID_1283_PG20)
1016 fw_name = WL128X_FW_NAME;
1017 else
1018 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001019 break;
1020 default:
1021 wl1271_error("no compatible firmware for bss_type %d",
1022 wl->bss_type);
1023 return -EINVAL;
1024 }
1025
1026 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1027
1028 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001029
1030 if (ret < 0) {
1031 wl1271_error("could not get firmware: %d", ret);
1032 return ret;
1033 }
1034
1035 if (fw->size % 4) {
1036 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1037 fw->size);
1038 ret = -EILSEQ;
1039 goto out;
1040 }
1041
Arik Nemtsov166d5042010-10-16 21:44:57 +02001042 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001044 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 if (!wl->fw) {
1047 wl1271_error("could not allocate memory for the firmware");
1048 ret = -ENOMEM;
1049 goto out;
1050 }
1051
1052 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +02001053 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054 ret = 0;
1055
1056out:
1057 release_firmware(fw);
1058
1059 return ret;
1060}
1061
1062static int wl1271_fetch_nvs(struct wl1271 *wl)
1063{
1064 const struct firmware *fw;
1065 int ret;
1066
Shahar Levi5aa42342011-03-06 16:32:07 +02001067 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001068
1069 if (ret < 0) {
1070 wl1271_error("could not get nvs file: %d", ret);
1071 return ret;
1072 }
1073
Shahar Levibc765bf2011-03-06 16:32:10 +02001074 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075
1076 if (!wl->nvs) {
1077 wl1271_error("could not allocate memory for the nvs file");
1078 ret = -ENOMEM;
1079 goto out;
1080 }
1081
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001082 wl->nvs_len = fw->size;
1083
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001084out:
1085 release_firmware(fw);
1086
1087 return ret;
1088}
1089
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001090static void wl1271_recovery_work(struct work_struct *work)
1091{
1092 struct wl1271 *wl =
1093 container_of(work, struct wl1271, recovery_work);
1094
1095 mutex_lock(&wl->mutex);
1096
1097 if (wl->state != WL1271_STATE_ON)
1098 goto out;
1099
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001100 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1101 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001102
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001103 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1104 ieee80211_connection_loss(wl->vif);
1105
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001106 /* Prevent spurious TX during FW restart */
1107 ieee80211_stop_queues(wl->hw);
1108
Luciano Coelho33c2c062011-05-10 14:46:02 +03001109 if (wl->sched_scanning) {
1110 ieee80211_sched_scan_stopped(wl->hw);
1111 wl->sched_scanning = false;
1112 }
1113
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001114 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001115 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001116 ieee80211_restart_hw(wl->hw);
1117
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001118 /*
1119 * Its safe to enable TX now - the queues are stopped after a request
1120 * to restart the HW.
1121 */
1122 ieee80211_wake_queues(wl->hw);
1123
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001124out:
1125 mutex_unlock(&wl->mutex);
1126}
1127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001128static void wl1271_fw_wakeup(struct wl1271 *wl)
1129{
1130 u32 elp_reg;
1131
1132 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001133 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001134}
1135
1136static int wl1271_setup(struct wl1271 *wl)
1137{
1138 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1139 if (!wl->fw_status)
1140 return -ENOMEM;
1141
1142 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1143 if (!wl->tx_res_if) {
1144 kfree(wl->fw_status);
1145 return -ENOMEM;
1146 }
1147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001148 return 0;
1149}
1150
1151static int wl1271_chip_wakeup(struct wl1271 *wl)
1152{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001153 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001154 int ret = 0;
1155
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001156 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001157 ret = wl1271_power_on(wl);
1158 if (ret < 0)
1159 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001161 wl1271_io_reset(wl);
1162 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001163
1164 /* We don't need a real memory partition here, because we only want
1165 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001166 memset(&partition, 0, sizeof(partition));
1167 partition.reg.start = REGISTERS_BASE;
1168 partition.reg.size = REGISTERS_DOWN_SIZE;
1169 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170
1171 /* ELP module wake up */
1172 wl1271_fw_wakeup(wl);
1173
1174 /* whal_FwCtrl_BootSm() */
1175
1176 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001177 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001178
1179 /* 1. check if chip id is valid */
1180
1181 switch (wl->chip.id) {
1182 case CHIP_ID_1271_PG10:
1183 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1184 wl->chip.id);
1185
1186 ret = wl1271_setup(wl);
1187 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001188 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189 break;
1190 case CHIP_ID_1271_PG20:
1191 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1192 wl->chip.id);
1193
Shahar Levi0c005042011-06-12 10:34:43 +03001194 /*
1195 * 'end-of-transaction flag' and 'LPD mode flag'
1196 * should be set in wl127x AP mode only
1197 */
Shahar Levi564f5952011-04-04 10:20:39 +03001198 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001199 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1200 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001201
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001202 ret = wl1271_setup(wl);
1203 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001204 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001206 case CHIP_ID_1283_PG20:
1207 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1208 wl->chip.id);
1209
1210 ret = wl1271_setup(wl);
1211 if (ret < 0)
1212 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001213
Ido Yariv0da13da2011-03-31 10:06:58 +02001214 if (wl1271_set_block_size(wl))
1215 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001216 break;
1217 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001219 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001221 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001222 }
1223
Arik Nemtsov166d5042010-10-16 21:44:57 +02001224 /* Make sure the firmware type matches the BSS type */
1225 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226 ret = wl1271_fetch_firmware(wl);
1227 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001228 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001229 }
1230
1231 /* No NVS from netlink, try to get it from the filesystem */
1232 if (wl->nvs == NULL) {
1233 ret = wl1271_fetch_nvs(wl);
1234 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001235 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236 }
1237
1238out:
1239 return ret;
1240}
1241
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001242static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1243{
1244 unsigned int quirks = 0;
1245 unsigned int *fw_ver = wl->chip.fw_ver;
1246
1247 /* Only for wl127x */
1248 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1249 /* Check STA version */
1250 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1251 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1252 /* Check AP version */
1253 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1254 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1255 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1256
1257 return quirks;
1258}
1259
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001260int wl1271_plt_start(struct wl1271 *wl)
1261{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001262 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263 int ret;
1264
1265 mutex_lock(&wl->mutex);
1266
1267 wl1271_notice("power up");
1268
1269 if (wl->state != WL1271_STATE_OFF) {
1270 wl1271_error("cannot go into PLT state because not "
1271 "in off state: %d", wl->state);
1272 ret = -EBUSY;
1273 goto out;
1274 }
1275
Arik Nemtsov166d5042010-10-16 21:44:57 +02001276 wl->bss_type = BSS_TYPE_STA_BSS;
1277
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001278 while (retries) {
1279 retries--;
1280 ret = wl1271_chip_wakeup(wl);
1281 if (ret < 0)
1282 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001284 ret = wl1271_boot(wl);
1285 if (ret < 0)
1286 goto power_off;
1287
1288 ret = wl1271_plt_init(wl);
1289 if (ret < 0)
1290 goto irq_disable;
1291
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001292 wl->state = WL1271_STATE_PLT;
1293 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001294 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001295
1296 /* Check if any quirks are needed with older fw versions */
1297 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298 goto out;
1299
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001300irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001301 mutex_unlock(&wl->mutex);
1302 /* Unlocking the mutex in the middle of handling is
1303 inherently unsafe. In this case we deem it safe to do,
1304 because we need to let any possibly pending IRQ out of
1305 the system (and while we are WL1271_STATE_OFF the IRQ
1306 work function will not do anything.) Also, any other
1307 possible concurrent operations will fail due to the
1308 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001309 wl1271_disable_interrupts(wl);
1310 wl1271_flush_deferred_work(wl);
1311 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001312 mutex_lock(&wl->mutex);
1313power_off:
1314 wl1271_power_off(wl);
1315 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001317 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1318 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319out:
1320 mutex_unlock(&wl->mutex);
1321
1322 return ret;
1323}
1324
Luciano Coelho4623ec72011-03-21 19:26:41 +02001325static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326{
1327 int ret = 0;
1328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 wl1271_notice("power down");
1330
1331 if (wl->state != WL1271_STATE_PLT) {
1332 wl1271_error("cannot power down because not in PLT "
1333 "state: %d", wl->state);
1334 ret = -EBUSY;
1335 goto out;
1336 }
1337
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 wl1271_power_off(wl);
1339
1340 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001341 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001343 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001344 wl1271_disable_interrupts(wl);
1345 wl1271_flush_deferred_work(wl);
1346 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001347 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001348 mutex_lock(&wl->mutex);
1349out:
1350 return ret;
1351}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001352
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001353int wl1271_plt_stop(struct wl1271 *wl)
1354{
1355 int ret;
1356
1357 mutex_lock(&wl->mutex);
1358 ret = __wl1271_plt_stop(wl);
1359 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 return ret;
1361}
1362
Johannes Berg7bb45682011-02-24 14:42:06 +01001363static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001364{
1365 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001366 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001367 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001368 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369
Ido Yarivb07d4032011-03-01 15:14:43 +02001370 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1371
1372 if (wl->bss_type == BSS_TYPE_AP_BSS)
1373 hlid = wl1271_tx_get_hlid(skb);
1374
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001375 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001376
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001377 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001378
1379 /*
1380 * The workqueue is slow to process the tx_queue and we need stop
1381 * the queue here, otherwise the queue will get too long.
1382 */
1383 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1384 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1385 ieee80211_stop_queues(wl->hw);
1386 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1387 }
1388
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001389 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001390 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001391 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1392 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1393 } else {
1394 skb_queue_tail(&wl->tx_queue[q], skb);
1395 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396
1397 /*
1398 * The chip specific setup must run before the first TX packet -
1399 * before that, the tx_work will not be initialized!
1400 */
1401
Ido Yarivb07d4032011-03-01 15:14:43 +02001402 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1403 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001404 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001405
1406 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407}
1408
Shahar Leviae47c452011-03-06 16:32:14 +02001409int wl1271_tx_dummy_packet(struct wl1271 *wl)
1410{
Ido Yariv990f5de2011-03-31 10:06:59 +02001411 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001412
Ido Yariv990f5de2011-03-31 10:06:59 +02001413 spin_lock_irqsave(&wl->wl_lock, flags);
1414 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1415 wl->tx_queue_count++;
1416 spin_unlock_irqrestore(&wl->wl_lock, flags);
1417
1418 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1419 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1420 wl1271_tx_work_locked(wl);
1421
1422 /*
1423 * If the FW TX is busy, TX work will be scheduled by the threaded
1424 * interrupt handler function
1425 */
1426 return 0;
1427}
1428
1429/*
1430 * The size of the dummy packet should be at least 1400 bytes. However, in
1431 * order to minimize the number of bus transactions, aligning it to 512 bytes
1432 * boundaries could be beneficial, performance wise
1433 */
1434#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1435
Luciano Coelhocf27d862011-04-01 21:08:23 +03001436static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001437{
1438 struct sk_buff *skb;
1439 struct ieee80211_hdr_3addr *hdr;
1440 unsigned int dummy_packet_size;
1441
1442 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1443 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1444
1445 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001446 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001447 wl1271_warning("Failed to allocate a dummy packet skb");
1448 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001449 }
1450
1451 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1452
1453 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1454 memset(hdr, 0, sizeof(*hdr));
1455 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001456 IEEE80211_STYPE_NULLFUNC |
1457 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001458
Ido Yariv990f5de2011-03-31 10:06:59 +02001459 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001460
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001461 /* Dummy packets require the TID to be management */
1462 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001463
1464 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001465 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001466 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001467
Ido Yariv990f5de2011-03-31 10:06:59 +02001468 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001469}
1470
Ido Yariv990f5de2011-03-31 10:06:59 +02001471
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001472static struct notifier_block wl1271_dev_notifier = {
1473 .notifier_call = wl1271_dev_notify,
1474};
1475
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001476#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001477static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001478{
1479 int ret;
1480
Eliad Peller94390642011-05-13 11:57:13 +03001481 mutex_lock(&wl->mutex);
1482
1483 ret = wl1271_ps_elp_wakeup(wl);
1484 if (ret < 0)
1485 goto out_unlock;
1486
1487 /* enter psm if needed*/
1488 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1489 DECLARE_COMPLETION_ONSTACK(compl);
1490
1491 wl->ps_compl = &compl;
1492 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1493 wl->basic_rate, true);
1494 if (ret < 0)
1495 goto out_sleep;
1496
1497 /* we must unlock here so we will be able to get events */
1498 wl1271_ps_elp_sleep(wl);
1499 mutex_unlock(&wl->mutex);
1500
1501 ret = wait_for_completion_timeout(
1502 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1503 if (ret <= 0) {
1504 wl1271_warning("couldn't enter ps mode!");
1505 ret = -EBUSY;
1506 goto out;
1507 }
1508
1509 /* take mutex again, and wakeup */
1510 mutex_lock(&wl->mutex);
1511
1512 ret = wl1271_ps_elp_wakeup(wl);
1513 if (ret < 0)
1514 goto out_unlock;
1515 }
1516out_sleep:
1517 wl1271_ps_elp_sleep(wl);
1518out_unlock:
1519 mutex_unlock(&wl->mutex);
1520out:
1521 return ret;
1522
1523}
1524
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001525static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001526{
1527 int ret;
1528
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001529 mutex_lock(&wl->mutex);
1530
1531 ret = wl1271_ps_elp_wakeup(wl);
1532 if (ret < 0)
1533 goto out_unlock;
1534
1535 ret = wl1271_acx_set_ap_beacon_filter(wl, true);
1536
1537 wl1271_ps_elp_sleep(wl);
1538out_unlock:
1539 mutex_unlock(&wl->mutex);
1540 return ret;
1541
1542}
1543
1544static int wl1271_configure_suspend(struct wl1271 *wl)
1545{
1546 if (wl->bss_type == BSS_TYPE_STA_BSS)
1547 return wl1271_configure_suspend_sta(wl);
1548 if (wl->bss_type == BSS_TYPE_AP_BSS)
1549 return wl1271_configure_suspend_ap(wl);
1550 return 0;
1551}
1552
1553static void wl1271_configure_resume(struct wl1271 *wl)
1554{
1555 int ret;
1556 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1557 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1558
1559 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001560 return;
1561
1562 mutex_lock(&wl->mutex);
1563 ret = wl1271_ps_elp_wakeup(wl);
1564 if (ret < 0)
1565 goto out;
1566
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001567 if (is_sta) {
1568 /* exit psm if it wasn't configured */
1569 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1570 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1571 wl->basic_rate, true);
1572 } else if (is_ap) {
1573 wl1271_acx_set_ap_beacon_filter(wl, false);
1574 }
Eliad Peller94390642011-05-13 11:57:13 +03001575
1576 wl1271_ps_elp_sleep(wl);
1577out:
1578 mutex_unlock(&wl->mutex);
1579}
1580
Eliad Peller402e48612011-05-13 11:57:09 +03001581static int wl1271_op_suspend(struct ieee80211_hw *hw,
1582 struct cfg80211_wowlan *wow)
1583{
1584 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001585 int ret;
1586
Eliad Peller402e48612011-05-13 11:57:09 +03001587 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001588 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001589
Eliad Peller4a859df2011-06-06 12:21:52 +03001590 wl->wow_enabled = true;
1591 ret = wl1271_configure_suspend(wl);
1592 if (ret < 0) {
1593 wl1271_warning("couldn't prepare device to suspend");
1594 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001595 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001596 /* flush any remaining work */
1597 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1598 flush_delayed_work(&wl->scan_complete_work);
1599
1600 /*
1601 * disable and re-enable interrupts in order to flush
1602 * the threaded_irq
1603 */
1604 wl1271_disable_interrupts(wl);
1605
1606 /*
1607 * set suspended flag to avoid triggering a new threaded_irq
1608 * work. no need for spinlock as interrupts are disabled.
1609 */
1610 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1611
1612 wl1271_enable_interrupts(wl);
1613 flush_work(&wl->tx_work);
1614 flush_delayed_work(&wl->pspoll_work);
1615 flush_delayed_work(&wl->elp_work);
1616
Eliad Peller402e48612011-05-13 11:57:09 +03001617 return 0;
1618}
1619
1620static int wl1271_op_resume(struct ieee80211_hw *hw)
1621{
1622 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001623 unsigned long flags;
1624 bool run_irq_work = false;
1625
Eliad Peller402e48612011-05-13 11:57:09 +03001626 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1627 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001628 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001629
1630 /*
1631 * re-enable irq_work enqueuing, and call irq_work directly if
1632 * there is a pending work.
1633 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001634 spin_lock_irqsave(&wl->wl_lock, flags);
1635 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1636 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1637 run_irq_work = true;
1638 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001639
Eliad Peller4a859df2011-06-06 12:21:52 +03001640 if (run_irq_work) {
1641 wl1271_debug(DEBUG_MAC80211,
1642 "run postponed irq_work directly");
1643 wl1271_irq(0, wl);
1644 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001645 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001646 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001647 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001648
Eliad Peller402e48612011-05-13 11:57:09 +03001649 return 0;
1650}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001651#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001652
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001653static int wl1271_op_start(struct ieee80211_hw *hw)
1654{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001655 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1656
1657 /*
1658 * We have to delay the booting of the hardware because
1659 * we need to know the local MAC address before downloading and
1660 * initializing the firmware. The MAC address cannot be changed
1661 * after boot, and without the proper MAC address, the firmware
1662 * will not function properly.
1663 *
1664 * The MAC address is first known when the corresponding interface
1665 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001666 *
1667 * In addition, we currently have different firmwares for AP and managed
1668 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001669 */
1670
1671 return 0;
1672}
1673
1674static void wl1271_op_stop(struct ieee80211_hw *hw)
1675{
1676 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1677}
1678
1679static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1680 struct ieee80211_vif *vif)
1681{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001682 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001683 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001684 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001686 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001688 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1689 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001690
1691 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001692 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001693 wl1271_debug(DEBUG_MAC80211,
1694 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001695 ret = -EBUSY;
1696 goto out;
1697 }
1698
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001699 /*
1700 * in some very corner case HW recovery scenarios its possible to
1701 * get here before __wl1271_op_remove_interface is complete, so
1702 * opt out if that is the case.
1703 */
1704 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1705 ret = -EBUSY;
1706 goto out;
1707 }
1708
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001709 switch (vif->type) {
1710 case NL80211_IFTYPE_STATION:
1711 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001712 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001713 break;
1714 case NL80211_IFTYPE_ADHOC:
1715 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001716 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001717 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001718 case NL80211_IFTYPE_AP:
1719 wl->bss_type = BSS_TYPE_AP_BSS;
1720 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001721 default:
1722 ret = -EOPNOTSUPP;
1723 goto out;
1724 }
1725
1726 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001727
1728 if (wl->state != WL1271_STATE_OFF) {
1729 wl1271_error("cannot start because not in off state: %d",
1730 wl->state);
1731 ret = -EBUSY;
1732 goto out;
1733 }
1734
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001735 while (retries) {
1736 retries--;
1737 ret = wl1271_chip_wakeup(wl);
1738 if (ret < 0)
1739 goto power_off;
1740
1741 ret = wl1271_boot(wl);
1742 if (ret < 0)
1743 goto power_off;
1744
1745 ret = wl1271_hw_init(wl);
1746 if (ret < 0)
1747 goto irq_disable;
1748
Eliad Peller71125ab2010-10-28 21:46:43 +02001749 booted = true;
1750 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001752irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001753 mutex_unlock(&wl->mutex);
1754 /* Unlocking the mutex in the middle of handling is
1755 inherently unsafe. In this case we deem it safe to do,
1756 because we need to let any possibly pending IRQ out of
1757 the system (and while we are WL1271_STATE_OFF the IRQ
1758 work function will not do anything.) Also, any other
1759 possible concurrent operations will fail due to the
1760 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001761 wl1271_disable_interrupts(wl);
1762 wl1271_flush_deferred_work(wl);
1763 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001764 mutex_lock(&wl->mutex);
1765power_off:
1766 wl1271_power_off(wl);
1767 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001768
Eliad Peller71125ab2010-10-28 21:46:43 +02001769 if (!booted) {
1770 wl1271_error("firmware boot failed despite %d retries",
1771 WL1271_BOOT_RETRIES);
1772 goto out;
1773 }
1774
1775 wl->vif = vif;
1776 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001777 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001778 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001779
1780 /* update hw/fw version info in wiphy struct */
1781 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001782 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001783 sizeof(wiphy->fw_version));
1784
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001785 /* Check if any quirks are needed with older fw versions */
1786 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1787
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001788 /*
1789 * Now we know if 11a is supported (info from the NVS), so disable
1790 * 11a channels if not supported
1791 */
1792 if (!wl->enable_11a)
1793 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1794
1795 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1796 wl->enable_11a ? "" : "not ");
1797
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001798out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 mutex_unlock(&wl->mutex);
1800
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001801 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001802 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001803 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001804 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001806 return ret;
1807}
1808
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001809static void __wl1271_op_remove_interface(struct wl1271 *wl,
1810 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001811{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001812 int i;
1813
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001814 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001815
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001816 /* because of hardware recovery, we may get here twice */
1817 if (wl->state != WL1271_STATE_ON)
1818 return;
1819
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001820 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001822 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001823 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001824 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001825
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001826 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001827 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001828 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001829
Luciano Coelho08688d62010-07-08 17:50:07 +03001830 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001831 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001832 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001833 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001834 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001835 }
1836
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001837 /*
1838 * this must be before the cancel_work calls below, so that the work
1839 * functions don't perform further work.
1840 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001841 wl->state = WL1271_STATE_OFF;
1842
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001843 mutex_unlock(&wl->mutex);
1844
Ido Yariva6208652011-03-01 15:14:41 +02001845 wl1271_disable_interrupts(wl);
1846 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001847 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001848 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001849 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03001850 del_timer_sync(&wl->rx_streaming_timer);
1851 cancel_work_sync(&wl->rx_streaming_enable_work);
1852 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001853 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001854 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001855
1856 mutex_lock(&wl->mutex);
1857
1858 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001859 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001860 wl1271_power_off(wl);
1861
1862 memset(wl->bssid, 0, ETH_ALEN);
1863 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1864 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001865 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001866 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001867 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868
1869 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001870 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001871 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1872 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001873 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001874 wl->tx_results_count = 0;
1875 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001876 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001877 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001878 wl->time_offset = 0;
1879 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001880 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001881 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001882 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001883 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001884 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001885 wl->ap_fw_ps_map = 0;
1886 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001887 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001888
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001889 /*
1890 * this is performed after the cancel_work calls and the associated
1891 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1892 * get executed before all these vars have been reset.
1893 */
1894 wl->flags = 0;
1895
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001896 for (i = 0; i < NUM_TX_QUEUES; i++)
1897 wl->tx_blocks_freed[i] = 0;
1898
1899 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001900
1901 kfree(wl->fw_status);
1902 wl->fw_status = NULL;
1903 kfree(wl->tx_res_if);
1904 wl->tx_res_if = NULL;
1905 kfree(wl->target_mem_map);
1906 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001907}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001908
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001909static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1910 struct ieee80211_vif *vif)
1911{
1912 struct wl1271 *wl = hw->priv;
1913
1914 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001915 /*
1916 * wl->vif can be null here if someone shuts down the interface
1917 * just when hardware recovery has been started.
1918 */
1919 if (wl->vif) {
1920 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001921 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001922 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001923
Juuso Oikarinen67353292010-11-18 15:19:02 +02001924 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001925 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926}
1927
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001928void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001929{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001930 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001931
1932 /* combine requested filters with current filter config */
1933 filters = wl->filters | filters;
1934
1935 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1936
1937 if (filters & FIF_PROMISC_IN_BSS) {
1938 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1939 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1940 wl->rx_config |= CFG_BSSID_FILTER_EN;
1941 }
1942 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1943 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1944 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1945 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1946 }
1947 if (filters & FIF_OTHER_BSS) {
1948 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1949 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1950 }
1951 if (filters & FIF_CONTROL) {
1952 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1953 wl->rx_filter |= CFG_RX_CTL_EN;
1954 }
1955 if (filters & FIF_FCSFAIL) {
1956 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1957 wl->rx_filter |= CFG_RX_FCS_ERROR;
1958 }
1959}
1960
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001961static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001962{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001963 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001964 /* we need to use a dummy BSSID for now */
1965 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1966 0xad, 0xbe, 0xef };
1967
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001968 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1969
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001970 /* pass through frames from all BSS */
1971 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1972
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001973 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001974 if (ret < 0)
1975 goto out;
1976
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001977 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001978
1979out:
1980 return ret;
1981}
1982
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001983static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001984{
1985 int ret;
1986
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001987 /*
1988 * One of the side effects of the JOIN command is that is clears
1989 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1990 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001991 * Currently the only valid scenario for JOIN during association
1992 * is on roaming, in which case we will also be given new keys.
1993 * Keep the below message for now, unless it starts bothering
1994 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001995 */
1996 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1997 wl1271_info("JOIN while associated.");
1998
1999 if (set_assoc)
2000 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2001
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002002 ret = wl1271_cmd_join(wl, wl->set_bss_type);
2003 if (ret < 0)
2004 goto out;
2005
2006 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2007
2008 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2009 goto out;
2010
2011 /*
2012 * The join command disable the keep-alive mode, shut down its process,
2013 * and also clear the template config, so we need to reset it all after
2014 * the join. The acx_aid starts the keep-alive process, and the order
2015 * of the commands below is relevant.
2016 */
2017 ret = wl1271_acx_keep_alive_mode(wl, true);
2018 if (ret < 0)
2019 goto out;
2020
2021 ret = wl1271_acx_aid(wl, wl->aid);
2022 if (ret < 0)
2023 goto out;
2024
2025 ret = wl1271_cmd_build_klv_null_data(wl);
2026 if (ret < 0)
2027 goto out;
2028
2029 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2030 ACX_KEEP_ALIVE_TPL_VALID);
2031 if (ret < 0)
2032 goto out;
2033
2034out:
2035 return ret;
2036}
2037
2038static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002039{
2040 int ret;
2041
2042 /* to stop listening to a channel, we disconnect */
2043 ret = wl1271_cmd_disconnect(wl);
2044 if (ret < 0)
2045 goto out;
2046
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002047 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002048 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002049
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02002050 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002051 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002052
2053out:
2054 return ret;
2055}
2056
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002057static void wl1271_set_band_rate(struct wl1271 *wl)
2058{
2059 if (wl->band == IEEE80211_BAND_2GHZ)
2060 wl->basic_rate_set = wl->conf.tx.basic_rate;
2061 else
2062 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2063}
2064
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002065static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002066{
2067 int ret;
2068
2069 if (idle) {
2070 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2071 ret = wl1271_unjoin(wl);
2072 if (ret < 0)
2073 goto out;
2074 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002075 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002076 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002077 if (ret < 0)
2078 goto out;
2079 ret = wl1271_acx_keep_alive_config(
2080 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2081 ACX_KEEP_ALIVE_TPL_INVALID);
2082 if (ret < 0)
2083 goto out;
2084 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2085 } else {
2086 /* increment the session counter */
2087 wl->session_counter++;
2088 if (wl->session_counter >= SESSION_COUNTER_MAX)
2089 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002090
2091 /* The current firmware only supports sched_scan in idle */
2092 if (wl->sched_scanning) {
2093 wl1271_scan_sched_scan_stop(wl);
2094 ieee80211_sched_scan_stopped(wl->hw);
2095 }
2096
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002097 ret = wl1271_dummy_join(wl);
2098 if (ret < 0)
2099 goto out;
2100 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2101 }
2102
2103out:
2104 return ret;
2105}
2106
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002107static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2108{
2109 struct wl1271 *wl = hw->priv;
2110 struct ieee80211_conf *conf = &hw->conf;
2111 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002112 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002113
2114 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2115
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002116 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2117 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002118 channel,
2119 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002120 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002121 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2122 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002123
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002124 /*
2125 * mac80211 will go to idle nearly immediately after transmitting some
2126 * frames, such as the deauth. To make sure those frames reach the air,
2127 * wait here until the TX queue is fully flushed.
2128 */
2129 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2130 (conf->flags & IEEE80211_CONF_IDLE))
2131 wl1271_tx_flush(wl);
2132
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002133 mutex_lock(&wl->mutex);
2134
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002135 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002136 /* we support configuring the channel and band while off */
2137 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2138 wl->band = conf->channel->band;
2139 wl->channel = channel;
2140 }
2141
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002142 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002143 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002144
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002145 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2146
Ido Yariva6208652011-03-01 15:14:41 +02002147 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002148 if (ret < 0)
2149 goto out;
2150
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002151 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002152 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2153 ((wl->band != conf->channel->band) ||
2154 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002155 wl->band = conf->channel->band;
2156 wl->channel = channel;
2157
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002158 if (!is_ap) {
2159 /*
2160 * FIXME: the mac80211 should really provide a fixed
2161 * rate to use here. for now, just use the smallest
2162 * possible rate for the band as a fixed rate for
2163 * association frames and other control messages.
2164 */
2165 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2166 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002167
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002168 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2169 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002170 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002171 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002172 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002173
2174 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2175 ret = wl1271_join(wl, false);
2176 if (ret < 0)
2177 wl1271_warning("cmd join on channel "
2178 "failed %d", ret);
2179 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002180 }
2181 }
2182
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002183 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2184 ret = wl1271_sta_handle_idle(wl,
2185 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002186 if (ret < 0)
2187 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002188 }
2189
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002190 /*
2191 * if mac80211 changes the PSM mode, make sure the mode is not
2192 * incorrectly changed after the pspoll failure active window.
2193 */
2194 if (changed & IEEE80211_CONF_CHANGE_PS)
2195 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2196
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002197 if (conf->flags & IEEE80211_CONF_PS &&
2198 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2199 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200
2201 /*
2202 * We enter PSM only if we're already associated.
2203 * If we're not, we'll enter it when joining an SSID,
2204 * through the bss_info_changed() hook.
2205 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002206 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002207 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002208 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002209 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002210 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002211 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002212 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002213 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002215 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002216
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002217 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002218 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002219 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220 }
2221
2222 if (conf->power_level != wl->power_level) {
2223 ret = wl1271_acx_tx_power(wl, conf->power_level);
2224 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002225 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226
2227 wl->power_level = conf->power_level;
2228 }
2229
2230out_sleep:
2231 wl1271_ps_elp_sleep(wl);
2232
2233out:
2234 mutex_unlock(&wl->mutex);
2235
2236 return ret;
2237}
2238
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002239struct wl1271_filter_params {
2240 bool enabled;
2241 int mc_list_length;
2242 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2243};
2244
Jiri Pirko22bedad2010-04-01 21:22:57 +00002245static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2246 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002247{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002248 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002249 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002250 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002251
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002252 if (unlikely(wl->state == WL1271_STATE_OFF))
2253 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002254
Juuso Oikarinen74441132009-10-13 12:47:53 +03002255 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002256 if (!fp) {
2257 wl1271_error("Out of memory setting filters.");
2258 return 0;
2259 }
2260
2261 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002262 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002263 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2264 fp->enabled = false;
2265 } else {
2266 fp->enabled = true;
2267 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002268 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002269 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002270 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002271 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002272 }
2273
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002274 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002275}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002277#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2278 FIF_ALLMULTI | \
2279 FIF_FCSFAIL | \
2280 FIF_BCN_PRBRESP_PROMISC | \
2281 FIF_CONTROL | \
2282 FIF_OTHER_BSS)
2283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2285 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002286 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002287{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002288 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002290 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002291
Arik Nemtsov7d057862010-10-16 19:25:35 +02002292 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2293 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002294
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002295 mutex_lock(&wl->mutex);
2296
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002297 *total &= WL1271_SUPPORTED_FILTERS;
2298 changed &= WL1271_SUPPORTED_FILTERS;
2299
2300 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002301 goto out;
2302
Ido Yariva6208652011-03-01 15:14:41 +02002303 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002304 if (ret < 0)
2305 goto out;
2306
Arik Nemtsov7d057862010-10-16 19:25:35 +02002307 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2308 if (*total & FIF_ALLMULTI)
2309 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2310 else if (fp)
2311 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2312 fp->mc_list,
2313 fp->mc_list_length);
2314 if (ret < 0)
2315 goto out_sleep;
2316 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002318 /* determine, whether supported filter values have changed */
2319 if (changed == 0)
2320 goto out_sleep;
2321
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002322 /* configure filters */
2323 wl->filters = *total;
2324 wl1271_configure_filters(wl, 0);
2325
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002326 /* apply configured filters */
2327 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2328 if (ret < 0)
2329 goto out_sleep;
2330
2331out_sleep:
2332 wl1271_ps_elp_sleep(wl);
2333
2334out:
2335 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002336 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002337}
2338
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002339static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2340 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2341 u16 tx_seq_16)
2342{
2343 struct wl1271_ap_key *ap_key;
2344 int i;
2345
2346 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2347
2348 if (key_size > MAX_KEY_SIZE)
2349 return -EINVAL;
2350
2351 /*
2352 * Find next free entry in ap_keys. Also check we are not replacing
2353 * an existing key.
2354 */
2355 for (i = 0; i < MAX_NUM_KEYS; i++) {
2356 if (wl->recorded_ap_keys[i] == NULL)
2357 break;
2358
2359 if (wl->recorded_ap_keys[i]->id == id) {
2360 wl1271_warning("trying to record key replacement");
2361 return -EINVAL;
2362 }
2363 }
2364
2365 if (i == MAX_NUM_KEYS)
2366 return -EBUSY;
2367
2368 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2369 if (!ap_key)
2370 return -ENOMEM;
2371
2372 ap_key->id = id;
2373 ap_key->key_type = key_type;
2374 ap_key->key_size = key_size;
2375 memcpy(ap_key->key, key, key_size);
2376 ap_key->hlid = hlid;
2377 ap_key->tx_seq_32 = tx_seq_32;
2378 ap_key->tx_seq_16 = tx_seq_16;
2379
2380 wl->recorded_ap_keys[i] = ap_key;
2381 return 0;
2382}
2383
2384static void wl1271_free_ap_keys(struct wl1271 *wl)
2385{
2386 int i;
2387
2388 for (i = 0; i < MAX_NUM_KEYS; i++) {
2389 kfree(wl->recorded_ap_keys[i]);
2390 wl->recorded_ap_keys[i] = NULL;
2391 }
2392}
2393
2394static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2395{
2396 int i, ret = 0;
2397 struct wl1271_ap_key *key;
2398 bool wep_key_added = false;
2399
2400 for (i = 0; i < MAX_NUM_KEYS; i++) {
2401 if (wl->recorded_ap_keys[i] == NULL)
2402 break;
2403
2404 key = wl->recorded_ap_keys[i];
2405 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2406 key->id, key->key_type,
2407 key->key_size, key->key,
2408 key->hlid, key->tx_seq_32,
2409 key->tx_seq_16);
2410 if (ret < 0)
2411 goto out;
2412
2413 if (key->key_type == KEY_WEP)
2414 wep_key_added = true;
2415 }
2416
2417 if (wep_key_added) {
2418 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2419 if (ret < 0)
2420 goto out;
2421 }
2422
2423out:
2424 wl1271_free_ap_keys(wl);
2425 return ret;
2426}
2427
2428static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2429 u8 key_size, const u8 *key, u32 tx_seq_32,
2430 u16 tx_seq_16, struct ieee80211_sta *sta)
2431{
2432 int ret;
2433 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2434
2435 if (is_ap) {
2436 struct wl1271_station *wl_sta;
2437 u8 hlid;
2438
2439 if (sta) {
2440 wl_sta = (struct wl1271_station *)sta->drv_priv;
2441 hlid = wl_sta->hlid;
2442 } else {
2443 hlid = WL1271_AP_BROADCAST_HLID;
2444 }
2445
2446 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2447 /*
2448 * We do not support removing keys after AP shutdown.
2449 * Pretend we do to make mac80211 happy.
2450 */
2451 if (action != KEY_ADD_OR_REPLACE)
2452 return 0;
2453
2454 ret = wl1271_record_ap_key(wl, id,
2455 key_type, key_size,
2456 key, hlid, tx_seq_32,
2457 tx_seq_16);
2458 } else {
2459 ret = wl1271_cmd_set_ap_key(wl, action,
2460 id, key_type, key_size,
2461 key, hlid, tx_seq_32,
2462 tx_seq_16);
2463 }
2464
2465 if (ret < 0)
2466 return ret;
2467 } else {
2468 const u8 *addr;
2469 static const u8 bcast_addr[ETH_ALEN] = {
2470 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2471 };
2472
2473 addr = sta ? sta->addr : bcast_addr;
2474
2475 if (is_zero_ether_addr(addr)) {
2476 /* We dont support TX only encryption */
2477 return -EOPNOTSUPP;
2478 }
2479
2480 /* The wl1271 does not allow to remove unicast keys - they
2481 will be cleared automatically on next CMD_JOIN. Ignore the
2482 request silently, as we dont want the mac80211 to emit
2483 an error message. */
2484 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2485 return 0;
2486
2487 ret = wl1271_cmd_set_sta_key(wl, action,
2488 id, key_type, key_size,
2489 key, addr, tx_seq_32,
2490 tx_seq_16);
2491 if (ret < 0)
2492 return ret;
2493
2494 /* the default WEP key needs to be configured at least once */
2495 if (key_type == KEY_WEP) {
2496 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2497 wl->default_key);
2498 if (ret < 0)
2499 return ret;
2500 }
2501 }
2502
2503 return 0;
2504}
2505
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002506static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2507 struct ieee80211_vif *vif,
2508 struct ieee80211_sta *sta,
2509 struct ieee80211_key_conf *key_conf)
2510{
2511 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002513 u32 tx_seq_32 = 0;
2514 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515 u8 key_type;
2516
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002517 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2518
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002519 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002520 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002521 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002522 key_conf->keylen, key_conf->flags);
2523 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2524
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002525 mutex_lock(&wl->mutex);
2526
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002527 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2528 ret = -EAGAIN;
2529 goto out_unlock;
2530 }
2531
Ido Yariva6208652011-03-01 15:14:41 +02002532 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002533 if (ret < 0)
2534 goto out_unlock;
2535
Johannes Berg97359d12010-08-10 09:46:38 +02002536 switch (key_conf->cipher) {
2537 case WLAN_CIPHER_SUITE_WEP40:
2538 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002539 key_type = KEY_WEP;
2540
2541 key_conf->hw_key_idx = key_conf->keyidx;
2542 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002543 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002544 key_type = KEY_TKIP;
2545
2546 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002547 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2548 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002550 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551 key_type = KEY_AES;
2552
2553 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002554 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2555 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002557 case WL1271_CIPHER_SUITE_GEM:
2558 key_type = KEY_GEM;
2559 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2560 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2561 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002562 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002563 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002564
2565 ret = -EOPNOTSUPP;
2566 goto out_sleep;
2567 }
2568
2569 switch (cmd) {
2570 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002571 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2572 key_conf->keyidx, key_type,
2573 key_conf->keylen, key_conf->key,
2574 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002575 if (ret < 0) {
2576 wl1271_error("Could not add or replace key");
2577 goto out_sleep;
2578 }
2579 break;
2580
2581 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002582 ret = wl1271_set_key(wl, KEY_REMOVE,
2583 key_conf->keyidx, key_type,
2584 key_conf->keylen, key_conf->key,
2585 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002586 if (ret < 0) {
2587 wl1271_error("Could not remove key");
2588 goto out_sleep;
2589 }
2590 break;
2591
2592 default:
2593 wl1271_error("Unsupported key cmd 0x%x", cmd);
2594 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002595 break;
2596 }
2597
2598out_sleep:
2599 wl1271_ps_elp_sleep(wl);
2600
2601out_unlock:
2602 mutex_unlock(&wl->mutex);
2603
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002604 return ret;
2605}
2606
2607static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002608 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002609 struct cfg80211_scan_request *req)
2610{
2611 struct wl1271 *wl = hw->priv;
2612 int ret;
2613 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002614 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002615
2616 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2617
2618 if (req->n_ssids) {
2619 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002620 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002621 }
2622
2623 mutex_lock(&wl->mutex);
2624
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002625 if (wl->state == WL1271_STATE_OFF) {
2626 /*
2627 * We cannot return -EBUSY here because cfg80211 will expect
2628 * a call to ieee80211_scan_completed if we do - in this case
2629 * there won't be any call.
2630 */
2631 ret = -EAGAIN;
2632 goto out;
2633 }
2634
Ido Yariva6208652011-03-01 15:14:41 +02002635 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002636 if (ret < 0)
2637 goto out;
2638
Luciano Coelho5924f892010-08-04 03:46:22 +03002639 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002640
2641 wl1271_ps_elp_sleep(wl);
2642
2643out:
2644 mutex_unlock(&wl->mutex);
2645
2646 return ret;
2647}
2648
Luciano Coelho33c2c062011-05-10 14:46:02 +03002649static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2650 struct ieee80211_vif *vif,
2651 struct cfg80211_sched_scan_request *req,
2652 struct ieee80211_sched_scan_ies *ies)
2653{
2654 struct wl1271 *wl = hw->priv;
2655 int ret;
2656
2657 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2658
2659 mutex_lock(&wl->mutex);
2660
2661 ret = wl1271_ps_elp_wakeup(wl);
2662 if (ret < 0)
2663 goto out;
2664
2665 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2666 if (ret < 0)
2667 goto out_sleep;
2668
2669 ret = wl1271_scan_sched_scan_start(wl);
2670 if (ret < 0)
2671 goto out_sleep;
2672
2673 wl->sched_scanning = true;
2674
2675out_sleep:
2676 wl1271_ps_elp_sleep(wl);
2677out:
2678 mutex_unlock(&wl->mutex);
2679 return ret;
2680}
2681
2682static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2683 struct ieee80211_vif *vif)
2684{
2685 struct wl1271 *wl = hw->priv;
2686 int ret;
2687
2688 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2689
2690 mutex_lock(&wl->mutex);
2691
2692 ret = wl1271_ps_elp_wakeup(wl);
2693 if (ret < 0)
2694 goto out;
2695
2696 wl1271_scan_sched_scan_stop(wl);
2697
2698 wl1271_ps_elp_sleep(wl);
2699out:
2700 mutex_unlock(&wl->mutex);
2701}
2702
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002703static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2704{
2705 struct wl1271 *wl = hw->priv;
2706 int ret = 0;
2707
2708 mutex_lock(&wl->mutex);
2709
2710 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2711 ret = -EAGAIN;
2712 goto out;
2713 }
2714
Ido Yariva6208652011-03-01 15:14:41 +02002715 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002716 if (ret < 0)
2717 goto out;
2718
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002719 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002720 if (ret < 0)
2721 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2722
2723 wl1271_ps_elp_sleep(wl);
2724
2725out:
2726 mutex_unlock(&wl->mutex);
2727
2728 return ret;
2729}
2730
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2732{
2733 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002734 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735
2736 mutex_lock(&wl->mutex);
2737
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002738 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2739 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002740 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002741 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002742
Ido Yariva6208652011-03-01 15:14:41 +02002743 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002744 if (ret < 0)
2745 goto out;
2746
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002747 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002748 if (ret < 0)
2749 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2750
2751 wl1271_ps_elp_sleep(wl);
2752
2753out:
2754 mutex_unlock(&wl->mutex);
2755
2756 return ret;
2757}
2758
Arik Nemtsove78a2872010-10-16 19:07:21 +02002759static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002760 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002761{
Eliad Peller889cb362011-05-01 09:56:45 +03002762 u8 ssid_len;
2763 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2764 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002765
Eliad Peller889cb362011-05-01 09:56:45 +03002766 if (!ptr) {
2767 wl1271_error("No SSID in IEs!");
2768 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002769 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002770
Eliad Peller889cb362011-05-01 09:56:45 +03002771 ssid_len = ptr[1];
2772 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2773 wl1271_error("SSID is too long!");
2774 return -EINVAL;
2775 }
2776
2777 wl->ssid_len = ssid_len;
2778 memcpy(wl->ssid, ptr+2, ssid_len);
2779 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002780}
2781
Arik Nemtsove78a2872010-10-16 19:07:21 +02002782static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2783 struct ieee80211_bss_conf *bss_conf,
2784 u32 changed)
2785{
2786 int ret = 0;
2787
2788 if (changed & BSS_CHANGED_ERP_SLOT) {
2789 if (bss_conf->use_short_slot)
2790 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2791 else
2792 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2793 if (ret < 0) {
2794 wl1271_warning("Set slot time failed %d", ret);
2795 goto out;
2796 }
2797 }
2798
2799 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2800 if (bss_conf->use_short_preamble)
2801 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2802 else
2803 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2804 }
2805
2806 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2807 if (bss_conf->use_cts_prot)
2808 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2809 else
2810 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2811 if (ret < 0) {
2812 wl1271_warning("Set ctsprotect failed %d", ret);
2813 goto out;
2814 }
2815 }
2816
2817out:
2818 return ret;
2819}
2820
2821static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2822 struct ieee80211_vif *vif,
2823 struct ieee80211_bss_conf *bss_conf,
2824 u32 changed)
2825{
2826 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2827 int ret = 0;
2828
2829 if ((changed & BSS_CHANGED_BEACON_INT)) {
2830 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2831 bss_conf->beacon_int);
2832
2833 wl->beacon_int = bss_conf->beacon_int;
2834 }
2835
2836 if ((changed & BSS_CHANGED_BEACON)) {
2837 struct ieee80211_hdr *hdr;
2838 int ieoffset = offsetof(struct ieee80211_mgmt,
2839 u.beacon.variable);
2840 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2841 u16 tmpl_id;
2842
2843 if (!beacon)
2844 goto out;
2845
2846 wl1271_debug(DEBUG_MASTER, "beacon updated");
2847
2848 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2849 if (ret < 0) {
2850 dev_kfree_skb(beacon);
2851 goto out;
2852 }
2853 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2854 CMD_TEMPL_BEACON;
2855 ret = wl1271_cmd_template_set(wl, tmpl_id,
2856 beacon->data,
2857 beacon->len, 0,
2858 wl1271_tx_min_rate_get(wl));
2859 if (ret < 0) {
2860 dev_kfree_skb(beacon);
2861 goto out;
2862 }
2863
2864 hdr = (struct ieee80211_hdr *) beacon->data;
2865 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2866 IEEE80211_STYPE_PROBE_RESP);
2867
2868 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2869 CMD_TEMPL_PROBE_RESPONSE;
2870 ret = wl1271_cmd_template_set(wl,
2871 tmpl_id,
2872 beacon->data,
2873 beacon->len, 0,
2874 wl1271_tx_min_rate_get(wl));
2875 dev_kfree_skb(beacon);
2876 if (ret < 0)
2877 goto out;
2878 }
2879
2880out:
2881 return ret;
2882}
2883
2884/* AP mode changes */
2885static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002886 struct ieee80211_vif *vif,
2887 struct ieee80211_bss_conf *bss_conf,
2888 u32 changed)
2889{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002890 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002891
Arik Nemtsove78a2872010-10-16 19:07:21 +02002892 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2893 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002894
Arik Nemtsove78a2872010-10-16 19:07:21 +02002895 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2896 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897
Arik Nemtsov70f47422011-04-18 14:15:25 +03002898 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002899 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002900 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002901 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002902 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002903
2904 ret = wl1271_ap_init_templates(wl);
2905 if (ret < 0)
2906 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002907 }
2908
Arik Nemtsove78a2872010-10-16 19:07:21 +02002909 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2910 if (ret < 0)
2911 goto out;
2912
2913 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2914 if (bss_conf->enable_beacon) {
2915 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2916 ret = wl1271_cmd_start_bss(wl);
2917 if (ret < 0)
2918 goto out;
2919
2920 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2921 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002922
2923 ret = wl1271_ap_init_hwenc(wl);
2924 if (ret < 0)
2925 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002926 }
2927 } else {
2928 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2929 ret = wl1271_cmd_stop_bss(wl);
2930 if (ret < 0)
2931 goto out;
2932
2933 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2934 wl1271_debug(DEBUG_AP, "stopped AP");
2935 }
2936 }
2937 }
2938
2939 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2940 if (ret < 0)
2941 goto out;
2942out:
2943 return;
2944}
2945
2946/* STA/IBSS mode changes */
2947static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2948 struct ieee80211_vif *vif,
2949 struct ieee80211_bss_conf *bss_conf,
2950 u32 changed)
2951{
2952 bool do_join = false, set_assoc = false;
2953 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002954 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002955 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002956 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002957 bool sta_exists = false;
2958 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002959
2960 if (is_ibss) {
2961 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2962 changed);
2963 if (ret < 0)
2964 goto out;
2965 }
2966
2967 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2968 do_join = true;
2969
2970 /* Need to update the SSID (for filtering etc) */
2971 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2972 do_join = true;
2973
2974 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002975 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2976 bss_conf->enable_beacon ? "enabled" : "disabled");
2977
2978 if (bss_conf->enable_beacon)
2979 wl->set_bss_type = BSS_TYPE_IBSS;
2980 else
2981 wl->set_bss_type = BSS_TYPE_STA_BSS;
2982 do_join = true;
2983 }
2984
Arik Nemtsove78a2872010-10-16 19:07:21 +02002985 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002986 bool enable = false;
2987 if (bss_conf->cqm_rssi_thold)
2988 enable = true;
2989 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2990 bss_conf->cqm_rssi_thold,
2991 bss_conf->cqm_rssi_hyst);
2992 if (ret < 0)
2993 goto out;
2994 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2995 }
2996
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002997 if ((changed & BSS_CHANGED_BSSID) &&
2998 /*
2999 * Now we know the correct bssid, so we send a new join command
3000 * and enable the BSSID filter
3001 */
3002 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003003 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003004
Eliad Pellerfa287b82010-12-26 09:27:50 +01003005 if (!is_zero_ether_addr(wl->bssid)) {
3006 ret = wl1271_cmd_build_null_data(wl);
3007 if (ret < 0)
3008 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003009
Eliad Pellerfa287b82010-12-26 09:27:50 +01003010 ret = wl1271_build_qos_null_data(wl);
3011 if (ret < 0)
3012 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003013
Eliad Pellerfa287b82010-12-26 09:27:50 +01003014 /* filter out all packets not from this BSSID */
3015 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02003016
Eliad Pellerfa287b82010-12-26 09:27:50 +01003017 /* Need to update the BSSID (for filtering etc) */
3018 do_join = true;
3019 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003020 }
3021
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003022 rcu_read_lock();
3023 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3024 if (sta) {
3025 /* save the supp_rates of the ap */
3026 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3027 if (sta->ht_cap.ht_supported)
3028 sta_rate_set |=
3029 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003030 sta_ht_cap = sta->ht_cap;
3031 sta_exists = true;
3032 }
3033 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003034
Arik Nemtsova1008852011-02-12 23:24:20 +02003035 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003036 /* handle new association with HT and HT information change */
3037 if ((changed & BSS_CHANGED_HT) &&
3038 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003039 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003040 true);
3041 if (ret < 0) {
3042 wl1271_warning("Set ht cap true failed %d",
3043 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003044 goto out;
3045 }
3046 ret = wl1271_acx_set_ht_information(wl,
3047 bss_conf->ht_operation_mode);
3048 if (ret < 0) {
3049 wl1271_warning("Set ht information failed %d",
3050 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003051 goto out;
3052 }
3053 }
3054 /* handle new association without HT and disassociation */
3055 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003056 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003057 false);
3058 if (ret < 0) {
3059 wl1271_warning("Set ht cap false failed %d",
3060 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003061 goto out;
3062 }
3063 }
3064 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003065
Arik Nemtsove78a2872010-10-16 19:07:21 +02003066 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003067 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003068 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003069 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003070 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003071 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003073 wl->ps_poll_failures = 0;
3074
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003075 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003076 * use basic rates from AP, and determine lowest rate
3077 * to use with control frames.
3078 */
3079 rates = bss_conf->basic_rates;
3080 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3081 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003082 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003083 if (sta_rate_set)
3084 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3085 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003086 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003087 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003088 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003089
3090 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003091 * with wl1271, we don't need to update the
3092 * beacon_int and dtim_period, because the firmware
3093 * updates it by itself when the first beacon is
3094 * received after a join.
3095 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003096 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3097 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003098 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003099
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003100 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003101 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003102 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003103 dev_kfree_skb(wl->probereq);
3104 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3105 ieoffset = offsetof(struct ieee80211_mgmt,
3106 u.probe_req.variable);
3107 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003108
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003109 /* enable the connection monitoring feature */
3110 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003112 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003113
3114 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003115 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3116 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003117 enum wl1271_cmd_ps_mode mode;
3118
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003119 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003120 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003121 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003122 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003123 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003124 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003125 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003126 } else {
3127 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003128 bool was_assoc =
3129 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3130 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003131 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003132 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003133
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003134 /* free probe-request template */
3135 dev_kfree_skb(wl->probereq);
3136 wl->probereq = NULL;
3137
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003138 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003139 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003140
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003141 /* revert back to minimum rates for the current band */
3142 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003143 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003144 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003145 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003146 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003147
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003148 /* disable connection monitor features */
3149 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003150
3151 /* Disable the keep-alive feature */
3152 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003153 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003154 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003155
3156 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003157 if (was_assoc) {
3158 wl1271_unjoin(wl);
3159 wl1271_dummy_join(wl);
3160 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003161 }
3162 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003163
Eliad Pellerd192d262011-05-24 14:33:08 +03003164 if (changed & BSS_CHANGED_IBSS) {
3165 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3166 bss_conf->ibss_joined);
3167
3168 if (bss_conf->ibss_joined) {
3169 u32 rates = bss_conf->basic_rates;
3170 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3171 rates);
3172 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3173
3174 /* by default, use 11b rates */
3175 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3176 ret = wl1271_acx_sta_rate_policies(wl);
3177 if (ret < 0)
3178 goto out;
3179 }
3180 }
3181
Arik Nemtsove78a2872010-10-16 19:07:21 +02003182 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3183 if (ret < 0)
3184 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003185
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003186 if (changed & BSS_CHANGED_ARP_FILTER) {
3187 __be32 addr = bss_conf->arp_addr_list[0];
3188 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3189
Eliad Pellerc5312772010-12-09 11:31:27 +02003190 if (bss_conf->arp_addr_cnt == 1 &&
3191 bss_conf->arp_filter_enabled) {
3192 /*
3193 * The template should have been configured only upon
3194 * association. however, it seems that the correct ip
3195 * isn't being set (when sending), so we have to
3196 * reconfigure the template upon every ip change.
3197 */
3198 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3199 if (ret < 0) {
3200 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003201 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003202 }
3203
3204 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003205 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003206 addr);
3207 } else
3208 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003209
3210 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003211 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003212 }
3213
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003214 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003215 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003216 if (ret < 0) {
3217 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003218 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003219 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003220 }
3221
Arik Nemtsove78a2872010-10-16 19:07:21 +02003222out:
3223 return;
3224}
3225
3226static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3227 struct ieee80211_vif *vif,
3228 struct ieee80211_bss_conf *bss_conf,
3229 u32 changed)
3230{
3231 struct wl1271 *wl = hw->priv;
3232 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3233 int ret;
3234
3235 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3236 (int)changed);
3237
3238 mutex_lock(&wl->mutex);
3239
3240 if (unlikely(wl->state == WL1271_STATE_OFF))
3241 goto out;
3242
Ido Yariva6208652011-03-01 15:14:41 +02003243 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003244 if (ret < 0)
3245 goto out;
3246
3247 if (is_ap)
3248 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3249 else
3250 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3251
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003252 wl1271_ps_elp_sleep(wl);
3253
3254out:
3255 mutex_unlock(&wl->mutex);
3256}
3257
Kalle Valoc6999d82010-02-18 13:25:41 +02003258static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3259 const struct ieee80211_tx_queue_params *params)
3260{
3261 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003262 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003263 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003264
3265 mutex_lock(&wl->mutex);
3266
3267 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3268
Kalle Valo4695dc92010-03-18 12:26:38 +02003269 if (params->uapsd)
3270 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3271 else
3272 ps_scheme = CONF_PS_SCHEME_LEGACY;
3273
Arik Nemtsov488fc542010-10-16 20:33:45 +02003274 if (wl->state == WL1271_STATE_OFF) {
3275 /*
3276 * If the state is off, the parameters will be recorded and
3277 * configured on init. This happens in AP-mode.
3278 */
3279 struct conf_tx_ac_category *conf_ac =
3280 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3281 struct conf_tx_tid *conf_tid =
3282 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3283
3284 conf_ac->ac = wl1271_tx_get_queue(queue);
3285 conf_ac->cw_min = (u8)params->cw_min;
3286 conf_ac->cw_max = params->cw_max;
3287 conf_ac->aifsn = params->aifs;
3288 conf_ac->tx_op_limit = params->txop << 5;
3289
3290 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3291 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3292 conf_tid->tsid = wl1271_tx_get_queue(queue);
3293 conf_tid->ps_scheme = ps_scheme;
3294 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3295 conf_tid->apsd_conf[0] = 0;
3296 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003297 goto out;
3298 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003299
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003300 ret = wl1271_ps_elp_wakeup(wl);
3301 if (ret < 0)
3302 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003303
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003304 /*
3305 * the txop is confed in units of 32us by the mac80211,
3306 * we need us
3307 */
3308 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3309 params->cw_min, params->cw_max,
3310 params->aifs, params->txop << 5);
3311 if (ret < 0)
3312 goto out_sleep;
3313
3314 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3315 CONF_CHANNEL_TYPE_EDCF,
3316 wl1271_tx_get_queue(queue),
3317 ps_scheme, CONF_ACK_POLICY_LEGACY,
3318 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003319
3320out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003321 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003322
3323out:
3324 mutex_unlock(&wl->mutex);
3325
3326 return ret;
3327}
3328
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003329static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3330{
3331
3332 struct wl1271 *wl = hw->priv;
3333 u64 mactime = ULLONG_MAX;
3334 int ret;
3335
3336 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3337
3338 mutex_lock(&wl->mutex);
3339
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003340 if (unlikely(wl->state == WL1271_STATE_OFF))
3341 goto out;
3342
Ido Yariva6208652011-03-01 15:14:41 +02003343 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003344 if (ret < 0)
3345 goto out;
3346
3347 ret = wl1271_acx_tsf_info(wl, &mactime);
3348 if (ret < 0)
3349 goto out_sleep;
3350
3351out_sleep:
3352 wl1271_ps_elp_sleep(wl);
3353
3354out:
3355 mutex_unlock(&wl->mutex);
3356 return mactime;
3357}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003358
John W. Linvilleece550d2010-07-28 16:41:06 -04003359static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3360 struct survey_info *survey)
3361{
3362 struct wl1271 *wl = hw->priv;
3363 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003364
John W. Linvilleece550d2010-07-28 16:41:06 -04003365 if (idx != 0)
3366 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003367
John W. Linvilleece550d2010-07-28 16:41:06 -04003368 survey->channel = conf->channel;
3369 survey->filled = SURVEY_INFO_NOISE_DBM;
3370 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003371
John W. Linvilleece550d2010-07-28 16:41:06 -04003372 return 0;
3373}
3374
Arik Nemtsov409622e2011-02-23 00:22:29 +02003375static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003376 struct ieee80211_sta *sta,
3377 u8 *hlid)
3378{
3379 struct wl1271_station *wl_sta;
3380 int id;
3381
3382 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3383 if (id >= AP_MAX_STATIONS) {
3384 wl1271_warning("could not allocate HLID - too much stations");
3385 return -EBUSY;
3386 }
3387
3388 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003389 __set_bit(id, wl->ap_hlid_map);
3390 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3391 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003392 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003393 return 0;
3394}
3395
Arik Nemtsov409622e2011-02-23 00:22:29 +02003396static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003397{
3398 int id = hlid - WL1271_AP_STA_HLID_START;
3399
Arik Nemtsov409622e2011-02-23 00:22:29 +02003400 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3401 return;
3402
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003403 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003404 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003405 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003406 __clear_bit(hlid, &wl->ap_ps_map);
3407 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003408}
3409
3410static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3411 struct ieee80211_vif *vif,
3412 struct ieee80211_sta *sta)
3413{
3414 struct wl1271 *wl = hw->priv;
3415 int ret = 0;
3416 u8 hlid;
3417
3418 mutex_lock(&wl->mutex);
3419
3420 if (unlikely(wl->state == WL1271_STATE_OFF))
3421 goto out;
3422
3423 if (wl->bss_type != BSS_TYPE_AP_BSS)
3424 goto out;
3425
3426 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3427
Arik Nemtsov409622e2011-02-23 00:22:29 +02003428 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003429 if (ret < 0)
3430 goto out;
3431
Ido Yariva6208652011-03-01 15:14:41 +02003432 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003433 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003434 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003435
3436 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3437 if (ret < 0)
3438 goto out_sleep;
3439
3440out_sleep:
3441 wl1271_ps_elp_sleep(wl);
3442
Arik Nemtsov409622e2011-02-23 00:22:29 +02003443out_free_sta:
3444 if (ret < 0)
3445 wl1271_free_sta(wl, hlid);
3446
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003447out:
3448 mutex_unlock(&wl->mutex);
3449 return ret;
3450}
3451
3452static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3453 struct ieee80211_vif *vif,
3454 struct ieee80211_sta *sta)
3455{
3456 struct wl1271 *wl = hw->priv;
3457 struct wl1271_station *wl_sta;
3458 int ret = 0, id;
3459
3460 mutex_lock(&wl->mutex);
3461
3462 if (unlikely(wl->state == WL1271_STATE_OFF))
3463 goto out;
3464
3465 if (wl->bss_type != BSS_TYPE_AP_BSS)
3466 goto out;
3467
3468 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3469
3470 wl_sta = (struct wl1271_station *)sta->drv_priv;
3471 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3472 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3473 goto out;
3474
Ido Yariva6208652011-03-01 15:14:41 +02003475 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003476 if (ret < 0)
3477 goto out;
3478
3479 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3480 if (ret < 0)
3481 goto out_sleep;
3482
Arik Nemtsov409622e2011-02-23 00:22:29 +02003483 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003484
3485out_sleep:
3486 wl1271_ps_elp_sleep(wl);
3487
3488out:
3489 mutex_unlock(&wl->mutex);
3490 return ret;
3491}
3492
Luciano Coelho4623ec72011-03-21 19:26:41 +02003493static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3494 struct ieee80211_vif *vif,
3495 enum ieee80211_ampdu_mlme_action action,
3496 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3497 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003498{
3499 struct wl1271 *wl = hw->priv;
3500 int ret;
3501
3502 mutex_lock(&wl->mutex);
3503
3504 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3505 ret = -EAGAIN;
3506 goto out;
3507 }
3508
Ido Yariva6208652011-03-01 15:14:41 +02003509 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003510 if (ret < 0)
3511 goto out;
3512
Shahar Levi70559a02011-05-22 16:10:22 +03003513 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3514 tid, action);
3515
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003516 switch (action) {
3517 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003518 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003519 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3520 true);
3521 if (!ret)
3522 wl->ba_rx_bitmap |= BIT(tid);
3523 } else {
3524 ret = -ENOTSUPP;
3525 }
3526 break;
3527
3528 case IEEE80211_AMPDU_RX_STOP:
3529 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3530 if (!ret)
3531 wl->ba_rx_bitmap &= ~BIT(tid);
3532 break;
3533
3534 /*
3535 * The BA initiator session management in FW independently.
3536 * Falling break here on purpose for all TX APDU commands.
3537 */
3538 case IEEE80211_AMPDU_TX_START:
3539 case IEEE80211_AMPDU_TX_STOP:
3540 case IEEE80211_AMPDU_TX_OPERATIONAL:
3541 ret = -EINVAL;
3542 break;
3543
3544 default:
3545 wl1271_error("Incorrect ampdu action id=%x\n", action);
3546 ret = -EINVAL;
3547 }
3548
3549 wl1271_ps_elp_sleep(wl);
3550
3551out:
3552 mutex_unlock(&wl->mutex);
3553
3554 return ret;
3555}
3556
Arik Nemtsov33437892011-04-26 23:35:39 +03003557static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3558{
3559 struct wl1271 *wl = hw->priv;
3560 bool ret = false;
3561
3562 mutex_lock(&wl->mutex);
3563
3564 if (unlikely(wl->state == WL1271_STATE_OFF))
3565 goto out;
3566
3567 /* packets are considered pending if in the TX queue or the FW */
3568 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3569
3570 /* the above is appropriate for STA mode for PS purposes */
3571 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3572
3573out:
3574 mutex_unlock(&wl->mutex);
3575
3576 return ret;
3577}
3578
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003579/* can't be const, mac80211 writes to this */
3580static struct ieee80211_rate wl1271_rates[] = {
3581 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003582 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3583 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003584 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003585 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3586 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003587 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3588 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003589 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3590 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003591 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3592 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003593 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3594 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003595 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3596 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003597 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3598 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003599 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003600 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3601 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003602 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003603 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3604 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003605 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003606 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3607 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003608 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003609 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3610 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003611 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003612 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3613 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003614 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003615 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3616 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003617 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003618 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3619 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003620};
3621
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003622/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003623static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003624 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003625 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003626 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3627 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3628 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003629 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003630 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3631 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3632 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003633 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003634 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3635 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3636 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003637 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003638};
3639
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003640/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003641static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003642 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003643 7, /* CONF_HW_RXTX_RATE_MCS7 */
3644 6, /* CONF_HW_RXTX_RATE_MCS6 */
3645 5, /* CONF_HW_RXTX_RATE_MCS5 */
3646 4, /* CONF_HW_RXTX_RATE_MCS4 */
3647 3, /* CONF_HW_RXTX_RATE_MCS3 */
3648 2, /* CONF_HW_RXTX_RATE_MCS2 */
3649 1, /* CONF_HW_RXTX_RATE_MCS1 */
3650 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003651
3652 11, /* CONF_HW_RXTX_RATE_54 */
3653 10, /* CONF_HW_RXTX_RATE_48 */
3654 9, /* CONF_HW_RXTX_RATE_36 */
3655 8, /* CONF_HW_RXTX_RATE_24 */
3656
3657 /* TI-specific rate */
3658 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3659
3660 7, /* CONF_HW_RXTX_RATE_18 */
3661 6, /* CONF_HW_RXTX_RATE_12 */
3662 3, /* CONF_HW_RXTX_RATE_11 */
3663 5, /* CONF_HW_RXTX_RATE_9 */
3664 4, /* CONF_HW_RXTX_RATE_6 */
3665 2, /* CONF_HW_RXTX_RATE_5_5 */
3666 1, /* CONF_HW_RXTX_RATE_2 */
3667 0 /* CONF_HW_RXTX_RATE_1 */
3668};
3669
Shahar Levie8b03a22010-10-13 16:09:39 +02003670/* 11n STA capabilities */
3671#define HW_RX_HIGHEST_RATE 72
3672
Shahar Levi00d20102010-11-08 11:20:10 +00003673#ifdef CONFIG_WL12XX_HT
3674#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003675 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3676 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003677 .ht_supported = true, \
3678 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3679 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3680 .mcs = { \
3681 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3682 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3683 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3684 }, \
3685}
Shahar Levi18357852010-10-13 16:09:41 +02003686#else
Shahar Levi00d20102010-11-08 11:20:10 +00003687#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003688 .ht_supported = false, \
3689}
3690#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692/* can't be const, mac80211 writes to this */
3693static struct ieee80211_supported_band wl1271_band_2ghz = {
3694 .channels = wl1271_channels,
3695 .n_channels = ARRAY_SIZE(wl1271_channels),
3696 .bitrates = wl1271_rates,
3697 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003698 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699};
3700
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003701/* 5 GHz data rates for WL1273 */
3702static struct ieee80211_rate wl1271_rates_5ghz[] = {
3703 { .bitrate = 60,
3704 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3705 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3706 { .bitrate = 90,
3707 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3708 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3709 { .bitrate = 120,
3710 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3711 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3712 { .bitrate = 180,
3713 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3714 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3715 { .bitrate = 240,
3716 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3717 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3718 { .bitrate = 360,
3719 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3720 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3721 { .bitrate = 480,
3722 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3723 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3724 { .bitrate = 540,
3725 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3726 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3727};
3728
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003729/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003730static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003731 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003732 { .hw_value = 8, .center_freq = 5040},
3733 { .hw_value = 9, .center_freq = 5045},
3734 { .hw_value = 11, .center_freq = 5055},
3735 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003736 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003737 { .hw_value = 34, .center_freq = 5170},
3738 { .hw_value = 36, .center_freq = 5180},
3739 { .hw_value = 38, .center_freq = 5190},
3740 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003741 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003742 { .hw_value = 44, .center_freq = 5220},
3743 { .hw_value = 46, .center_freq = 5230},
3744 { .hw_value = 48, .center_freq = 5240},
3745 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003746 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003747 { .hw_value = 60, .center_freq = 5300},
3748 { .hw_value = 64, .center_freq = 5320},
3749 { .hw_value = 100, .center_freq = 5500},
3750 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003751 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003752 { .hw_value = 112, .center_freq = 5560},
3753 { .hw_value = 116, .center_freq = 5580},
3754 { .hw_value = 120, .center_freq = 5600},
3755 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003756 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003757 { .hw_value = 132, .center_freq = 5660},
3758 { .hw_value = 136, .center_freq = 5680},
3759 { .hw_value = 140, .center_freq = 5700},
3760 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003761 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003762 { .hw_value = 157, .center_freq = 5785},
3763 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003764 { .hw_value = 165, .center_freq = 5825},
3765};
3766
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003767/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003768static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003769 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003770 7, /* CONF_HW_RXTX_RATE_MCS7 */
3771 6, /* CONF_HW_RXTX_RATE_MCS6 */
3772 5, /* CONF_HW_RXTX_RATE_MCS5 */
3773 4, /* CONF_HW_RXTX_RATE_MCS4 */
3774 3, /* CONF_HW_RXTX_RATE_MCS3 */
3775 2, /* CONF_HW_RXTX_RATE_MCS2 */
3776 1, /* CONF_HW_RXTX_RATE_MCS1 */
3777 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003778
3779 7, /* CONF_HW_RXTX_RATE_54 */
3780 6, /* CONF_HW_RXTX_RATE_48 */
3781 5, /* CONF_HW_RXTX_RATE_36 */
3782 4, /* CONF_HW_RXTX_RATE_24 */
3783
3784 /* TI-specific rate */
3785 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3786
3787 3, /* CONF_HW_RXTX_RATE_18 */
3788 2, /* CONF_HW_RXTX_RATE_12 */
3789 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3790 1, /* CONF_HW_RXTX_RATE_9 */
3791 0, /* CONF_HW_RXTX_RATE_6 */
3792 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3793 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3794 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3795};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003796
3797static struct ieee80211_supported_band wl1271_band_5ghz = {
3798 .channels = wl1271_channels_5ghz,
3799 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3800 .bitrates = wl1271_rates_5ghz,
3801 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003802 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003803};
3804
Tobias Klausera0ea9492010-05-20 10:38:11 +02003805static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003806 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3807 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3808};
3809
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003810static const struct ieee80211_ops wl1271_ops = {
3811 .start = wl1271_op_start,
3812 .stop = wl1271_op_stop,
3813 .add_interface = wl1271_op_add_interface,
3814 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003815#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003816 .suspend = wl1271_op_suspend,
3817 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003818#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003819 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003820 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003821 .configure_filter = wl1271_op_configure_filter,
3822 .tx = wl1271_op_tx,
3823 .set_key = wl1271_op_set_key,
3824 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003825 .sched_scan_start = wl1271_op_sched_scan_start,
3826 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003827 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003828 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003829 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003830 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003831 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003832 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003833 .sta_add = wl1271_op_sta_add,
3834 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003835 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003836 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003837 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003838};
3839
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003840
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003841u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003842{
3843 u8 idx;
3844
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003845 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003846
3847 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3848 wl1271_error("Illegal RX rate from HW: %d", rate);
3849 return 0;
3850 }
3851
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003852 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003853 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3854 wl1271_error("Unsupported RX rate from HW: %d", rate);
3855 return 0;
3856 }
3857
3858 return idx;
3859}
3860
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003861static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3862 struct device_attribute *attr,
3863 char *buf)
3864{
3865 struct wl1271 *wl = dev_get_drvdata(dev);
3866 ssize_t len;
3867
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003868 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003869
3870 mutex_lock(&wl->mutex);
3871 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3872 wl->sg_enabled);
3873 mutex_unlock(&wl->mutex);
3874
3875 return len;
3876
3877}
3878
3879static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3880 struct device_attribute *attr,
3881 const char *buf, size_t count)
3882{
3883 struct wl1271 *wl = dev_get_drvdata(dev);
3884 unsigned long res;
3885 int ret;
3886
Luciano Coelho6277ed62011-04-01 17:49:54 +03003887 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003888 if (ret < 0) {
3889 wl1271_warning("incorrect value written to bt_coex_mode");
3890 return count;
3891 }
3892
3893 mutex_lock(&wl->mutex);
3894
3895 res = !!res;
3896
3897 if (res == wl->sg_enabled)
3898 goto out;
3899
3900 wl->sg_enabled = res;
3901
3902 if (wl->state == WL1271_STATE_OFF)
3903 goto out;
3904
Ido Yariva6208652011-03-01 15:14:41 +02003905 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003906 if (ret < 0)
3907 goto out;
3908
3909 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3910 wl1271_ps_elp_sleep(wl);
3911
3912 out:
3913 mutex_unlock(&wl->mutex);
3914 return count;
3915}
3916
3917static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3918 wl1271_sysfs_show_bt_coex_state,
3919 wl1271_sysfs_store_bt_coex_state);
3920
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003921static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3922 struct device_attribute *attr,
3923 char *buf)
3924{
3925 struct wl1271 *wl = dev_get_drvdata(dev);
3926 ssize_t len;
3927
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003928 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003929
3930 mutex_lock(&wl->mutex);
3931 if (wl->hw_pg_ver >= 0)
3932 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3933 else
3934 len = snprintf(buf, len, "n/a\n");
3935 mutex_unlock(&wl->mutex);
3936
3937 return len;
3938}
3939
3940static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3941 wl1271_sysfs_show_hw_pg_ver, NULL);
3942
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003943int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003944{
3945 int ret;
3946
3947 if (wl->mac80211_registered)
3948 return 0;
3949
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003950 ret = wl1271_fetch_nvs(wl);
3951 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003952 /* NOTE: The wl->nvs->nvs element must be first, in
3953 * order to simplify the casting, we assume it is at
3954 * the beginning of the wl->nvs structure.
3955 */
3956 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003957
3958 wl->mac_addr[0] = nvs_ptr[11];
3959 wl->mac_addr[1] = nvs_ptr[10];
3960 wl->mac_addr[2] = nvs_ptr[6];
3961 wl->mac_addr[3] = nvs_ptr[5];
3962 wl->mac_addr[4] = nvs_ptr[4];
3963 wl->mac_addr[5] = nvs_ptr[3];
3964 }
3965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003966 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3967
3968 ret = ieee80211_register_hw(wl->hw);
3969 if (ret < 0) {
3970 wl1271_error("unable to register mac80211 hw: %d", ret);
3971 return ret;
3972 }
3973
3974 wl->mac80211_registered = true;
3975
Eliad Pellerd60080a2010-11-24 12:53:16 +02003976 wl1271_debugfs_init(wl);
3977
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003978 register_netdevice_notifier(&wl1271_dev_notifier);
3979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003980 wl1271_notice("loaded");
3981
3982 return 0;
3983}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003984EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003985
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003986void wl1271_unregister_hw(struct wl1271 *wl)
3987{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003988 if (wl->state == WL1271_STATE_PLT)
3989 __wl1271_plt_stop(wl);
3990
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003991 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003992 ieee80211_unregister_hw(wl->hw);
3993 wl->mac80211_registered = false;
3994
3995}
3996EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3997
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003998int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003999{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004000 static const u32 cipher_suites[] = {
4001 WLAN_CIPHER_SUITE_WEP40,
4002 WLAN_CIPHER_SUITE_WEP104,
4003 WLAN_CIPHER_SUITE_TKIP,
4004 WLAN_CIPHER_SUITE_CCMP,
4005 WL1271_CIPHER_SUITE_GEM,
4006 };
4007
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004008 /* The tx descriptor buffer and the TKIP space. */
4009 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4010 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004011
4012 /* unit us */
4013 /* FIXME: find a proper value */
4014 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004015 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004016
4017 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004018 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004019 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004020 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004021 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004022 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004023 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004024 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004025 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004026 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004027
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004028 wl->hw->wiphy->cipher_suites = cipher_suites;
4029 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4030
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004031 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004032 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004033 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004034 /*
4035 * Maximum length of elements in scanning probe request templates
4036 * should be the maximum length possible for a template, without
4037 * the IEEE80211 header of the template
4038 */
4039 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
4040 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004041
Luciano Coelho4a31c112011-03-21 23:16:14 +02004042 /* make sure all our channels fit in the scanned_ch bitmask */
4043 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4044 ARRAY_SIZE(wl1271_channels_5ghz) >
4045 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004046 /*
4047 * We keep local copies of the band structs because we need to
4048 * modify them on a per-device basis.
4049 */
4050 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4051 sizeof(wl1271_band_2ghz));
4052 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4053 sizeof(wl1271_band_5ghz));
4054
4055 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4056 &wl->bands[IEEE80211_BAND_2GHZ];
4057 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4058 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004059
Kalle Valo12bd8942010-03-18 12:26:33 +02004060 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004061 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004062
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004063 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4064
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004065 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004066
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004067 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4068
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004069 wl->hw->max_rx_aggregation_subframes = 8;
4070
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004071 return 0;
4072}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004073EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004074
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004075#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004076
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004077struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004078{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004079 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004080 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004081 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004082 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004083 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004084
4085 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4086 if (!hw) {
4087 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004088 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004089 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004090 }
4091
Julia Lawall929ebd32010-05-15 23:16:39 +02004092 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004093 if (!plat_dev) {
4094 wl1271_error("could not allocate platform_device");
4095 ret = -ENOMEM;
4096 goto err_plat_alloc;
4097 }
4098
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004099 wl = hw->priv;
4100 memset(wl, 0, sizeof(*wl));
4101
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004102 INIT_LIST_HEAD(&wl->list);
4103
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004104 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004105 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004106
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004107 for (i = 0; i < NUM_TX_QUEUES; i++)
4108 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004109
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004110 for (i = 0; i < NUM_TX_QUEUES; i++)
4111 for (j = 0; j < AP_MAX_LINKS; j++)
4112 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4113
Ido Yariva6208652011-03-01 15:14:41 +02004114 skb_queue_head_init(&wl->deferred_rx_queue);
4115 skb_queue_head_init(&wl->deferred_tx_queue);
4116
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004117 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004118 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004119 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004120 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4121 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4122 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004123 INIT_WORK(&wl->rx_streaming_enable_work,
4124 wl1271_rx_streaming_enable_work);
4125 INIT_WORK(&wl->rx_streaming_disable_work,
4126 wl1271_rx_streaming_disable_work);
4127
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004128 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004129 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004130 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004131 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02004132 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
4133 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004134 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004135 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004136 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004137 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004138 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004139 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004140 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004141 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004142 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004143 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004144 wl->bss_type = MAX_BSS_TYPE;
4145 wl->set_bss_type = MAX_BSS_TYPE;
4146 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004147 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004148 wl->ap_ps_map = 0;
4149 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004150 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004151 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004152 wl->sched_scanning = false;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004153 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4154 (unsigned long) wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004155
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004156 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004157 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004158 wl->tx_frames[i] = NULL;
4159
4160 spin_lock_init(&wl->wl_lock);
4161
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004162 wl->state = WL1271_STATE_OFF;
4163 mutex_init(&wl->mutex);
4164
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004165 /* Apply default driver configuration. */
4166 wl1271_conf_init(wl);
4167
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004168 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4169 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4170 if (!wl->aggr_buf) {
4171 ret = -ENOMEM;
4172 goto err_hw;
4173 }
4174
Ido Yariv990f5de2011-03-31 10:06:59 +02004175 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4176 if (!wl->dummy_packet) {
4177 ret = -ENOMEM;
4178 goto err_aggr;
4179 }
4180
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004181 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004182 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004183 if (ret) {
4184 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004185 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004186 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004187 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004188
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004189 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004190 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004191 if (ret < 0) {
4192 wl1271_error("failed to create sysfs file bt_coex_state");
4193 goto err_platform;
4194 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004195
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004196 /* Create sysfs file to get HW PG version */
4197 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4198 if (ret < 0) {
4199 wl1271_error("failed to create sysfs file hw_pg_ver");
4200 goto err_bt_coex_state;
4201 }
4202
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004203 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004204
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004205err_bt_coex_state:
4206 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4207
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004208err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004209 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004210
Ido Yariv990f5de2011-03-31 10:06:59 +02004211err_dummy_packet:
4212 dev_kfree_skb(wl->dummy_packet);
4213
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004214err_aggr:
4215 free_pages((unsigned long)wl->aggr_buf, order);
4216
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004217err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004218 wl1271_debugfs_exit(wl);
4219 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004220
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004221err_plat_alloc:
4222 ieee80211_free_hw(hw);
4223
4224err_hw_alloc:
4225
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004226 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004227}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004228EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004229
4230int wl1271_free_hw(struct wl1271 *wl)
4231{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004232 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004233 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004234 free_pages((unsigned long)wl->aggr_buf,
4235 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004236 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004237
4238 wl1271_debugfs_exit(wl);
4239
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004240 vfree(wl->fw);
4241 wl->fw = NULL;
4242 kfree(wl->nvs);
4243 wl->nvs = NULL;
4244
4245 kfree(wl->fw_status);
4246 kfree(wl->tx_res_if);
4247
4248 ieee80211_free_hw(wl->hw);
4249
4250 return 0;
4251}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004252EXPORT_SYMBOL_GPL(wl1271_free_hw);
4253
Guy Eilam491bbd62011-01-12 10:33:29 +01004254u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004255EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004256module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004257MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4258
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004259MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004260MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004261MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");