blob: fa6b996d7d4d1be4ad37cfb2b9bfedae851649b3 [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 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200309 .rf = {
310 .tx_per_channel_power_compensation_2 = {
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 },
313 .tx_per_channel_power_compensation_5 = {
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 },
318 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100319 .ht = {
320 .tx_ba_win_size = 64,
321 .inactivity_timeout = 10000,
322 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200323 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200324 .num_stations = 1,
325 .ssid_profiles = 1,
326 .rx_block_num = 70,
327 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300328 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200329 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200330 .min_req_rx_blocks = 22,
331 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200332 },
333 .mem_wl128x = {
334 .num_stations = 1,
335 .ssid_profiles = 1,
336 .rx_block_num = 40,
337 .tx_min_block_num = 40,
338 .dynamic_memory = 1,
339 .min_req_tx_blocks = 45,
340 .min_req_rx_blocks = 22,
341 .tx_min = 27,
342 },
Shahar Leviff868432011-04-11 15:41:46 +0300343 .fm_coex = {
344 .enable = true,
345 .swallow_period = 5,
346 .n_divider_fref_set_1 = 0xff, /* default */
347 .n_divider_fref_set_2 = 12,
348 .m_divider_fref_set_1 = 148,
349 .m_divider_fref_set_2 = 0xffff, /* default */
350 .coex_pll_stabilization_time = 0xffffffff, /* default */
351 .ldo_stabilization_time = 0xffff, /* default */
352 .fm_disturbed_band_margin = 0xff, /* default */
353 .swallow_clk_diff = 0xff, /* default */
354 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300355 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300356};
357
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300358static void __wl1271_op_remove_interface(struct wl1271 *wl,
359 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200360static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200361
362
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200363static void wl1271_device_release(struct device *dev)
364{
365
366}
367
368static struct platform_device wl1271_device = {
369 .name = "wl1271",
370 .id = -1,
371
372 /* device model insists to have a release function */
373 .dev = {
374 .release = wl1271_device_release,
375 },
376};
377
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200378static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300379static LIST_HEAD(wl_list);
380
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300381static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
382 void *arg)
383{
384 struct net_device *dev = arg;
385 struct wireless_dev *wdev;
386 struct wiphy *wiphy;
387 struct ieee80211_hw *hw;
388 struct wl1271 *wl;
389 struct wl1271 *wl_temp;
390 int ret = 0;
391
392 /* Check that this notification is for us. */
393 if (what != NETDEV_CHANGE)
394 return NOTIFY_DONE;
395
396 wdev = dev->ieee80211_ptr;
397 if (wdev == NULL)
398 return NOTIFY_DONE;
399
400 wiphy = wdev->wiphy;
401 if (wiphy == NULL)
402 return NOTIFY_DONE;
403
404 hw = wiphy_priv(wiphy);
405 if (hw == NULL)
406 return NOTIFY_DONE;
407
408 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200409 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410 list_for_each_entry(wl, &wl_list, list) {
411 if (wl == wl_temp)
412 break;
413 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200414 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300415 if (wl != wl_temp)
416 return NOTIFY_DONE;
417
418 mutex_lock(&wl->mutex);
419
420 if (wl->state == WL1271_STATE_OFF)
421 goto out;
422
423 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
424 goto out;
425
Ido Yariva6208652011-03-01 15:14:41 +0200426 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300427 if (ret < 0)
428 goto out;
429
430 if ((dev->operstate == IF_OPER_UP) &&
431 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
432 wl1271_cmd_set_sta_state(wl);
433 wl1271_info("Association completed.");
434 }
435
436 wl1271_ps_elp_sleep(wl);
437
438out:
439 mutex_unlock(&wl->mutex);
440
441 return NOTIFY_OK;
442}
443
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100444static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200445 struct regulatory_request *request)
446{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100447 struct ieee80211_supported_band *band;
448 struct ieee80211_channel *ch;
449 int i;
450
451 band = wiphy->bands[IEEE80211_BAND_5GHZ];
452 for (i = 0; i < band->n_channels; i++) {
453 ch = &band->channels[i];
454 if (ch->flags & IEEE80211_CHAN_DISABLED)
455 continue;
456
457 if (ch->flags & IEEE80211_CHAN_RADAR)
458 ch->flags |= IEEE80211_CHAN_NO_IBSS |
459 IEEE80211_CHAN_PASSIVE_SCAN;
460
461 }
462
463 return 0;
464}
465
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300466static void wl1271_conf_init(struct wl1271 *wl)
467{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300468
469 /*
470 * This function applies the default configuration to the driver. This
471 * function is invoked upon driver load (spi probe.)
472 *
473 * The configuration is stored in a run-time structure in order to
474 * facilitate for run-time adjustment of any of the parameters. Making
475 * changes to the configuration structure will apply the new values on
476 * the next interface up (wl1271_op_start.)
477 */
478
479 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300480 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300481}
482
483
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300484static int wl1271_plt_init(struct wl1271 *wl)
485{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200486 struct conf_tx_ac_category *conf_ac;
487 struct conf_tx_tid *conf_tid;
488 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300489
Shahar Levi49d750ca2011-03-06 16:32:09 +0200490 if (wl->chip.id == CHIP_ID_1283_PG20)
491 ret = wl128x_cmd_general_parms(wl);
492 else
493 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200494 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200495 return ret;
496
Shahar Levi49d750ca2011-03-06 16:32:09 +0200497 if (wl->chip.id == CHIP_ID_1283_PG20)
498 ret = wl128x_cmd_radio_parms(wl);
499 else
500 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200501 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200502 return ret;
503
Shahar Levi49d750ca2011-03-06 16:32:09 +0200504 if (wl->chip.id != CHIP_ID_1283_PG20) {
505 ret = wl1271_cmd_ext_radio_parms(wl);
506 if (ret < 0)
507 return ret;
508 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200509 if (ret < 0)
510 return ret;
511
Shahar Levi48a61472011-03-06 16:32:08 +0200512 /* Chip-specific initializations */
513 ret = wl1271_chip_specific_init(wl);
514 if (ret < 0)
515 return ret;
516
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200517 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200518 if (ret < 0)
519 return ret;
520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300521 ret = wl1271_acx_init_mem_config(wl);
522 if (ret < 0)
523 return ret;
524
Luciano Coelho12419cc2010-02-18 13:25:44 +0200525 /* PHY layer config */
526 ret = wl1271_init_phy_config(wl);
527 if (ret < 0)
528 goto out_free_memmap;
529
530 ret = wl1271_acx_dco_itrim_params(wl);
531 if (ret < 0)
532 goto out_free_memmap;
533
534 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200535 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200536 if (ret < 0)
537 goto out_free_memmap;
538
539 /* Bluetooth WLAN coexistence */
540 ret = wl1271_init_pta(wl);
541 if (ret < 0)
542 goto out_free_memmap;
543
Shahar Leviff868432011-04-11 15:41:46 +0300544 /* FM WLAN coexistence */
545 ret = wl1271_acx_fm_coex(wl);
546 if (ret < 0)
547 goto out_free_memmap;
548
Luciano Coelho12419cc2010-02-18 13:25:44 +0200549 /* Energy detection */
550 ret = wl1271_init_energy_detection(wl);
551 if (ret < 0)
552 goto out_free_memmap;
553
Gery Kahn1ec610e2011-02-01 03:03:08 -0600554 ret = wl1271_acx_sta_mem_cfg(wl);
555 if (ret < 0)
556 goto out_free_memmap;
557
Luciano Coelho12419cc2010-02-18 13:25:44 +0200558 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100559 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200560 if (ret < 0)
561 goto out_free_memmap;
562
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200563 /* Default TID/AC configuration */
564 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200565 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200566 conf_ac = &wl->conf.tx.ac_conf[i];
567 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
568 conf_ac->cw_max, conf_ac->aifsn,
569 conf_ac->tx_op_limit);
570 if (ret < 0)
571 goto out_free_memmap;
572
Luciano Coelho12419cc2010-02-18 13:25:44 +0200573 conf_tid = &wl->conf.tx.tid_conf[i];
574 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
575 conf_tid->channel_type,
576 conf_tid->tsid,
577 conf_tid->ps_scheme,
578 conf_tid->ack_policy,
579 conf_tid->apsd_conf[0],
580 conf_tid->apsd_conf[1]);
581 if (ret < 0)
582 goto out_free_memmap;
583 }
584
Luciano Coelho12419cc2010-02-18 13:25:44 +0200585 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200586 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300587 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200588 goto out_free_memmap;
589
590 /* Configure for CAM power saving (ie. always active) */
591 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
592 if (ret < 0)
593 goto out_free_memmap;
594
595 /* configure PM */
596 ret = wl1271_acx_pm_config(wl);
597 if (ret < 0)
598 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300599
600 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200601
602 out_free_memmap:
603 kfree(wl->target_mem_map);
604 wl->target_mem_map = NULL;
605
606 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300607}
608
Arik Nemtsovb622d992011-02-23 00:22:31 +0200609static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
610{
611 bool fw_ps;
612
613 /* only regulate station links */
614 if (hlid < WL1271_AP_STA_HLID_START)
615 return;
616
617 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
618
619 /*
620 * Wake up from high level PS if the STA is asleep with too little
621 * blocks in FW or if the STA is awake.
622 */
623 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
624 wl1271_ps_link_end(wl, hlid);
625
626 /* Start high-level PS if the STA is asleep with enough blocks in FW */
627 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
628 wl1271_ps_link_start(wl, hlid, true);
629}
630
631static void wl1271_irq_update_links_status(struct wl1271 *wl,
632 struct wl1271_fw_ap_status *status)
633{
634 u32 cur_fw_ps_map;
635 u8 hlid;
636
637 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
638 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
639 wl1271_debug(DEBUG_PSM,
640 "link ps prev 0x%x cur 0x%x changed 0x%x",
641 wl->ap_fw_ps_map, cur_fw_ps_map,
642 wl->ap_fw_ps_map ^ cur_fw_ps_map);
643
644 wl->ap_fw_ps_map = cur_fw_ps_map;
645 }
646
647 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
648 u8 cnt = status->tx_lnk_free_blks[hlid] -
649 wl->links[hlid].prev_freed_blks;
650
651 wl->links[hlid].prev_freed_blks =
652 status->tx_lnk_free_blks[hlid];
653 wl->links[hlid].allocated_blks -= cnt;
654
655 wl1271_irq_ps_regulate_link(wl, hlid,
656 wl->links[hlid].allocated_blks);
657 }
658}
659
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300660static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200661 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200663 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200664 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200665 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200666 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300667 int i;
668
Shahar Levi13b107d2011-03-06 16:32:12 +0200669 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200670 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
671 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200672 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200673 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
674 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200675 }
676
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
678 "drv_rx_counter = %d, tx_results_counter = %d)",
679 status->intr,
680 status->fw_rx_counter,
681 status->drv_rx_counter,
682 status->tx_results_counter);
683
684 /* update number of available TX blocks */
685 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200686 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
687 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300688
689 wl->tx_blocks_freed[i] =
690 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200691 }
692
Ido Yarivd2f4d472011-03-31 10:07:00 +0200693 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200694
Ido Yarivd2f4d472011-03-31 10:07:00 +0200695 if (wl->bss_type == BSS_TYPE_AP_BSS) {
696 /* Update num of allocated TX blocks per link and ps status */
697 wl1271_irq_update_links_status(wl, &full_status->ap);
698 wl->tx_blocks_available += freed_blocks;
699 } else {
700 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
701
702 /*
703 * The FW might change the total number of TX memblocks before
704 * we get a notification about blocks being released. Thus, the
705 * available blocks calculation might yield a temporary result
706 * which is lower than the actual available blocks. Keeping in
707 * mind that only blocks that were allocated can be moved from
708 * TX to RX, tx_blocks_available should never decrease here.
709 */
710 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
711 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712 }
713
Ido Yariva5225502010-10-12 14:49:10 +0200714 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200715 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200716 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300717
718 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200719 getnstimeofday(&ts);
720 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
721 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300722}
723
Ido Yariva6208652011-03-01 15:14:41 +0200724static void wl1271_flush_deferred_work(struct wl1271 *wl)
725{
726 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200727
Ido Yariva6208652011-03-01 15:14:41 +0200728 /* Pass all received frames to the network stack */
729 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
730 ieee80211_rx_ni(wl->hw, skb);
731
732 /* Return sent skbs to the network stack */
733 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
734 ieee80211_tx_status(wl->hw, skb);
735}
736
737static void wl1271_netstack_work(struct work_struct *work)
738{
739 struct wl1271 *wl =
740 container_of(work, struct wl1271, netstack_work);
741
742 do {
743 wl1271_flush_deferred_work(wl);
744 } while (skb_queue_len(&wl->deferred_rx_queue));
745}
746
747#define WL1271_IRQ_MAX_LOOPS 256
748
749irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300750{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300751 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300752 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200753 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200754 struct wl1271 *wl = (struct wl1271 *)cookie;
755 bool done = false;
756 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200757 unsigned long flags;
758
759 /* TX might be handled here, avoid redundant work */
760 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
761 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300762
Ido Yariv341b7cd2011-03-31 10:07:01 +0200763 /*
764 * In case edge triggered interrupt must be used, we cannot iterate
765 * more than once without introducing race conditions with the hardirq.
766 */
767 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
768 loopcount = 1;
769
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300770 mutex_lock(&wl->mutex);
771
772 wl1271_debug(DEBUG_IRQ, "IRQ work");
773
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200774 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775 goto out;
776
Ido Yariva6208652011-03-01 15:14:41 +0200777 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300778 if (ret < 0)
779 goto out;
780
Ido Yariva6208652011-03-01 15:14:41 +0200781 while (!done && loopcount--) {
782 /*
783 * In order to avoid a race with the hardirq, clear the flag
784 * before acknowledging the chip. Since the mutex is held,
785 * wl1271_ps_elp_wakeup cannot be called concurrently.
786 */
787 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
788 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200789
790 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200791 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200792 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200793 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200794 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200795 continue;
796 }
797
Eliad Pellerccc83b02010-10-27 14:09:57 +0200798 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
799 wl1271_error("watchdog interrupt received! "
800 "starting recovery.");
801 ieee80211_queue_work(wl->hw, &wl->recovery_work);
802
803 /* restarting the chip. ignore any other interrupt. */
804 goto out;
805 }
806
Ido Yariva6208652011-03-01 15:14:41 +0200807 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200808 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
809
Ido Yariv8aad2462011-03-01 15:14:38 +0200810 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200811
Ido Yariva5225502010-10-12 14:49:10 +0200812 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200813 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200814 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200815 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200816 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200817 /*
818 * In order to avoid starvation of the TX path,
819 * call the work function directly.
820 */
821 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200822 } else {
823 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200824 }
825
Ido Yariv8aad2462011-03-01 15:14:38 +0200826 /* check for tx results */
827 if (wl->fw_status->common.tx_results_counter !=
828 (wl->tx_results_count & 0xff))
829 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200830
831 /* Make sure the deferred queues don't get too long */
832 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
833 skb_queue_len(&wl->deferred_rx_queue);
834 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
835 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200836 }
837
838 if (intr & WL1271_ACX_INTR_EVENT_A) {
839 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
840 wl1271_event_handle(wl, 0);
841 }
842
843 if (intr & WL1271_ACX_INTR_EVENT_B) {
844 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
845 wl1271_event_handle(wl, 1);
846 }
847
848 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
849 wl1271_debug(DEBUG_IRQ,
850 "WL1271_ACX_INTR_INIT_COMPLETE");
851
852 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
853 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854 }
855
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856 wl1271_ps_elp_sleep(wl);
857
858out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200859 spin_lock_irqsave(&wl->wl_lock, flags);
860 /* In case TX was not handled here, queue TX work */
861 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
862 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
863 wl->tx_queue_count)
864 ieee80211_queue_work(wl->hw, &wl->tx_work);
865 spin_unlock_irqrestore(&wl->wl_lock, flags);
866
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200868
869 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300870}
Ido Yariva6208652011-03-01 15:14:41 +0200871EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873static int wl1271_fetch_firmware(struct wl1271 *wl)
874{
875 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200876 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300877 int ret;
878
Arik Nemtsov166d5042010-10-16 21:44:57 +0200879 switch (wl->bss_type) {
880 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200881 if (wl->chip.id == CHIP_ID_1283_PG20)
882 fw_name = WL128X_AP_FW_NAME;
883 else
884 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200885 break;
886 case BSS_TYPE_IBSS:
887 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200888 if (wl->chip.id == CHIP_ID_1283_PG20)
889 fw_name = WL128X_FW_NAME;
890 else
891 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200892 break;
893 default:
894 wl1271_error("no compatible firmware for bss_type %d",
895 wl->bss_type);
896 return -EINVAL;
897 }
898
899 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
900
901 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902
903 if (ret < 0) {
904 wl1271_error("could not get firmware: %d", ret);
905 return ret;
906 }
907
908 if (fw->size % 4) {
909 wl1271_error("firmware size is not multiple of 32 bits: %zu",
910 fw->size);
911 ret = -EILSEQ;
912 goto out;
913 }
914
Arik Nemtsov166d5042010-10-16 21:44:57 +0200915 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300916 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300917 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300918
919 if (!wl->fw) {
920 wl1271_error("could not allocate memory for the firmware");
921 ret = -ENOMEM;
922 goto out;
923 }
924
925 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200926 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927 ret = 0;
928
929out:
930 release_firmware(fw);
931
932 return ret;
933}
934
935static int wl1271_fetch_nvs(struct wl1271 *wl)
936{
937 const struct firmware *fw;
938 int ret;
939
Shahar Levi5aa42342011-03-06 16:32:07 +0200940 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941
942 if (ret < 0) {
943 wl1271_error("could not get nvs file: %d", ret);
944 return ret;
945 }
946
Shahar Levibc765bf2011-03-06 16:32:10 +0200947 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948
949 if (!wl->nvs) {
950 wl1271_error("could not allocate memory for the nvs file");
951 ret = -ENOMEM;
952 goto out;
953 }
954
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200955 wl->nvs_len = fw->size;
956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957out:
958 release_firmware(fw);
959
960 return ret;
961}
962
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200963static void wl1271_recovery_work(struct work_struct *work)
964{
965 struct wl1271 *wl =
966 container_of(work, struct wl1271, recovery_work);
967
968 mutex_lock(&wl->mutex);
969
970 if (wl->state != WL1271_STATE_ON)
971 goto out;
972
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300973 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
974 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200975
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200976 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
977 ieee80211_connection_loss(wl->vif);
978
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300979 /* Prevent spurious TX during FW restart */
980 ieee80211_stop_queues(wl->hw);
981
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200982 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300983 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200984 ieee80211_restart_hw(wl->hw);
985
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300986 /*
987 * Its safe to enable TX now - the queues are stopped after a request
988 * to restart the HW.
989 */
990 ieee80211_wake_queues(wl->hw);
991
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200992out:
993 mutex_unlock(&wl->mutex);
994}
995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996static void wl1271_fw_wakeup(struct wl1271 *wl)
997{
998 u32 elp_reg;
999
1000 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001001 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002}
1003
1004static int wl1271_setup(struct wl1271 *wl)
1005{
1006 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1007 if (!wl->fw_status)
1008 return -ENOMEM;
1009
1010 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1011 if (!wl->tx_res_if) {
1012 kfree(wl->fw_status);
1013 return -ENOMEM;
1014 }
1015
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 return 0;
1017}
1018
1019static int wl1271_chip_wakeup(struct wl1271 *wl)
1020{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001021 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 int ret = 0;
1023
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001024 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001025 ret = wl1271_power_on(wl);
1026 if (ret < 0)
1027 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001028 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001029 wl1271_io_reset(wl);
1030 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031
1032 /* We don't need a real memory partition here, because we only want
1033 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001034 memset(&partition, 0, sizeof(partition));
1035 partition.reg.start = REGISTERS_BASE;
1036 partition.reg.size = REGISTERS_DOWN_SIZE;
1037 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038
1039 /* ELP module wake up */
1040 wl1271_fw_wakeup(wl);
1041
1042 /* whal_FwCtrl_BootSm() */
1043
1044 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001045 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
1047 /* 1. check if chip id is valid */
1048
1049 switch (wl->chip.id) {
1050 case CHIP_ID_1271_PG10:
1051 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1052 wl->chip.id);
1053
1054 ret = wl1271_setup(wl);
1055 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001056 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 break;
1058 case CHIP_ID_1271_PG20:
1059 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1060 wl->chip.id);
1061
Shahar Levi564f5952011-04-04 10:20:39 +03001062 /* end-of-transaction flag should be set in wl127x AP mode */
1063 if (wl->bss_type == BSS_TYPE_AP_BSS)
1064 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1065
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 ret = wl1271_setup(wl);
1067 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001068 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001069 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001070 case CHIP_ID_1283_PG20:
1071 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1072 wl->chip.id);
1073
1074 ret = wl1271_setup(wl);
1075 if (ret < 0)
1076 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001077 if (wl1271_set_block_size(wl))
1078 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001079 break;
1080 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001082 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001084 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001085 }
1086
Arik Nemtsov166d5042010-10-16 21:44:57 +02001087 /* Make sure the firmware type matches the BSS type */
1088 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089 ret = wl1271_fetch_firmware(wl);
1090 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001091 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 }
1093
1094 /* No NVS from netlink, try to get it from the filesystem */
1095 if (wl->nvs == NULL) {
1096 ret = wl1271_fetch_nvs(wl);
1097 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001098 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 }
1100
1101out:
1102 return ret;
1103}
1104
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001105static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1106{
1107 unsigned int quirks = 0;
1108 unsigned int *fw_ver = wl->chip.fw_ver;
1109
1110 /* Only for wl127x */
1111 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1112 /* Check STA version */
1113 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1114 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1115 /* Check AP version */
1116 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1117 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1118 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1119
1120 return quirks;
1121}
1122
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001123int wl1271_plt_start(struct wl1271 *wl)
1124{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001125 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001126 int ret;
1127
1128 mutex_lock(&wl->mutex);
1129
1130 wl1271_notice("power up");
1131
1132 if (wl->state != WL1271_STATE_OFF) {
1133 wl1271_error("cannot go into PLT state because not "
1134 "in off state: %d", wl->state);
1135 ret = -EBUSY;
1136 goto out;
1137 }
1138
Arik Nemtsov166d5042010-10-16 21:44:57 +02001139 wl->bss_type = BSS_TYPE_STA_BSS;
1140
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001141 while (retries) {
1142 retries--;
1143 ret = wl1271_chip_wakeup(wl);
1144 if (ret < 0)
1145 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001146
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001147 ret = wl1271_boot(wl);
1148 if (ret < 0)
1149 goto power_off;
1150
1151 ret = wl1271_plt_init(wl);
1152 if (ret < 0)
1153 goto irq_disable;
1154
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001155 wl->state = WL1271_STATE_PLT;
1156 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001157 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001158
1159 /* Check if any quirks are needed with older fw versions */
1160 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001161 goto out;
1162
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001163irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001164 mutex_unlock(&wl->mutex);
1165 /* Unlocking the mutex in the middle of handling is
1166 inherently unsafe. In this case we deem it safe to do,
1167 because we need to let any possibly pending IRQ out of
1168 the system (and while we are WL1271_STATE_OFF the IRQ
1169 work function will not do anything.) Also, any other
1170 possible concurrent operations will fail due to the
1171 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001172 wl1271_disable_interrupts(wl);
1173 wl1271_flush_deferred_work(wl);
1174 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001175 mutex_lock(&wl->mutex);
1176power_off:
1177 wl1271_power_off(wl);
1178 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001179
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001180 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1181 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001182out:
1183 mutex_unlock(&wl->mutex);
1184
1185 return ret;
1186}
1187
Luciano Coelho4623ec72011-03-21 19:26:41 +02001188static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001189{
1190 int ret = 0;
1191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001192 wl1271_notice("power down");
1193
1194 if (wl->state != WL1271_STATE_PLT) {
1195 wl1271_error("cannot power down because not in PLT "
1196 "state: %d", wl->state);
1197 ret = -EBUSY;
1198 goto out;
1199 }
1200
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 wl1271_power_off(wl);
1202
1203 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001204 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001205
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001207 wl1271_disable_interrupts(wl);
1208 wl1271_flush_deferred_work(wl);
1209 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001211 mutex_lock(&wl->mutex);
1212out:
1213 return ret;
1214}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001215
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001216int wl1271_plt_stop(struct wl1271 *wl)
1217{
1218 int ret;
1219
1220 mutex_lock(&wl->mutex);
1221 ret = __wl1271_plt_stop(wl);
1222 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001223 return ret;
1224}
1225
Johannes Berg7bb45682011-02-24 14:42:06 +01001226static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001227{
1228 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001229 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001230 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001231 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232
Ido Yarivb07d4032011-03-01 15:14:43 +02001233 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1234
1235 if (wl->bss_type == BSS_TYPE_AP_BSS)
1236 hlid = wl1271_tx_get_hlid(skb);
1237
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001238 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001239
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001240 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001241
1242 /*
1243 * The workqueue is slow to process the tx_queue and we need stop
1244 * the queue here, otherwise the queue will get too long.
1245 */
1246 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1247 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1248 ieee80211_stop_queues(wl->hw);
1249 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1250 }
1251
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001252 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001253 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001254 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1255 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1256 } else {
1257 skb_queue_tail(&wl->tx_queue[q], skb);
1258 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001259
1260 /*
1261 * The chip specific setup must run before the first TX packet -
1262 * before that, the tx_work will not be initialized!
1263 */
1264
Ido Yarivb07d4032011-03-01 15:14:43 +02001265 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1266 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001267 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001268
1269 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270}
1271
Shahar Leviae47c452011-03-06 16:32:14 +02001272int wl1271_tx_dummy_packet(struct wl1271 *wl)
1273{
Ido Yariv990f5de2011-03-31 10:06:59 +02001274 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001275
Ido Yariv990f5de2011-03-31 10:06:59 +02001276 spin_lock_irqsave(&wl->wl_lock, flags);
1277 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1278 wl->tx_queue_count++;
1279 spin_unlock_irqrestore(&wl->wl_lock, flags);
1280
1281 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1282 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1283 wl1271_tx_work_locked(wl);
1284
1285 /*
1286 * If the FW TX is busy, TX work will be scheduled by the threaded
1287 * interrupt handler function
1288 */
1289 return 0;
1290}
1291
1292/*
1293 * The size of the dummy packet should be at least 1400 bytes. However, in
1294 * order to minimize the number of bus transactions, aligning it to 512 bytes
1295 * boundaries could be beneficial, performance wise
1296 */
1297#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1298
Luciano Coelhocf27d862011-04-01 21:08:23 +03001299static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001300{
1301 struct sk_buff *skb;
1302 struct ieee80211_hdr_3addr *hdr;
1303 unsigned int dummy_packet_size;
1304
1305 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1306 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1307
1308 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001309 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001310 wl1271_warning("Failed to allocate a dummy packet skb");
1311 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001312 }
1313
1314 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1315
1316 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1317 memset(hdr, 0, sizeof(*hdr));
1318 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001319 IEEE80211_STYPE_NULLFUNC |
1320 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001321
Ido Yariv990f5de2011-03-31 10:06:59 +02001322 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001323
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001324 /* Dummy packets require the TID to be management */
1325 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001326
1327 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001328 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001329 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001330
Ido Yariv990f5de2011-03-31 10:06:59 +02001331 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001332}
1333
Ido Yariv990f5de2011-03-31 10:06:59 +02001334
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001335static struct notifier_block wl1271_dev_notifier = {
1336 .notifier_call = wl1271_dev_notify,
1337};
1338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339static int wl1271_op_start(struct ieee80211_hw *hw)
1340{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001341 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1342
1343 /*
1344 * We have to delay the booting of the hardware because
1345 * we need to know the local MAC address before downloading and
1346 * initializing the firmware. The MAC address cannot be changed
1347 * after boot, and without the proper MAC address, the firmware
1348 * will not function properly.
1349 *
1350 * The MAC address is first known when the corresponding interface
1351 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001352 *
1353 * In addition, we currently have different firmwares for AP and managed
1354 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001355 */
1356
1357 return 0;
1358}
1359
1360static void wl1271_op_stop(struct ieee80211_hw *hw)
1361{
1362 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1363}
1364
1365static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1366 struct ieee80211_vif *vif)
1367{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001369 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001371 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001372 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001374 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1375 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376
1377 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001378 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001379 wl1271_debug(DEBUG_MAC80211,
1380 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001381 ret = -EBUSY;
1382 goto out;
1383 }
1384
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001385 /*
1386 * in some very corner case HW recovery scenarios its possible to
1387 * get here before __wl1271_op_remove_interface is complete, so
1388 * opt out if that is the case.
1389 */
1390 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1391 ret = -EBUSY;
1392 goto out;
1393 }
1394
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001395 switch (vif->type) {
1396 case NL80211_IFTYPE_STATION:
1397 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001398 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001399 break;
1400 case NL80211_IFTYPE_ADHOC:
1401 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001402 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001403 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001404 case NL80211_IFTYPE_AP:
1405 wl->bss_type = BSS_TYPE_AP_BSS;
1406 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001407 default:
1408 ret = -EOPNOTSUPP;
1409 goto out;
1410 }
1411
1412 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001413
1414 if (wl->state != WL1271_STATE_OFF) {
1415 wl1271_error("cannot start because not in off state: %d",
1416 wl->state);
1417 ret = -EBUSY;
1418 goto out;
1419 }
1420
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001421 while (retries) {
1422 retries--;
1423 ret = wl1271_chip_wakeup(wl);
1424 if (ret < 0)
1425 goto power_off;
1426
1427 ret = wl1271_boot(wl);
1428 if (ret < 0)
1429 goto power_off;
1430
1431 ret = wl1271_hw_init(wl);
1432 if (ret < 0)
1433 goto irq_disable;
1434
Eliad Peller71125ab2010-10-28 21:46:43 +02001435 booted = true;
1436 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001437
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001438irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 mutex_unlock(&wl->mutex);
1440 /* Unlocking the mutex in the middle of handling is
1441 inherently unsafe. In this case we deem it safe to do,
1442 because we need to let any possibly pending IRQ out of
1443 the system (and while we are WL1271_STATE_OFF the IRQ
1444 work function will not do anything.) Also, any other
1445 possible concurrent operations will fail due to the
1446 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001447 wl1271_disable_interrupts(wl);
1448 wl1271_flush_deferred_work(wl);
1449 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001450 mutex_lock(&wl->mutex);
1451power_off:
1452 wl1271_power_off(wl);
1453 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001454
Eliad Peller71125ab2010-10-28 21:46:43 +02001455 if (!booted) {
1456 wl1271_error("firmware boot failed despite %d retries",
1457 WL1271_BOOT_RETRIES);
1458 goto out;
1459 }
1460
1461 wl->vif = vif;
1462 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001463 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001464 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001465
1466 /* update hw/fw version info in wiphy struct */
1467 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001468 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001469 sizeof(wiphy->fw_version));
1470
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001471 /* Check if any quirks are needed with older fw versions */
1472 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1473
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001474 /*
1475 * Now we know if 11a is supported (info from the NVS), so disable
1476 * 11a channels if not supported
1477 */
1478 if (!wl->enable_11a)
1479 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1480
1481 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1482 wl->enable_11a ? "" : "not ");
1483
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001484out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485 mutex_unlock(&wl->mutex);
1486
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001487 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001488 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001489 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001490 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001491
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 return ret;
1493}
1494
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001495static void __wl1271_op_remove_interface(struct wl1271 *wl,
1496 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001498 int i;
1499
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001500 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001502 /* because of hardware recovery, we may get here twice */
1503 if (wl->state != WL1271_STATE_ON)
1504 return;
1505
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001506 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001508 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001509 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001510 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001511
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001512 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001513 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001514 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001515
Luciano Coelho08688d62010-07-08 17:50:07 +03001516 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001517 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001518 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001519 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001520 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521 }
1522
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001523 /*
1524 * this must be before the cancel_work calls below, so that the work
1525 * functions don't perform further work.
1526 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001527 wl->state = WL1271_STATE_OFF;
1528
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 mutex_unlock(&wl->mutex);
1530
Ido Yariva6208652011-03-01 15:14:41 +02001531 wl1271_disable_interrupts(wl);
1532 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001533 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001534 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001535 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001536 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001537 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538
1539 mutex_lock(&wl->mutex);
1540
1541 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001542 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001543 wl1271_power_off(wl);
1544
1545 memset(wl->bssid, 0, ETH_ALEN);
1546 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1547 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001549 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001550 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001551
1552 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001553 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001554 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1555 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001556 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 wl->tx_results_count = 0;
1558 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001559 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001560 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001561 wl->time_offset = 0;
1562 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001563 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001564 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001565 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001566 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001567 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001568 wl->ap_fw_ps_map = 0;
1569 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001570
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001571 /*
1572 * this is performed after the cancel_work calls and the associated
1573 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1574 * get executed before all these vars have been reset.
1575 */
1576 wl->flags = 0;
1577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001578 for (i = 0; i < NUM_TX_QUEUES; i++)
1579 wl->tx_blocks_freed[i] = 0;
1580
1581 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001582
1583 kfree(wl->fw_status);
1584 wl->fw_status = NULL;
1585 kfree(wl->tx_res_if);
1586 wl->tx_res_if = NULL;
1587 kfree(wl->target_mem_map);
1588 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001589}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001590
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001591static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1592 struct ieee80211_vif *vif)
1593{
1594 struct wl1271 *wl = hw->priv;
1595
1596 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001597 /*
1598 * wl->vif can be null here if someone shuts down the interface
1599 * just when hardware recovery has been started.
1600 */
1601 if (wl->vif) {
1602 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001603 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001604 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001605
Juuso Oikarinen67353292010-11-18 15:19:02 +02001606 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001607 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001608}
1609
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001610void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001611{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001612 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001613
1614 /* combine requested filters with current filter config */
1615 filters = wl->filters | filters;
1616
1617 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1618
1619 if (filters & FIF_PROMISC_IN_BSS) {
1620 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1621 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1622 wl->rx_config |= CFG_BSSID_FILTER_EN;
1623 }
1624 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1625 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1626 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1627 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1628 }
1629 if (filters & FIF_OTHER_BSS) {
1630 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1631 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1632 }
1633 if (filters & FIF_CONTROL) {
1634 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1635 wl->rx_filter |= CFG_RX_CTL_EN;
1636 }
1637 if (filters & FIF_FCSFAIL) {
1638 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1639 wl->rx_filter |= CFG_RX_FCS_ERROR;
1640 }
1641}
1642
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001643static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001644{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001645 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001646 /* we need to use a dummy BSSID for now */
1647 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1648 0xad, 0xbe, 0xef };
1649
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001650 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1651
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001652 /* pass through frames from all BSS */
1653 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1654
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001655 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001656 if (ret < 0)
1657 goto out;
1658
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001659 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001660
1661out:
1662 return ret;
1663}
1664
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001665static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001666{
1667 int ret;
1668
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001669 /*
1670 * One of the side effects of the JOIN command is that is clears
1671 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1672 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001673 * Currently the only valid scenario for JOIN during association
1674 * is on roaming, in which case we will also be given new keys.
1675 * Keep the below message for now, unless it starts bothering
1676 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001677 */
1678 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1679 wl1271_info("JOIN while associated.");
1680
1681 if (set_assoc)
1682 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1683
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001684 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1685 if (ret < 0)
1686 goto out;
1687
1688 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1689
1690 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1691 goto out;
1692
1693 /*
1694 * The join command disable the keep-alive mode, shut down its process,
1695 * and also clear the template config, so we need to reset it all after
1696 * the join. The acx_aid starts the keep-alive process, and the order
1697 * of the commands below is relevant.
1698 */
1699 ret = wl1271_acx_keep_alive_mode(wl, true);
1700 if (ret < 0)
1701 goto out;
1702
1703 ret = wl1271_acx_aid(wl, wl->aid);
1704 if (ret < 0)
1705 goto out;
1706
1707 ret = wl1271_cmd_build_klv_null_data(wl);
1708 if (ret < 0)
1709 goto out;
1710
1711 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1712 ACX_KEEP_ALIVE_TPL_VALID);
1713 if (ret < 0)
1714 goto out;
1715
1716out:
1717 return ret;
1718}
1719
1720static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001721{
1722 int ret;
1723
1724 /* to stop listening to a channel, we disconnect */
1725 ret = wl1271_cmd_disconnect(wl);
1726 if (ret < 0)
1727 goto out;
1728
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001729 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001730 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001731
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001732 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001733 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001734
1735out:
1736 return ret;
1737}
1738
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001739static void wl1271_set_band_rate(struct wl1271 *wl)
1740{
1741 if (wl->band == IEEE80211_BAND_2GHZ)
1742 wl->basic_rate_set = wl->conf.tx.basic_rate;
1743 else
1744 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1745}
1746
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001747static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001748{
1749 int ret;
1750
1751 if (idle) {
1752 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1753 ret = wl1271_unjoin(wl);
1754 if (ret < 0)
1755 goto out;
1756 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001757 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001758 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001759 if (ret < 0)
1760 goto out;
1761 ret = wl1271_acx_keep_alive_config(
1762 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1763 ACX_KEEP_ALIVE_TPL_INVALID);
1764 if (ret < 0)
1765 goto out;
1766 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1767 } else {
1768 /* increment the session counter */
1769 wl->session_counter++;
1770 if (wl->session_counter >= SESSION_COUNTER_MAX)
1771 wl->session_counter = 0;
1772 ret = wl1271_dummy_join(wl);
1773 if (ret < 0)
1774 goto out;
1775 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1776 }
1777
1778out:
1779 return ret;
1780}
1781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1783{
1784 struct wl1271 *wl = hw->priv;
1785 struct ieee80211_conf *conf = &hw->conf;
1786 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001787 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001788
1789 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1790
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001791 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1792 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001793 channel,
1794 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001795 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001796 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1797 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001798
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001799 /*
1800 * mac80211 will go to idle nearly immediately after transmitting some
1801 * frames, such as the deauth. To make sure those frames reach the air,
1802 * wait here until the TX queue is fully flushed.
1803 */
1804 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1805 (conf->flags & IEEE80211_CONF_IDLE))
1806 wl1271_tx_flush(wl);
1807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808 mutex_lock(&wl->mutex);
1809
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001810 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001811 /* we support configuring the channel and band while off */
1812 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1813 wl->band = conf->channel->band;
1814 wl->channel = channel;
1815 }
1816
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001817 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001818 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001819
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001820 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1821
Ido Yariva6208652011-03-01 15:14:41 +02001822 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 if (ret < 0)
1824 goto out;
1825
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001826 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001827 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1828 ((wl->band != conf->channel->band) ||
1829 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001830 wl->band = conf->channel->band;
1831 wl->channel = channel;
1832
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001833 if (!is_ap) {
1834 /*
1835 * FIXME: the mac80211 should really provide a fixed
1836 * rate to use here. for now, just use the smallest
1837 * possible rate for the band as a fixed rate for
1838 * association frames and other control messages.
1839 */
1840 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1841 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001842
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001843 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1844 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001845 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001846 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001847 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001848
1849 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1850 ret = wl1271_join(wl, false);
1851 if (ret < 0)
1852 wl1271_warning("cmd join on channel "
1853 "failed %d", ret);
1854 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001855 }
1856 }
1857
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001858 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1859 ret = wl1271_sta_handle_idle(wl,
1860 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001861 if (ret < 0)
1862 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001863 }
1864
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001865 /*
1866 * if mac80211 changes the PSM mode, make sure the mode is not
1867 * incorrectly changed after the pspoll failure active window.
1868 */
1869 if (changed & IEEE80211_CONF_CHANGE_PS)
1870 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1871
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001872 if (conf->flags & IEEE80211_CONF_PS &&
1873 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1874 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001875
1876 /*
1877 * We enter PSM only if we're already associated.
1878 * If we're not, we'll enter it when joining an SSID,
1879 * through the bss_info_changed() hook.
1880 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001881 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001882 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001883 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001884 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001885 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001886 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001887 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001888 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001889
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001890 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001891
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001892 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001893 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001894 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895 }
1896
1897 if (conf->power_level != wl->power_level) {
1898 ret = wl1271_acx_tx_power(wl, conf->power_level);
1899 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001900 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001901
1902 wl->power_level = conf->power_level;
1903 }
1904
1905out_sleep:
1906 wl1271_ps_elp_sleep(wl);
1907
1908out:
1909 mutex_unlock(&wl->mutex);
1910
1911 return ret;
1912}
1913
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001914struct wl1271_filter_params {
1915 bool enabled;
1916 int mc_list_length;
1917 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1918};
1919
Jiri Pirko22bedad2010-04-01 21:22:57 +00001920static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1921 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001922{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001923 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001924 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001925 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001926
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001927 if (unlikely(wl->state == WL1271_STATE_OFF))
1928 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001929
Juuso Oikarinen74441132009-10-13 12:47:53 +03001930 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001931 if (!fp) {
1932 wl1271_error("Out of memory setting filters.");
1933 return 0;
1934 }
1935
1936 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001937 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001938 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1939 fp->enabled = false;
1940 } else {
1941 fp->enabled = true;
1942 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001943 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00001944 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001945 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00001946 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001947 }
1948
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001949 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001950}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001951
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001952#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1953 FIF_ALLMULTI | \
1954 FIF_FCSFAIL | \
1955 FIF_BCN_PRBRESP_PROMISC | \
1956 FIF_CONTROL | \
1957 FIF_OTHER_BSS)
1958
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1960 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001961 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001962{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001963 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001965 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966
Arik Nemtsov7d057862010-10-16 19:25:35 +02001967 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1968 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001970 mutex_lock(&wl->mutex);
1971
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001972 *total &= WL1271_SUPPORTED_FILTERS;
1973 changed &= WL1271_SUPPORTED_FILTERS;
1974
1975 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001976 goto out;
1977
Ido Yariva6208652011-03-01 15:14:41 +02001978 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001979 if (ret < 0)
1980 goto out;
1981
Arik Nemtsov7d057862010-10-16 19:25:35 +02001982 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1983 if (*total & FIF_ALLMULTI)
1984 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1985 else if (fp)
1986 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1987 fp->mc_list,
1988 fp->mc_list_length);
1989 if (ret < 0)
1990 goto out_sleep;
1991 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001992
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001993 /* determine, whether supported filter values have changed */
1994 if (changed == 0)
1995 goto out_sleep;
1996
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001997 /* configure filters */
1998 wl->filters = *total;
1999 wl1271_configure_filters(wl, 0);
2000
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002001 /* apply configured filters */
2002 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2003 if (ret < 0)
2004 goto out_sleep;
2005
2006out_sleep:
2007 wl1271_ps_elp_sleep(wl);
2008
2009out:
2010 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002011 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002012}
2013
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002014static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2015 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2016 u16 tx_seq_16)
2017{
2018 struct wl1271_ap_key *ap_key;
2019 int i;
2020
2021 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2022
2023 if (key_size > MAX_KEY_SIZE)
2024 return -EINVAL;
2025
2026 /*
2027 * Find next free entry in ap_keys. Also check we are not replacing
2028 * an existing key.
2029 */
2030 for (i = 0; i < MAX_NUM_KEYS; i++) {
2031 if (wl->recorded_ap_keys[i] == NULL)
2032 break;
2033
2034 if (wl->recorded_ap_keys[i]->id == id) {
2035 wl1271_warning("trying to record key replacement");
2036 return -EINVAL;
2037 }
2038 }
2039
2040 if (i == MAX_NUM_KEYS)
2041 return -EBUSY;
2042
2043 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2044 if (!ap_key)
2045 return -ENOMEM;
2046
2047 ap_key->id = id;
2048 ap_key->key_type = key_type;
2049 ap_key->key_size = key_size;
2050 memcpy(ap_key->key, key, key_size);
2051 ap_key->hlid = hlid;
2052 ap_key->tx_seq_32 = tx_seq_32;
2053 ap_key->tx_seq_16 = tx_seq_16;
2054
2055 wl->recorded_ap_keys[i] = ap_key;
2056 return 0;
2057}
2058
2059static void wl1271_free_ap_keys(struct wl1271 *wl)
2060{
2061 int i;
2062
2063 for (i = 0; i < MAX_NUM_KEYS; i++) {
2064 kfree(wl->recorded_ap_keys[i]);
2065 wl->recorded_ap_keys[i] = NULL;
2066 }
2067}
2068
2069static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2070{
2071 int i, ret = 0;
2072 struct wl1271_ap_key *key;
2073 bool wep_key_added = false;
2074
2075 for (i = 0; i < MAX_NUM_KEYS; i++) {
2076 if (wl->recorded_ap_keys[i] == NULL)
2077 break;
2078
2079 key = wl->recorded_ap_keys[i];
2080 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2081 key->id, key->key_type,
2082 key->key_size, key->key,
2083 key->hlid, key->tx_seq_32,
2084 key->tx_seq_16);
2085 if (ret < 0)
2086 goto out;
2087
2088 if (key->key_type == KEY_WEP)
2089 wep_key_added = true;
2090 }
2091
2092 if (wep_key_added) {
2093 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2094 if (ret < 0)
2095 goto out;
2096 }
2097
2098out:
2099 wl1271_free_ap_keys(wl);
2100 return ret;
2101}
2102
2103static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2104 u8 key_size, const u8 *key, u32 tx_seq_32,
2105 u16 tx_seq_16, struct ieee80211_sta *sta)
2106{
2107 int ret;
2108 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2109
2110 if (is_ap) {
2111 struct wl1271_station *wl_sta;
2112 u8 hlid;
2113
2114 if (sta) {
2115 wl_sta = (struct wl1271_station *)sta->drv_priv;
2116 hlid = wl_sta->hlid;
2117 } else {
2118 hlid = WL1271_AP_BROADCAST_HLID;
2119 }
2120
2121 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2122 /*
2123 * We do not support removing keys after AP shutdown.
2124 * Pretend we do to make mac80211 happy.
2125 */
2126 if (action != KEY_ADD_OR_REPLACE)
2127 return 0;
2128
2129 ret = wl1271_record_ap_key(wl, id,
2130 key_type, key_size,
2131 key, hlid, tx_seq_32,
2132 tx_seq_16);
2133 } else {
2134 ret = wl1271_cmd_set_ap_key(wl, action,
2135 id, key_type, key_size,
2136 key, hlid, tx_seq_32,
2137 tx_seq_16);
2138 }
2139
2140 if (ret < 0)
2141 return ret;
2142 } else {
2143 const u8 *addr;
2144 static const u8 bcast_addr[ETH_ALEN] = {
2145 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2146 };
2147
2148 addr = sta ? sta->addr : bcast_addr;
2149
2150 if (is_zero_ether_addr(addr)) {
2151 /* We dont support TX only encryption */
2152 return -EOPNOTSUPP;
2153 }
2154
2155 /* The wl1271 does not allow to remove unicast keys - they
2156 will be cleared automatically on next CMD_JOIN. Ignore the
2157 request silently, as we dont want the mac80211 to emit
2158 an error message. */
2159 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2160 return 0;
2161
2162 ret = wl1271_cmd_set_sta_key(wl, action,
2163 id, key_type, key_size,
2164 key, addr, tx_seq_32,
2165 tx_seq_16);
2166 if (ret < 0)
2167 return ret;
2168
2169 /* the default WEP key needs to be configured at least once */
2170 if (key_type == KEY_WEP) {
2171 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2172 wl->default_key);
2173 if (ret < 0)
2174 return ret;
2175 }
2176 }
2177
2178 return 0;
2179}
2180
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2182 struct ieee80211_vif *vif,
2183 struct ieee80211_sta *sta,
2184 struct ieee80211_key_conf *key_conf)
2185{
2186 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002187 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002188 u32 tx_seq_32 = 0;
2189 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190 u8 key_type;
2191
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2193
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002194 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002195 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002196 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197 key_conf->keylen, key_conf->flags);
2198 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2199
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200 mutex_lock(&wl->mutex);
2201
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002202 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2203 ret = -EAGAIN;
2204 goto out_unlock;
2205 }
2206
Ido Yariva6208652011-03-01 15:14:41 +02002207 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002208 if (ret < 0)
2209 goto out_unlock;
2210
Johannes Berg97359d12010-08-10 09:46:38 +02002211 switch (key_conf->cipher) {
2212 case WLAN_CIPHER_SUITE_WEP40:
2213 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002214 key_type = KEY_WEP;
2215
2216 key_conf->hw_key_idx = key_conf->keyidx;
2217 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002218 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002219 key_type = KEY_TKIP;
2220
2221 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002222 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2223 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002224 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002225 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226 key_type = KEY_AES;
2227
2228 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002229 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2230 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002232 case WL1271_CIPHER_SUITE_GEM:
2233 key_type = KEY_GEM;
2234 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2235 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2236 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002237 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002238 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239
2240 ret = -EOPNOTSUPP;
2241 goto out_sleep;
2242 }
2243
2244 switch (cmd) {
2245 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002246 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2247 key_conf->keyidx, key_type,
2248 key_conf->keylen, key_conf->key,
2249 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002250 if (ret < 0) {
2251 wl1271_error("Could not add or replace key");
2252 goto out_sleep;
2253 }
2254 break;
2255
2256 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002257 ret = wl1271_set_key(wl, KEY_REMOVE,
2258 key_conf->keyidx, key_type,
2259 key_conf->keylen, key_conf->key,
2260 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002261 if (ret < 0) {
2262 wl1271_error("Could not remove key");
2263 goto out_sleep;
2264 }
2265 break;
2266
2267 default:
2268 wl1271_error("Unsupported key cmd 0x%x", cmd);
2269 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270 break;
2271 }
2272
2273out_sleep:
2274 wl1271_ps_elp_sleep(wl);
2275
2276out_unlock:
2277 mutex_unlock(&wl->mutex);
2278
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279 return ret;
2280}
2281
2282static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002283 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284 struct cfg80211_scan_request *req)
2285{
2286 struct wl1271 *wl = hw->priv;
2287 int ret;
2288 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002289 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290
2291 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2292
2293 if (req->n_ssids) {
2294 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002295 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296 }
2297
2298 mutex_lock(&wl->mutex);
2299
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002300 if (wl->state == WL1271_STATE_OFF) {
2301 /*
2302 * We cannot return -EBUSY here because cfg80211 will expect
2303 * a call to ieee80211_scan_completed if we do - in this case
2304 * there won't be any call.
2305 */
2306 ret = -EAGAIN;
2307 goto out;
2308 }
2309
Ido Yariva6208652011-03-01 15:14:41 +02002310 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002311 if (ret < 0)
2312 goto out;
2313
Luciano Coelho5924f892010-08-04 03:46:22 +03002314 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002315
2316 wl1271_ps_elp_sleep(wl);
2317
2318out:
2319 mutex_unlock(&wl->mutex);
2320
2321 return ret;
2322}
2323
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002324static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2325{
2326 struct wl1271 *wl = hw->priv;
2327 int ret = 0;
2328
2329 mutex_lock(&wl->mutex);
2330
2331 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2332 ret = -EAGAIN;
2333 goto out;
2334 }
2335
Ido Yariva6208652011-03-01 15:14:41 +02002336 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002337 if (ret < 0)
2338 goto out;
2339
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002340 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002341 if (ret < 0)
2342 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2343
2344 wl1271_ps_elp_sleep(wl);
2345
2346out:
2347 mutex_unlock(&wl->mutex);
2348
2349 return ret;
2350}
2351
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002352static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2353{
2354 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002355 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356
2357 mutex_lock(&wl->mutex);
2358
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002359 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2360 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002361 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002362 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002363
Ido Yariva6208652011-03-01 15:14:41 +02002364 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 if (ret < 0)
2366 goto out;
2367
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002368 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369 if (ret < 0)
2370 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2371
2372 wl1271_ps_elp_sleep(wl);
2373
2374out:
2375 mutex_unlock(&wl->mutex);
2376
2377 return ret;
2378}
2379
Arik Nemtsove78a2872010-10-16 19:07:21 +02002380static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002381 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002382{
Eliad Peller889cb362011-05-01 09:56:45 +03002383 u8 ssid_len;
2384 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2385 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002386
Eliad Peller889cb362011-05-01 09:56:45 +03002387 if (!ptr) {
2388 wl1271_error("No SSID in IEs!");
2389 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002390 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002391
Eliad Peller889cb362011-05-01 09:56:45 +03002392 ssid_len = ptr[1];
2393 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2394 wl1271_error("SSID is too long!");
2395 return -EINVAL;
2396 }
2397
2398 wl->ssid_len = ssid_len;
2399 memcpy(wl->ssid, ptr+2, ssid_len);
2400 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002401}
2402
Arik Nemtsove78a2872010-10-16 19:07:21 +02002403static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2404 struct ieee80211_bss_conf *bss_conf,
2405 u32 changed)
2406{
2407 int ret = 0;
2408
2409 if (changed & BSS_CHANGED_ERP_SLOT) {
2410 if (bss_conf->use_short_slot)
2411 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2412 else
2413 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2414 if (ret < 0) {
2415 wl1271_warning("Set slot time failed %d", ret);
2416 goto out;
2417 }
2418 }
2419
2420 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2421 if (bss_conf->use_short_preamble)
2422 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2423 else
2424 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2425 }
2426
2427 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2428 if (bss_conf->use_cts_prot)
2429 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2430 else
2431 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2432 if (ret < 0) {
2433 wl1271_warning("Set ctsprotect failed %d", ret);
2434 goto out;
2435 }
2436 }
2437
2438out:
2439 return ret;
2440}
2441
2442static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2443 struct ieee80211_vif *vif,
2444 struct ieee80211_bss_conf *bss_conf,
2445 u32 changed)
2446{
2447 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2448 int ret = 0;
2449
2450 if ((changed & BSS_CHANGED_BEACON_INT)) {
2451 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2452 bss_conf->beacon_int);
2453
2454 wl->beacon_int = bss_conf->beacon_int;
2455 }
2456
2457 if ((changed & BSS_CHANGED_BEACON)) {
2458 struct ieee80211_hdr *hdr;
2459 int ieoffset = offsetof(struct ieee80211_mgmt,
2460 u.beacon.variable);
2461 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2462 u16 tmpl_id;
2463
2464 if (!beacon)
2465 goto out;
2466
2467 wl1271_debug(DEBUG_MASTER, "beacon updated");
2468
2469 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2470 if (ret < 0) {
2471 dev_kfree_skb(beacon);
2472 goto out;
2473 }
2474 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2475 CMD_TEMPL_BEACON;
2476 ret = wl1271_cmd_template_set(wl, tmpl_id,
2477 beacon->data,
2478 beacon->len, 0,
2479 wl1271_tx_min_rate_get(wl));
2480 if (ret < 0) {
2481 dev_kfree_skb(beacon);
2482 goto out;
2483 }
2484
2485 hdr = (struct ieee80211_hdr *) beacon->data;
2486 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2487 IEEE80211_STYPE_PROBE_RESP);
2488
2489 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2490 CMD_TEMPL_PROBE_RESPONSE;
2491 ret = wl1271_cmd_template_set(wl,
2492 tmpl_id,
2493 beacon->data,
2494 beacon->len, 0,
2495 wl1271_tx_min_rate_get(wl));
2496 dev_kfree_skb(beacon);
2497 if (ret < 0)
2498 goto out;
2499 }
2500
2501out:
2502 return ret;
2503}
2504
2505/* AP mode changes */
2506static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507 struct ieee80211_vif *vif,
2508 struct ieee80211_bss_conf *bss_conf,
2509 u32 changed)
2510{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002511 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002512
Arik Nemtsove78a2872010-10-16 19:07:21 +02002513 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2514 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515
Arik Nemtsove78a2872010-10-16 19:07:21 +02002516 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2517 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002518
Arik Nemtsov70f47422011-04-18 14:15:25 +03002519 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002520 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002521 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002522 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002523 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002524
2525 ret = wl1271_ap_init_templates(wl);
2526 if (ret < 0)
2527 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002528 }
2529
Arik Nemtsove78a2872010-10-16 19:07:21 +02002530 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2531 if (ret < 0)
2532 goto out;
2533
2534 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2535 if (bss_conf->enable_beacon) {
2536 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2537 ret = wl1271_cmd_start_bss(wl);
2538 if (ret < 0)
2539 goto out;
2540
2541 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2542 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002543
2544 ret = wl1271_ap_init_hwenc(wl);
2545 if (ret < 0)
2546 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002547 }
2548 } else {
2549 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2550 ret = wl1271_cmd_stop_bss(wl);
2551 if (ret < 0)
2552 goto out;
2553
2554 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2555 wl1271_debug(DEBUG_AP, "stopped AP");
2556 }
2557 }
2558 }
2559
Eliad Pellercb5ae052011-04-07 15:52:05 +03002560 if (changed & BSS_CHANGED_IBSS) {
2561 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2562 bss_conf->ibss_joined);
2563
2564 if (bss_conf->ibss_joined) {
2565 u32 rates = bss_conf->basic_rates;
2566 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2567 rates);
2568 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2569
2570 /* by default, use 11b rates */
2571 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2572 ret = wl1271_acx_sta_rate_policies(wl);
2573 if (ret < 0)
2574 goto out;
2575 }
2576 }
2577
Arik Nemtsove78a2872010-10-16 19:07:21 +02002578 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2579 if (ret < 0)
2580 goto out;
2581out:
2582 return;
2583}
2584
2585/* STA/IBSS mode changes */
2586static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2587 struct ieee80211_vif *vif,
2588 struct ieee80211_bss_conf *bss_conf,
2589 u32 changed)
2590{
2591 bool do_join = false, set_assoc = false;
2592 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002593 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002594 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002595 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002596 bool sta_exists = false;
2597 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002598
2599 if (is_ibss) {
2600 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2601 changed);
2602 if (ret < 0)
2603 goto out;
2604 }
2605
2606 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2607 do_join = true;
2608
2609 /* Need to update the SSID (for filtering etc) */
2610 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2611 do_join = true;
2612
2613 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002614 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2615 bss_conf->enable_beacon ? "enabled" : "disabled");
2616
2617 if (bss_conf->enable_beacon)
2618 wl->set_bss_type = BSS_TYPE_IBSS;
2619 else
2620 wl->set_bss_type = BSS_TYPE_STA_BSS;
2621 do_join = true;
2622 }
2623
Arik Nemtsove78a2872010-10-16 19:07:21 +02002624 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002625 bool enable = false;
2626 if (bss_conf->cqm_rssi_thold)
2627 enable = true;
2628 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2629 bss_conf->cqm_rssi_thold,
2630 bss_conf->cqm_rssi_hyst);
2631 if (ret < 0)
2632 goto out;
2633 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2634 }
2635
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002636 if ((changed & BSS_CHANGED_BSSID) &&
2637 /*
2638 * Now we know the correct bssid, so we send a new join command
2639 * and enable the BSSID filter
2640 */
2641 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002642 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002643
Eliad Pellerfa287b82010-12-26 09:27:50 +01002644 if (!is_zero_ether_addr(wl->bssid)) {
2645 ret = wl1271_cmd_build_null_data(wl);
2646 if (ret < 0)
2647 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002648
Eliad Pellerfa287b82010-12-26 09:27:50 +01002649 ret = wl1271_build_qos_null_data(wl);
2650 if (ret < 0)
2651 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002652
Eliad Pellerfa287b82010-12-26 09:27:50 +01002653 /* filter out all packets not from this BSSID */
2654 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002655
Eliad Pellerfa287b82010-12-26 09:27:50 +01002656 /* Need to update the BSSID (for filtering etc) */
2657 do_join = true;
2658 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002659 }
2660
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002661 rcu_read_lock();
2662 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2663 if (sta) {
2664 /* save the supp_rates of the ap */
2665 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2666 if (sta->ht_cap.ht_supported)
2667 sta_rate_set |=
2668 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002669 sta_ht_cap = sta->ht_cap;
2670 sta_exists = true;
2671 }
2672 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002673
Arik Nemtsova1008852011-02-12 23:24:20 +02002674 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002675 /* handle new association with HT and HT information change */
2676 if ((changed & BSS_CHANGED_HT) &&
2677 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002678 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002679 true);
2680 if (ret < 0) {
2681 wl1271_warning("Set ht cap true failed %d",
2682 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002683 goto out;
2684 }
2685 ret = wl1271_acx_set_ht_information(wl,
2686 bss_conf->ht_operation_mode);
2687 if (ret < 0) {
2688 wl1271_warning("Set ht information failed %d",
2689 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002690 goto out;
2691 }
2692 }
2693 /* handle new association without HT and disassociation */
2694 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002695 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002696 false);
2697 if (ret < 0) {
2698 wl1271_warning("Set ht cap false failed %d",
2699 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002700 goto out;
2701 }
2702 }
2703 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002704
Arik Nemtsove78a2872010-10-16 19:07:21 +02002705 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002707 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002708 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002710 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002711
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002712 wl->ps_poll_failures = 0;
2713
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002714 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002715 * use basic rates from AP, and determine lowest rate
2716 * to use with control frames.
2717 */
2718 rates = bss_conf->basic_rates;
2719 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2720 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002721 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002722 if (sta_rate_set)
2723 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2724 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002725 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002726 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002727 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002728
2729 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002730 * with wl1271, we don't need to update the
2731 * beacon_int and dtim_period, because the firmware
2732 * updates it by itself when the first beacon is
2733 * received after a join.
2734 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2736 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002737 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002739 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002740 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002741 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002742 dev_kfree_skb(wl->probereq);
2743 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2744 ieoffset = offsetof(struct ieee80211_mgmt,
2745 u.probe_req.variable);
2746 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002747
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002748 /* enable the connection monitoring feature */
2749 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002750 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002751 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752
2753 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002754 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2755 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002756 enum wl1271_cmd_ps_mode mode;
2757
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002759 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002760 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002761 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002762 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002763 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002764 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002765 } else {
2766 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002767 bool was_assoc =
2768 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2769 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002770 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002771 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002772
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002773 /* free probe-request template */
2774 dev_kfree_skb(wl->probereq);
2775 wl->probereq = NULL;
2776
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002777 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002778 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002779
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002780 /* revert back to minimum rates for the current band */
2781 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002782 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002783 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002784 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002785 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002786
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002787 /* disable connection monitor features */
2788 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002789
2790 /* Disable the keep-alive feature */
2791 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002792 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002793 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002794
2795 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002796 if (was_assoc) {
2797 wl1271_unjoin(wl);
2798 wl1271_dummy_join(wl);
2799 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002800 }
2801 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002802
Arik Nemtsove78a2872010-10-16 19:07:21 +02002803 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2804 if (ret < 0)
2805 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002806
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002807 if (changed & BSS_CHANGED_ARP_FILTER) {
2808 __be32 addr = bss_conf->arp_addr_list[0];
2809 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2810
Eliad Pellerc5312772010-12-09 11:31:27 +02002811 if (bss_conf->arp_addr_cnt == 1 &&
2812 bss_conf->arp_filter_enabled) {
2813 /*
2814 * The template should have been configured only upon
2815 * association. however, it seems that the correct ip
2816 * isn't being set (when sending), so we have to
2817 * reconfigure the template upon every ip change.
2818 */
2819 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2820 if (ret < 0) {
2821 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002822 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002823 }
2824
2825 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002826 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002827 addr);
2828 } else
2829 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002830
2831 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002832 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002833 }
2834
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002835 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002836 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002837 if (ret < 0) {
2838 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002839 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002840 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002841 }
2842
Arik Nemtsove78a2872010-10-16 19:07:21 +02002843out:
2844 return;
2845}
2846
2847static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2848 struct ieee80211_vif *vif,
2849 struct ieee80211_bss_conf *bss_conf,
2850 u32 changed)
2851{
2852 struct wl1271 *wl = hw->priv;
2853 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2854 int ret;
2855
2856 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2857 (int)changed);
2858
2859 mutex_lock(&wl->mutex);
2860
2861 if (unlikely(wl->state == WL1271_STATE_OFF))
2862 goto out;
2863
Ido Yariva6208652011-03-01 15:14:41 +02002864 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002865 if (ret < 0)
2866 goto out;
2867
2868 if (is_ap)
2869 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2870 else
2871 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2872
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002873 wl1271_ps_elp_sleep(wl);
2874
2875out:
2876 mutex_unlock(&wl->mutex);
2877}
2878
Kalle Valoc6999d82010-02-18 13:25:41 +02002879static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2880 const struct ieee80211_tx_queue_params *params)
2881{
2882 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002883 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002884 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002885
2886 mutex_lock(&wl->mutex);
2887
2888 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2889
Kalle Valo4695dc92010-03-18 12:26:38 +02002890 if (params->uapsd)
2891 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2892 else
2893 ps_scheme = CONF_PS_SCHEME_LEGACY;
2894
Arik Nemtsov488fc542010-10-16 20:33:45 +02002895 if (wl->state == WL1271_STATE_OFF) {
2896 /*
2897 * If the state is off, the parameters will be recorded and
2898 * configured on init. This happens in AP-mode.
2899 */
2900 struct conf_tx_ac_category *conf_ac =
2901 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2902 struct conf_tx_tid *conf_tid =
2903 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2904
2905 conf_ac->ac = wl1271_tx_get_queue(queue);
2906 conf_ac->cw_min = (u8)params->cw_min;
2907 conf_ac->cw_max = params->cw_max;
2908 conf_ac->aifsn = params->aifs;
2909 conf_ac->tx_op_limit = params->txop << 5;
2910
2911 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2912 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2913 conf_tid->tsid = wl1271_tx_get_queue(queue);
2914 conf_tid->ps_scheme = ps_scheme;
2915 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2916 conf_tid->apsd_conf[0] = 0;
2917 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002918 goto out;
2919 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002920
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002921 ret = wl1271_ps_elp_wakeup(wl);
2922 if (ret < 0)
2923 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002924
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002925 /*
2926 * the txop is confed in units of 32us by the mac80211,
2927 * we need us
2928 */
2929 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2930 params->cw_min, params->cw_max,
2931 params->aifs, params->txop << 5);
2932 if (ret < 0)
2933 goto out_sleep;
2934
2935 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2936 CONF_CHANNEL_TYPE_EDCF,
2937 wl1271_tx_get_queue(queue),
2938 ps_scheme, CONF_ACK_POLICY_LEGACY,
2939 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002940
2941out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002942 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002943
2944out:
2945 mutex_unlock(&wl->mutex);
2946
2947 return ret;
2948}
2949
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002950static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2951{
2952
2953 struct wl1271 *wl = hw->priv;
2954 u64 mactime = ULLONG_MAX;
2955 int ret;
2956
2957 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2958
2959 mutex_lock(&wl->mutex);
2960
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002961 if (unlikely(wl->state == WL1271_STATE_OFF))
2962 goto out;
2963
Ido Yariva6208652011-03-01 15:14:41 +02002964 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002965 if (ret < 0)
2966 goto out;
2967
2968 ret = wl1271_acx_tsf_info(wl, &mactime);
2969 if (ret < 0)
2970 goto out_sleep;
2971
2972out_sleep:
2973 wl1271_ps_elp_sleep(wl);
2974
2975out:
2976 mutex_unlock(&wl->mutex);
2977 return mactime;
2978}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979
John W. Linvilleece550d2010-07-28 16:41:06 -04002980static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2981 struct survey_info *survey)
2982{
2983 struct wl1271 *wl = hw->priv;
2984 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002985
John W. Linvilleece550d2010-07-28 16:41:06 -04002986 if (idx != 0)
2987 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002988
John W. Linvilleece550d2010-07-28 16:41:06 -04002989 survey->channel = conf->channel;
2990 survey->filled = SURVEY_INFO_NOISE_DBM;
2991 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002992
John W. Linvilleece550d2010-07-28 16:41:06 -04002993 return 0;
2994}
2995
Arik Nemtsov409622e2011-02-23 00:22:29 +02002996static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002997 struct ieee80211_sta *sta,
2998 u8 *hlid)
2999{
3000 struct wl1271_station *wl_sta;
3001 int id;
3002
3003 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3004 if (id >= AP_MAX_STATIONS) {
3005 wl1271_warning("could not allocate HLID - too much stations");
3006 return -EBUSY;
3007 }
3008
3009 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003010 __set_bit(id, wl->ap_hlid_map);
3011 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3012 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003013 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003014 return 0;
3015}
3016
Arik Nemtsov409622e2011-02-23 00:22:29 +02003017static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003018{
3019 int id = hlid - WL1271_AP_STA_HLID_START;
3020
Arik Nemtsov409622e2011-02-23 00:22:29 +02003021 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3022 return;
3023
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003024 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003025 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003026 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003027 __clear_bit(hlid, &wl->ap_ps_map);
3028 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003029}
3030
3031static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3032 struct ieee80211_vif *vif,
3033 struct ieee80211_sta *sta)
3034{
3035 struct wl1271 *wl = hw->priv;
3036 int ret = 0;
3037 u8 hlid;
3038
3039 mutex_lock(&wl->mutex);
3040
3041 if (unlikely(wl->state == WL1271_STATE_OFF))
3042 goto out;
3043
3044 if (wl->bss_type != BSS_TYPE_AP_BSS)
3045 goto out;
3046
3047 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3048
Arik Nemtsov409622e2011-02-23 00:22:29 +02003049 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003050 if (ret < 0)
3051 goto out;
3052
Ido Yariva6208652011-03-01 15:14:41 +02003053 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003054 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003055 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003056
3057 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3058 if (ret < 0)
3059 goto out_sleep;
3060
3061out_sleep:
3062 wl1271_ps_elp_sleep(wl);
3063
Arik Nemtsov409622e2011-02-23 00:22:29 +02003064out_free_sta:
3065 if (ret < 0)
3066 wl1271_free_sta(wl, hlid);
3067
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003068out:
3069 mutex_unlock(&wl->mutex);
3070 return ret;
3071}
3072
3073static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3074 struct ieee80211_vif *vif,
3075 struct ieee80211_sta *sta)
3076{
3077 struct wl1271 *wl = hw->priv;
3078 struct wl1271_station *wl_sta;
3079 int ret = 0, id;
3080
3081 mutex_lock(&wl->mutex);
3082
3083 if (unlikely(wl->state == WL1271_STATE_OFF))
3084 goto out;
3085
3086 if (wl->bss_type != BSS_TYPE_AP_BSS)
3087 goto out;
3088
3089 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3090
3091 wl_sta = (struct wl1271_station *)sta->drv_priv;
3092 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3093 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3094 goto out;
3095
Ido Yariva6208652011-03-01 15:14:41 +02003096 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003097 if (ret < 0)
3098 goto out;
3099
3100 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3101 if (ret < 0)
3102 goto out_sleep;
3103
Arik Nemtsov409622e2011-02-23 00:22:29 +02003104 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003105
3106out_sleep:
3107 wl1271_ps_elp_sleep(wl);
3108
3109out:
3110 mutex_unlock(&wl->mutex);
3111 return ret;
3112}
3113
Luciano Coelho4623ec72011-03-21 19:26:41 +02003114static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3115 struct ieee80211_vif *vif,
3116 enum ieee80211_ampdu_mlme_action action,
3117 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3118 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003119{
3120 struct wl1271 *wl = hw->priv;
3121 int ret;
3122
3123 mutex_lock(&wl->mutex);
3124
3125 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3126 ret = -EAGAIN;
3127 goto out;
3128 }
3129
Ido Yariva6208652011-03-01 15:14:41 +02003130 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003131 if (ret < 0)
3132 goto out;
3133
3134 switch (action) {
3135 case IEEE80211_AMPDU_RX_START:
3136 if (wl->ba_support) {
3137 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3138 true);
3139 if (!ret)
3140 wl->ba_rx_bitmap |= BIT(tid);
3141 } else {
3142 ret = -ENOTSUPP;
3143 }
3144 break;
3145
3146 case IEEE80211_AMPDU_RX_STOP:
3147 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3148 if (!ret)
3149 wl->ba_rx_bitmap &= ~BIT(tid);
3150 break;
3151
3152 /*
3153 * The BA initiator session management in FW independently.
3154 * Falling break here on purpose for all TX APDU commands.
3155 */
3156 case IEEE80211_AMPDU_TX_START:
3157 case IEEE80211_AMPDU_TX_STOP:
3158 case IEEE80211_AMPDU_TX_OPERATIONAL:
3159 ret = -EINVAL;
3160 break;
3161
3162 default:
3163 wl1271_error("Incorrect ampdu action id=%x\n", action);
3164 ret = -EINVAL;
3165 }
3166
3167 wl1271_ps_elp_sleep(wl);
3168
3169out:
3170 mutex_unlock(&wl->mutex);
3171
3172 return ret;
3173}
3174
Arik Nemtsov33437892011-04-26 23:35:39 +03003175static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3176{
3177 struct wl1271 *wl = hw->priv;
3178 bool ret = false;
3179
3180 mutex_lock(&wl->mutex);
3181
3182 if (unlikely(wl->state == WL1271_STATE_OFF))
3183 goto out;
3184
3185 /* packets are considered pending if in the TX queue or the FW */
3186 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3187
3188 /* the above is appropriate for STA mode for PS purposes */
3189 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3190
3191out:
3192 mutex_unlock(&wl->mutex);
3193
3194 return ret;
3195}
3196
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003197/* can't be const, mac80211 writes to this */
3198static struct ieee80211_rate wl1271_rates[] = {
3199 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003200 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3201 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003202 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003203 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3204 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003205 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3206 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003207 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3208 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003209 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3210 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003211 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3212 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003213 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3214 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003215 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3216 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003217 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003218 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3219 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003221 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3222 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003223 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003224 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3225 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003227 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3228 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003229 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003230 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3231 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003233 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3234 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003236 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3237 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003238};
3239
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003240/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003241static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003242 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003243 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003244 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3245 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3246 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003247 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003248 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3249 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3250 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003251 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003252 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3253 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3254 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003255 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003256};
3257
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003258/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003259static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003260 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003261 7, /* CONF_HW_RXTX_RATE_MCS7 */
3262 6, /* CONF_HW_RXTX_RATE_MCS6 */
3263 5, /* CONF_HW_RXTX_RATE_MCS5 */
3264 4, /* CONF_HW_RXTX_RATE_MCS4 */
3265 3, /* CONF_HW_RXTX_RATE_MCS3 */
3266 2, /* CONF_HW_RXTX_RATE_MCS2 */
3267 1, /* CONF_HW_RXTX_RATE_MCS1 */
3268 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003269
3270 11, /* CONF_HW_RXTX_RATE_54 */
3271 10, /* CONF_HW_RXTX_RATE_48 */
3272 9, /* CONF_HW_RXTX_RATE_36 */
3273 8, /* CONF_HW_RXTX_RATE_24 */
3274
3275 /* TI-specific rate */
3276 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3277
3278 7, /* CONF_HW_RXTX_RATE_18 */
3279 6, /* CONF_HW_RXTX_RATE_12 */
3280 3, /* CONF_HW_RXTX_RATE_11 */
3281 5, /* CONF_HW_RXTX_RATE_9 */
3282 4, /* CONF_HW_RXTX_RATE_6 */
3283 2, /* CONF_HW_RXTX_RATE_5_5 */
3284 1, /* CONF_HW_RXTX_RATE_2 */
3285 0 /* CONF_HW_RXTX_RATE_1 */
3286};
3287
Shahar Levie8b03a22010-10-13 16:09:39 +02003288/* 11n STA capabilities */
3289#define HW_RX_HIGHEST_RATE 72
3290
Shahar Levi00d20102010-11-08 11:20:10 +00003291#ifdef CONFIG_WL12XX_HT
3292#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003293 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3294 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003295 .ht_supported = true, \
3296 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3297 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3298 .mcs = { \
3299 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3300 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3301 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3302 }, \
3303}
Shahar Levi18357852010-10-13 16:09:41 +02003304#else
Shahar Levi00d20102010-11-08 11:20:10 +00003305#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003306 .ht_supported = false, \
3307}
3308#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003309
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310/* can't be const, mac80211 writes to this */
3311static struct ieee80211_supported_band wl1271_band_2ghz = {
3312 .channels = wl1271_channels,
3313 .n_channels = ARRAY_SIZE(wl1271_channels),
3314 .bitrates = wl1271_rates,
3315 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003316 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003317};
3318
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003319/* 5 GHz data rates for WL1273 */
3320static struct ieee80211_rate wl1271_rates_5ghz[] = {
3321 { .bitrate = 60,
3322 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3323 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3324 { .bitrate = 90,
3325 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3326 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3327 { .bitrate = 120,
3328 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3329 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3330 { .bitrate = 180,
3331 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3332 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3333 { .bitrate = 240,
3334 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3335 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3336 { .bitrate = 360,
3337 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3338 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3339 { .bitrate = 480,
3340 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3341 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3342 { .bitrate = 540,
3343 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3344 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3345};
3346
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003347/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003348static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003349 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003350 { .hw_value = 8, .center_freq = 5040},
3351 { .hw_value = 9, .center_freq = 5045},
3352 { .hw_value = 11, .center_freq = 5055},
3353 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003354 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003355 { .hw_value = 34, .center_freq = 5170},
3356 { .hw_value = 36, .center_freq = 5180},
3357 { .hw_value = 38, .center_freq = 5190},
3358 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003359 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003360 { .hw_value = 44, .center_freq = 5220},
3361 { .hw_value = 46, .center_freq = 5230},
3362 { .hw_value = 48, .center_freq = 5240},
3363 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003364 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003365 { .hw_value = 60, .center_freq = 5300},
3366 { .hw_value = 64, .center_freq = 5320},
3367 { .hw_value = 100, .center_freq = 5500},
3368 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003369 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003370 { .hw_value = 112, .center_freq = 5560},
3371 { .hw_value = 116, .center_freq = 5580},
3372 { .hw_value = 120, .center_freq = 5600},
3373 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003374 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003375 { .hw_value = 132, .center_freq = 5660},
3376 { .hw_value = 136, .center_freq = 5680},
3377 { .hw_value = 140, .center_freq = 5700},
3378 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003379 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003380 { .hw_value = 157, .center_freq = 5785},
3381 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003382 { .hw_value = 165, .center_freq = 5825},
3383};
3384
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003385/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003386static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003387 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003388 7, /* CONF_HW_RXTX_RATE_MCS7 */
3389 6, /* CONF_HW_RXTX_RATE_MCS6 */
3390 5, /* CONF_HW_RXTX_RATE_MCS5 */
3391 4, /* CONF_HW_RXTX_RATE_MCS4 */
3392 3, /* CONF_HW_RXTX_RATE_MCS3 */
3393 2, /* CONF_HW_RXTX_RATE_MCS2 */
3394 1, /* CONF_HW_RXTX_RATE_MCS1 */
3395 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003396
3397 7, /* CONF_HW_RXTX_RATE_54 */
3398 6, /* CONF_HW_RXTX_RATE_48 */
3399 5, /* CONF_HW_RXTX_RATE_36 */
3400 4, /* CONF_HW_RXTX_RATE_24 */
3401
3402 /* TI-specific rate */
3403 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3404
3405 3, /* CONF_HW_RXTX_RATE_18 */
3406 2, /* CONF_HW_RXTX_RATE_12 */
3407 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3408 1, /* CONF_HW_RXTX_RATE_9 */
3409 0, /* CONF_HW_RXTX_RATE_6 */
3410 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3411 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3412 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3413};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003414
3415static struct ieee80211_supported_band wl1271_band_5ghz = {
3416 .channels = wl1271_channels_5ghz,
3417 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3418 .bitrates = wl1271_rates_5ghz,
3419 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003420 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003421};
3422
Tobias Klausera0ea9492010-05-20 10:38:11 +02003423static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003424 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3425 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3426};
3427
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428static const struct ieee80211_ops wl1271_ops = {
3429 .start = wl1271_op_start,
3430 .stop = wl1271_op_stop,
3431 .add_interface = wl1271_op_add_interface,
3432 .remove_interface = wl1271_op_remove_interface,
3433 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003434 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003435 .configure_filter = wl1271_op_configure_filter,
3436 .tx = wl1271_op_tx,
3437 .set_key = wl1271_op_set_key,
3438 .hw_scan = wl1271_op_hw_scan,
3439 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003440 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003441 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003442 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003443 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003444 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003445 .sta_add = wl1271_op_sta_add,
3446 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003447 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003448 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003449 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003450};
3451
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003452
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003453u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003454{
3455 u8 idx;
3456
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003457 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003458
3459 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3460 wl1271_error("Illegal RX rate from HW: %d", rate);
3461 return 0;
3462 }
3463
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003464 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003465 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3466 wl1271_error("Unsupported RX rate from HW: %d", rate);
3467 return 0;
3468 }
3469
3470 return idx;
3471}
3472
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003473static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3474 struct device_attribute *attr,
3475 char *buf)
3476{
3477 struct wl1271 *wl = dev_get_drvdata(dev);
3478 ssize_t len;
3479
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003480 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003481
3482 mutex_lock(&wl->mutex);
3483 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3484 wl->sg_enabled);
3485 mutex_unlock(&wl->mutex);
3486
3487 return len;
3488
3489}
3490
3491static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3492 struct device_attribute *attr,
3493 const char *buf, size_t count)
3494{
3495 struct wl1271 *wl = dev_get_drvdata(dev);
3496 unsigned long res;
3497 int ret;
3498
Luciano Coelho6277ed62011-04-01 17:49:54 +03003499 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003500 if (ret < 0) {
3501 wl1271_warning("incorrect value written to bt_coex_mode");
3502 return count;
3503 }
3504
3505 mutex_lock(&wl->mutex);
3506
3507 res = !!res;
3508
3509 if (res == wl->sg_enabled)
3510 goto out;
3511
3512 wl->sg_enabled = res;
3513
3514 if (wl->state == WL1271_STATE_OFF)
3515 goto out;
3516
Ido Yariva6208652011-03-01 15:14:41 +02003517 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003518 if (ret < 0)
3519 goto out;
3520
3521 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3522 wl1271_ps_elp_sleep(wl);
3523
3524 out:
3525 mutex_unlock(&wl->mutex);
3526 return count;
3527}
3528
3529static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3530 wl1271_sysfs_show_bt_coex_state,
3531 wl1271_sysfs_store_bt_coex_state);
3532
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003533static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3534 struct device_attribute *attr,
3535 char *buf)
3536{
3537 struct wl1271 *wl = dev_get_drvdata(dev);
3538 ssize_t len;
3539
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003540 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003541
3542 mutex_lock(&wl->mutex);
3543 if (wl->hw_pg_ver >= 0)
3544 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3545 else
3546 len = snprintf(buf, len, "n/a\n");
3547 mutex_unlock(&wl->mutex);
3548
3549 return len;
3550}
3551
3552static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3553 wl1271_sysfs_show_hw_pg_ver, NULL);
3554
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003555int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003556{
3557 int ret;
3558
3559 if (wl->mac80211_registered)
3560 return 0;
3561
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003562 ret = wl1271_fetch_nvs(wl);
3563 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003564 /* NOTE: The wl->nvs->nvs element must be first, in
3565 * order to simplify the casting, we assume it is at
3566 * the beginning of the wl->nvs structure.
3567 */
3568 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003569
3570 wl->mac_addr[0] = nvs_ptr[11];
3571 wl->mac_addr[1] = nvs_ptr[10];
3572 wl->mac_addr[2] = nvs_ptr[6];
3573 wl->mac_addr[3] = nvs_ptr[5];
3574 wl->mac_addr[4] = nvs_ptr[4];
3575 wl->mac_addr[5] = nvs_ptr[3];
3576 }
3577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003578 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3579
3580 ret = ieee80211_register_hw(wl->hw);
3581 if (ret < 0) {
3582 wl1271_error("unable to register mac80211 hw: %d", ret);
3583 return ret;
3584 }
3585
3586 wl->mac80211_registered = true;
3587
Eliad Pellerd60080a2010-11-24 12:53:16 +02003588 wl1271_debugfs_init(wl);
3589
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003590 register_netdevice_notifier(&wl1271_dev_notifier);
3591
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003592 wl1271_notice("loaded");
3593
3594 return 0;
3595}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003596EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003597
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003598void wl1271_unregister_hw(struct wl1271 *wl)
3599{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003600 if (wl->state == WL1271_STATE_PLT)
3601 __wl1271_plt_stop(wl);
3602
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003603 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003604 ieee80211_unregister_hw(wl->hw);
3605 wl->mac80211_registered = false;
3606
3607}
3608EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3609
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003610int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003611{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003612 static const u32 cipher_suites[] = {
3613 WLAN_CIPHER_SUITE_WEP40,
3614 WLAN_CIPHER_SUITE_WEP104,
3615 WLAN_CIPHER_SUITE_TKIP,
3616 WLAN_CIPHER_SUITE_CCMP,
3617 WL1271_CIPHER_SUITE_GEM,
3618 };
3619
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003620 /* The tx descriptor buffer and the TKIP space. */
3621 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3622 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003623
3624 /* unit us */
3625 /* FIXME: find a proper value */
3626 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003627 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003628
3629 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003630 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003631 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003632 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003633 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003634 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003635 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003636 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003637 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003638
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003639 wl->hw->wiphy->cipher_suites = cipher_suites;
3640 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3641
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003642 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003643 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003644 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003645 /*
3646 * Maximum length of elements in scanning probe request templates
3647 * should be the maximum length possible for a template, without
3648 * the IEEE80211 header of the template
3649 */
3650 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3651 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003652
Luciano Coelho4a31c112011-03-21 23:16:14 +02003653 /* make sure all our channels fit in the scanned_ch bitmask */
3654 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3655 ARRAY_SIZE(wl1271_channels_5ghz) >
3656 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003657 /*
3658 * We keep local copies of the band structs because we need to
3659 * modify them on a per-device basis.
3660 */
3661 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3662 sizeof(wl1271_band_2ghz));
3663 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3664 sizeof(wl1271_band_5ghz));
3665
3666 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3667 &wl->bands[IEEE80211_BAND_2GHZ];
3668 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3669 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003670
Kalle Valo12bd8942010-03-18 12:26:33 +02003671 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003672 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003673
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003674 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3675
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003676 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003677
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003678 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3679
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003680 wl->hw->max_rx_aggregation_subframes = 8;
3681
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003682 return 0;
3683}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003684EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003686#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003687
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003688struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003689{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003690 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003691 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003693 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003694 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003695
3696 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3697 if (!hw) {
3698 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003699 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003700 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003701 }
3702
Julia Lawall929ebd32010-05-15 23:16:39 +02003703 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003704 if (!plat_dev) {
3705 wl1271_error("could not allocate platform_device");
3706 ret = -ENOMEM;
3707 goto err_plat_alloc;
3708 }
3709
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710 wl = hw->priv;
3711 memset(wl, 0, sizeof(*wl));
3712
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003713 INIT_LIST_HEAD(&wl->list);
3714
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003715 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003716 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003717
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003718 for (i = 0; i < NUM_TX_QUEUES; i++)
3719 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003720
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003721 for (i = 0; i < NUM_TX_QUEUES; i++)
3722 for (j = 0; j < AP_MAX_LINKS; j++)
3723 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3724
Ido Yariva6208652011-03-01 15:14:41 +02003725 skb_queue_head_init(&wl->deferred_rx_queue);
3726 skb_queue_head_init(&wl->deferred_tx_queue);
3727
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003728 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003729 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003730 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003731 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3732 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3733 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003734 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003735 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003736 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003737 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003738 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3739 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003740 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003741 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003742 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003743 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003744 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003745 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003746 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003747 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003748 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003749 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003750 wl->bss_type = MAX_BSS_TYPE;
3751 wl->set_bss_type = MAX_BSS_TYPE;
3752 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003753 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003754 wl->ap_ps_map = 0;
3755 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003756 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003757 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003758
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003759 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003760 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003761 wl->tx_frames[i] = NULL;
3762
3763 spin_lock_init(&wl->wl_lock);
3764
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003765 wl->state = WL1271_STATE_OFF;
3766 mutex_init(&wl->mutex);
3767
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003768 /* Apply default driver configuration. */
3769 wl1271_conf_init(wl);
3770
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003771 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3772 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3773 if (!wl->aggr_buf) {
3774 ret = -ENOMEM;
3775 goto err_hw;
3776 }
3777
Ido Yariv990f5de2011-03-31 10:06:59 +02003778 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3779 if (!wl->dummy_packet) {
3780 ret = -ENOMEM;
3781 goto err_aggr;
3782 }
3783
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003784 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003785 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003786 if (ret) {
3787 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003788 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003789 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003790 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003791
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003792 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003793 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003794 if (ret < 0) {
3795 wl1271_error("failed to create sysfs file bt_coex_state");
3796 goto err_platform;
3797 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003798
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003799 /* Create sysfs file to get HW PG version */
3800 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3801 if (ret < 0) {
3802 wl1271_error("failed to create sysfs file hw_pg_ver");
3803 goto err_bt_coex_state;
3804 }
3805
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003806 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003807
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003808err_bt_coex_state:
3809 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3810
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003811err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003812 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003813
Ido Yariv990f5de2011-03-31 10:06:59 +02003814err_dummy_packet:
3815 dev_kfree_skb(wl->dummy_packet);
3816
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003817err_aggr:
3818 free_pages((unsigned long)wl->aggr_buf, order);
3819
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003820err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003821 wl1271_debugfs_exit(wl);
3822 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003823
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003824err_plat_alloc:
3825 ieee80211_free_hw(hw);
3826
3827err_hw_alloc:
3828
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003829 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003830}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003831EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003832
3833int wl1271_free_hw(struct wl1271 *wl)
3834{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003835 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003836 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003837 free_pages((unsigned long)wl->aggr_buf,
3838 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003839 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003840
3841 wl1271_debugfs_exit(wl);
3842
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003843 vfree(wl->fw);
3844 wl->fw = NULL;
3845 kfree(wl->nvs);
3846 wl->nvs = NULL;
3847
3848 kfree(wl->fw_status);
3849 kfree(wl->tx_res_if);
3850
3851 ieee80211_free_hw(wl->hw);
3852
3853 return 0;
3854}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003855EXPORT_SYMBOL_GPL(wl1271_free_hw);
3856
Guy Eilam491bbd62011-01-12 10:33:29 +01003857u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003858EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003859module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003860MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3861
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003862MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003863MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003864MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");