blob: 88d2e9052a0d9303387e0e9bc0f09598f5dbeda0 [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-Cohen958b20e02011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
314 .num_probe_reqs = 2,
315 .rssi_threshold = -90,
316 .snr_threshold = 0,
317 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200318 .rf = {
319 .tx_per_channel_power_compensation_2 = {
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 },
322 .tx_per_channel_power_compensation_5 = {
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 },
327 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100328 .ht = {
329 .tx_ba_win_size = 64,
330 .inactivity_timeout = 10000,
331 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200332 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200333 .num_stations = 1,
334 .ssid_profiles = 1,
335 .rx_block_num = 70,
336 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300337 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200338 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200339 .min_req_rx_blocks = 22,
340 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200341 },
342 .mem_wl128x = {
343 .num_stations = 1,
344 .ssid_profiles = 1,
345 .rx_block_num = 40,
346 .tx_min_block_num = 40,
347 .dynamic_memory = 1,
348 .min_req_tx_blocks = 45,
349 .min_req_rx_blocks = 22,
350 .tx_min = 27,
351 },
Shahar Leviff868432011-04-11 15:41:46 +0300352 .fm_coex = {
353 .enable = true,
354 .swallow_period = 5,
355 .n_divider_fref_set_1 = 0xff, /* default */
356 .n_divider_fref_set_2 = 12,
357 .m_divider_fref_set_1 = 148,
358 .m_divider_fref_set_2 = 0xffff, /* default */
359 .coex_pll_stabilization_time = 0xffffffff, /* default */
360 .ldo_stabilization_time = 0xffff, /* default */
361 .fm_disturbed_band_margin = 0xff, /* default */
362 .swallow_clk_diff = 0xff, /* default */
363 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300364 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300365};
366
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300367static void __wl1271_op_remove_interface(struct wl1271 *wl,
368 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200369static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200370
371
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200372static void wl1271_device_release(struct device *dev)
373{
374
375}
376
377static struct platform_device wl1271_device = {
378 .name = "wl1271",
379 .id = -1,
380
381 /* device model insists to have a release function */
382 .dev = {
383 .release = wl1271_device_release,
384 },
385};
386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300390static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
391 void *arg)
392{
393 struct net_device *dev = arg;
394 struct wireless_dev *wdev;
395 struct wiphy *wiphy;
396 struct ieee80211_hw *hw;
397 struct wl1271 *wl;
398 struct wl1271 *wl_temp;
399 int ret = 0;
400
401 /* Check that this notification is for us. */
402 if (what != NETDEV_CHANGE)
403 return NOTIFY_DONE;
404
405 wdev = dev->ieee80211_ptr;
406 if (wdev == NULL)
407 return NOTIFY_DONE;
408
409 wiphy = wdev->wiphy;
410 if (wiphy == NULL)
411 return NOTIFY_DONE;
412
413 hw = wiphy_priv(wiphy);
414 if (hw == NULL)
415 return NOTIFY_DONE;
416
417 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200418 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300419 list_for_each_entry(wl, &wl_list, list) {
420 if (wl == wl_temp)
421 break;
422 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200423 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300424 if (wl != wl_temp)
425 return NOTIFY_DONE;
426
427 mutex_lock(&wl->mutex);
428
429 if (wl->state == WL1271_STATE_OFF)
430 goto out;
431
432 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
433 goto out;
434
Ido Yariva6208652011-03-01 15:14:41 +0200435 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300436 if (ret < 0)
437 goto out;
438
439 if ((dev->operstate == IF_OPER_UP) &&
440 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
441 wl1271_cmd_set_sta_state(wl);
442 wl1271_info("Association completed.");
443 }
444
445 wl1271_ps_elp_sleep(wl);
446
447out:
448 mutex_unlock(&wl->mutex);
449
450 return NOTIFY_OK;
451}
452
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100453static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200454 struct regulatory_request *request)
455{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100456 struct ieee80211_supported_band *band;
457 struct ieee80211_channel *ch;
458 int i;
459
460 band = wiphy->bands[IEEE80211_BAND_5GHZ];
461 for (i = 0; i < band->n_channels; i++) {
462 ch = &band->channels[i];
463 if (ch->flags & IEEE80211_CHAN_DISABLED)
464 continue;
465
466 if (ch->flags & IEEE80211_CHAN_RADAR)
467 ch->flags |= IEEE80211_CHAN_NO_IBSS |
468 IEEE80211_CHAN_PASSIVE_SCAN;
469
470 }
471
472 return 0;
473}
474
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300475static void wl1271_conf_init(struct wl1271 *wl)
476{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300477
478 /*
479 * This function applies the default configuration to the driver. This
480 * function is invoked upon driver load (spi probe.)
481 *
482 * The configuration is stored in a run-time structure in order to
483 * facilitate for run-time adjustment of any of the parameters. Making
484 * changes to the configuration structure will apply the new values on
485 * the next interface up (wl1271_op_start.)
486 */
487
488 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300489 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300490}
491
492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493static int wl1271_plt_init(struct wl1271 *wl)
494{
Luciano Coelho12419cce2010-02-18 13:25:44 +0200495 struct conf_tx_ac_category *conf_ac;
496 struct conf_tx_tid *conf_tid;
497 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300498
Shahar Levi49d750ca2011-03-06 16:32:09 +0200499 if (wl->chip.id == CHIP_ID_1283_PG20)
500 ret = wl128x_cmd_general_parms(wl);
501 else
502 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200503 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200504 return ret;
505
Shahar Levi49d750ca2011-03-06 16:32:09 +0200506 if (wl->chip.id == CHIP_ID_1283_PG20)
507 ret = wl128x_cmd_radio_parms(wl);
508 else
509 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200510 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200511 return ret;
512
Shahar Levi49d750ca2011-03-06 16:32:09 +0200513 if (wl->chip.id != CHIP_ID_1283_PG20) {
514 ret = wl1271_cmd_ext_radio_parms(wl);
515 if (ret < 0)
516 return ret;
517 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200518 if (ret < 0)
519 return ret;
520
Shahar Levi48a61472011-03-06 16:32:08 +0200521 /* Chip-specific initializations */
522 ret = wl1271_chip_specific_init(wl);
523 if (ret < 0)
524 return ret;
525
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200526 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200527 if (ret < 0)
528 return ret;
529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300530 ret = wl1271_acx_init_mem_config(wl);
531 if (ret < 0)
532 return ret;
533
Luciano Coelho12419cce2010-02-18 13:25:44 +0200534 /* PHY layer config */
535 ret = wl1271_init_phy_config(wl);
536 if (ret < 0)
537 goto out_free_memmap;
538
539 ret = wl1271_acx_dco_itrim_params(wl);
540 if (ret < 0)
541 goto out_free_memmap;
542
543 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200544 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200545 if (ret < 0)
546 goto out_free_memmap;
547
548 /* Bluetooth WLAN coexistence */
549 ret = wl1271_init_pta(wl);
550 if (ret < 0)
551 goto out_free_memmap;
552
Shahar Leviff868432011-04-11 15:41:46 +0300553 /* FM WLAN coexistence */
554 ret = wl1271_acx_fm_coex(wl);
555 if (ret < 0)
556 goto out_free_memmap;
557
Luciano Coelho12419cce2010-02-18 13:25:44 +0200558 /* Energy detection */
559 ret = wl1271_init_energy_detection(wl);
560 if (ret < 0)
561 goto out_free_memmap;
562
Gery Kahn1ec610e2011-02-01 03:03:08 -0600563 ret = wl1271_acx_sta_mem_cfg(wl);
564 if (ret < 0)
565 goto out_free_memmap;
566
Luciano Coelho12419cce2010-02-18 13:25:44 +0200567 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100568 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200569 if (ret < 0)
570 goto out_free_memmap;
571
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200572 /* Default TID/AC configuration */
573 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cce2010-02-18 13:25:44 +0200574 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200575 conf_ac = &wl->conf.tx.ac_conf[i];
576 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
577 conf_ac->cw_max, conf_ac->aifsn,
578 conf_ac->tx_op_limit);
579 if (ret < 0)
580 goto out_free_memmap;
581
Luciano Coelho12419cce2010-02-18 13:25:44 +0200582 conf_tid = &wl->conf.tx.tid_conf[i];
583 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
584 conf_tid->channel_type,
585 conf_tid->tsid,
586 conf_tid->ps_scheme,
587 conf_tid->ack_policy,
588 conf_tid->apsd_conf[0],
589 conf_tid->apsd_conf[1]);
590 if (ret < 0)
591 goto out_free_memmap;
592 }
593
Luciano Coelho12419cce2010-02-18 13:25:44 +0200594 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200595 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300596 if (ret < 0)
Luciano Coelho12419cce2010-02-18 13:25:44 +0200597 goto out_free_memmap;
598
599 /* Configure for CAM power saving (ie. always active) */
600 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
601 if (ret < 0)
602 goto out_free_memmap;
603
604 /* configure PM */
605 ret = wl1271_acx_pm_config(wl);
606 if (ret < 0)
607 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300608
609 return 0;
Luciano Coelho12419cce2010-02-18 13:25:44 +0200610
611 out_free_memmap:
612 kfree(wl->target_mem_map);
613 wl->target_mem_map = NULL;
614
615 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300616}
617
Arik Nemtsovb622d992011-02-23 00:22:31 +0200618static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
619{
620 bool fw_ps;
621
622 /* only regulate station links */
623 if (hlid < WL1271_AP_STA_HLID_START)
624 return;
625
626 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
627
628 /*
629 * Wake up from high level PS if the STA is asleep with too little
630 * blocks in FW or if the STA is awake.
631 */
632 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
633 wl1271_ps_link_end(wl, hlid);
634
635 /* Start high-level PS if the STA is asleep with enough blocks in FW */
636 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
637 wl1271_ps_link_start(wl, hlid, true);
638}
639
640static void wl1271_irq_update_links_status(struct wl1271 *wl,
641 struct wl1271_fw_ap_status *status)
642{
643 u32 cur_fw_ps_map;
644 u8 hlid;
645
646 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
647 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
648 wl1271_debug(DEBUG_PSM,
649 "link ps prev 0x%x cur 0x%x changed 0x%x",
650 wl->ap_fw_ps_map, cur_fw_ps_map,
651 wl->ap_fw_ps_map ^ cur_fw_ps_map);
652
653 wl->ap_fw_ps_map = cur_fw_ps_map;
654 }
655
656 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
657 u8 cnt = status->tx_lnk_free_blks[hlid] -
658 wl->links[hlid].prev_freed_blks;
659
660 wl->links[hlid].prev_freed_blks =
661 status->tx_lnk_free_blks[hlid];
662 wl->links[hlid].allocated_blks -= cnt;
663
664 wl1271_irq_ps_regulate_link(wl, hlid,
665 wl->links[hlid].allocated_blks);
666 }
667}
668
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300669static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200670 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300671{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200672 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200673 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200674 u32 old_tx_blk_count = wl->tx_blocks_available;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200675 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300676 int i;
677
Shahar Levi13b107d2011-03-06 16:32:12 +0200678 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200679 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
680 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200681 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200682 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
683 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200684 }
685
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300686 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
687 "drv_rx_counter = %d, tx_results_counter = %d)",
688 status->intr,
689 status->fw_rx_counter,
690 status->drv_rx_counter,
691 status->tx_results_counter);
692
693 /* update number of available TX blocks */
694 for (i = 0; i < NUM_TX_QUEUES; i++) {
Ido Yarivd2f4d472011-03-31 10:07:00 +0200695 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
696 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300697
698 wl->tx_blocks_freed[i] =
699 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200700 }
701
Ido Yarivd2f4d472011-03-31 10:07:00 +0200702 wl->tx_allocated_blocks -= freed_blocks;
Shahar Levi13b107d2011-03-06 16:32:12 +0200703
Ido Yarivd2f4d472011-03-31 10:07:00 +0200704 if (wl->bss_type == BSS_TYPE_AP_BSS) {
705 /* Update num of allocated TX blocks per link and ps status */
706 wl1271_irq_update_links_status(wl, &full_status->ap);
707 wl->tx_blocks_available += freed_blocks;
708 } else {
709 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
710
711 /*
712 * The FW might change the total number of TX memblocks before
713 * we get a notification about blocks being released. Thus, the
714 * available blocks calculation might yield a temporary result
715 * which is lower than the actual available blocks. Keeping in
716 * mind that only blocks that were allocated can be moved from
717 * TX to RX, tx_blocks_available should never decrease here.
718 */
719 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
720 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721 }
722
Ido Yariva5225502010-10-12 14:49:10 +0200723 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200724 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200725 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300726
727 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200728 getnstimeofday(&ts);
729 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
730 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300731}
732
Ido Yariva6208652011-03-01 15:14:41 +0200733static void wl1271_flush_deferred_work(struct wl1271 *wl)
734{
735 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200736
Ido Yariva6208652011-03-01 15:14:41 +0200737 /* Pass all received frames to the network stack */
738 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
739 ieee80211_rx_ni(wl->hw, skb);
740
741 /* Return sent skbs to the network stack */
742 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
743 ieee80211_tx_status(wl->hw, skb);
744}
745
746static void wl1271_netstack_work(struct work_struct *work)
747{
748 struct wl1271 *wl =
749 container_of(work, struct wl1271, netstack_work);
750
751 do {
752 wl1271_flush_deferred_work(wl);
753 } while (skb_queue_len(&wl->deferred_rx_queue));
754}
755
756#define WL1271_IRQ_MAX_LOOPS 256
757
758irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300759{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300760 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300761 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200762 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200763 struct wl1271 *wl = (struct wl1271 *)cookie;
764 bool done = false;
765 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200766 unsigned long flags;
767
768 /* TX might be handled here, avoid redundant work */
769 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
770 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300771
Ido Yariv341b7cd2011-03-31 10:07:01 +0200772 /*
773 * In case edge triggered interrupt must be used, we cannot iterate
774 * more than once without introducing race conditions with the hardirq.
775 */
776 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
777 loopcount = 1;
778
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300779 mutex_lock(&wl->mutex);
780
781 wl1271_debug(DEBUG_IRQ, "IRQ work");
782
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200783 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300784 goto out;
785
Ido Yariva6208652011-03-01 15:14:41 +0200786 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787 if (ret < 0)
788 goto out;
789
Ido Yariva6208652011-03-01 15:14:41 +0200790 while (!done && loopcount--) {
791 /*
792 * In order to avoid a race with the hardirq, clear the flag
793 * before acknowledging the chip. Since the mutex is held,
794 * wl1271_ps_elp_wakeup cannot be called concurrently.
795 */
796 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
797 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200798
799 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200800 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200801 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200802 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200803 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200804 continue;
805 }
806
Eliad Pellerccc83b02010-10-27 14:09:57 +0200807 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
808 wl1271_error("watchdog interrupt received! "
809 "starting recovery.");
810 ieee80211_queue_work(wl->hw, &wl->recovery_work);
811
812 /* restarting the chip. ignore any other interrupt. */
813 goto out;
814 }
815
Ido Yariva6208652011-03-01 15:14:41 +0200816 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200817 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
818
Ido Yariv8aad2462011-03-01 15:14:38 +0200819 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200820
Ido Yariva5225502010-10-12 14:49:10 +0200821 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200822 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200823 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Juuso Oikarinen6742f552010-12-13 09:52:37 +0200824 wl->tx_queue_count) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200825 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200826 /*
827 * In order to avoid starvation of the TX path,
828 * call the work function directly.
829 */
830 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200831 } else {
832 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200833 }
834
Ido Yariv8aad2462011-03-01 15:14:38 +0200835 /* check for tx results */
836 if (wl->fw_status->common.tx_results_counter !=
837 (wl->tx_results_count & 0xff))
838 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200839
840 /* Make sure the deferred queues don't get too long */
841 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
842 skb_queue_len(&wl->deferred_rx_queue);
843 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
844 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200845 }
846
847 if (intr & WL1271_ACX_INTR_EVENT_A) {
848 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
849 wl1271_event_handle(wl, 0);
850 }
851
852 if (intr & WL1271_ACX_INTR_EVENT_B) {
853 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
854 wl1271_event_handle(wl, 1);
855 }
856
857 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
858 wl1271_debug(DEBUG_IRQ,
859 "WL1271_ACX_INTR_INIT_COMPLETE");
860
861 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
862 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300863 }
864
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300865 wl1271_ps_elp_sleep(wl);
866
867out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200868 spin_lock_irqsave(&wl->wl_lock, flags);
869 /* In case TX was not handled here, queue TX work */
870 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
871 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
872 wl->tx_queue_count)
873 ieee80211_queue_work(wl->hw, &wl->tx_work);
874 spin_unlock_irqrestore(&wl->wl_lock, flags);
875
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300876 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200877
878 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300879}
Ido Yariva6208652011-03-01 15:14:41 +0200880EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300882static int wl1271_fetch_firmware(struct wl1271 *wl)
883{
884 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200885 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 int ret;
887
Arik Nemtsov166d5042010-10-16 21:44:57 +0200888 switch (wl->bss_type) {
889 case BSS_TYPE_AP_BSS:
Arik Nemtsov1aed55f2011-03-06 16:32:18 +0200890 if (wl->chip.id == CHIP_ID_1283_PG20)
891 fw_name = WL128X_AP_FW_NAME;
892 else
893 fw_name = WL127X_AP_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200894 break;
895 case BSS_TYPE_IBSS:
896 case BSS_TYPE_STA_BSS:
Shahar Levibc765bf2011-03-06 16:32:10 +0200897 if (wl->chip.id == CHIP_ID_1283_PG20)
898 fw_name = WL128X_FW_NAME;
899 else
900 fw_name = WL1271_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200901 break;
902 default:
903 wl1271_error("no compatible firmware for bss_type %d",
904 wl->bss_type);
905 return -EINVAL;
906 }
907
908 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
909
910 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300911
912 if (ret < 0) {
913 wl1271_error("could not get firmware: %d", ret);
914 return ret;
915 }
916
917 if (fw->size % 4) {
918 wl1271_error("firmware size is not multiple of 32 bits: %zu",
919 fw->size);
920 ret = -EILSEQ;
921 goto out;
922 }
923
Arik Nemtsov166d5042010-10-16 21:44:57 +0200924 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300925 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +0300926 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300927
928 if (!wl->fw) {
929 wl1271_error("could not allocate memory for the firmware");
930 ret = -ENOMEM;
931 goto out;
932 }
933
934 memcpy(wl->fw, fw->data, wl->fw_len);
Arik Nemtsov166d5042010-10-16 21:44:57 +0200935 wl->fw_bss_type = wl->bss_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300936 ret = 0;
937
938out:
939 release_firmware(fw);
940
941 return ret;
942}
943
944static int wl1271_fetch_nvs(struct wl1271 *wl)
945{
946 const struct firmware *fw;
947 int ret;
948
Shahar Levi5aa42342011-03-06 16:32:07 +0200949 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950
951 if (ret < 0) {
952 wl1271_error("could not get nvs file: %d", ret);
953 return ret;
954 }
955
Shahar Levibc765bf2011-03-06 16:32:10 +0200956 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300957
958 if (!wl->nvs) {
959 wl1271_error("could not allocate memory for the nvs file");
960 ret = -ENOMEM;
961 goto out;
962 }
963
Juuso Oikarinen02fabb02010-08-19 04:41:15 +0200964 wl->nvs_len = fw->size;
965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300966out:
967 release_firmware(fw);
968
969 return ret;
970}
971
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200972static void wl1271_recovery_work(struct work_struct *work)
973{
974 struct wl1271 *wl =
975 container_of(work, struct wl1271, recovery_work);
976
977 mutex_lock(&wl->mutex);
978
979 if (wl->state != WL1271_STATE_ON)
980 goto out;
981
Arik Nemtsov52dcaf52011-04-18 14:15:24 +0300982 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
983 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200984
Juuso Oikarinend25611d2010-09-30 10:43:27 +0200985 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
986 ieee80211_connection_loss(wl->vif);
987
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300988 /* Prevent spurious TX during FW restart */
989 ieee80211_stop_queues(wl->hw);
990
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200991 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300992 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200993 ieee80211_restart_hw(wl->hw);
994
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300995 /*
996 * Its safe to enable TX now - the queues are stopped after a request
997 * to restart the HW.
998 */
999 ieee80211_wake_queues(wl->hw);
1000
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001001out:
1002 mutex_unlock(&wl->mutex);
1003}
1004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005static void wl1271_fw_wakeup(struct wl1271 *wl)
1006{
1007 u32 elp_reg;
1008
1009 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001010 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011}
1012
1013static int wl1271_setup(struct wl1271 *wl)
1014{
1015 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1016 if (!wl->fw_status)
1017 return -ENOMEM;
1018
1019 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1020 if (!wl->tx_res_if) {
1021 kfree(wl->fw_status);
1022 return -ENOMEM;
1023 }
1024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 return 0;
1026}
1027
1028static int wl1271_chip_wakeup(struct wl1271 *wl)
1029{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001030 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001031 int ret = 0;
1032
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001033 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001034 ret = wl1271_power_on(wl);
1035 if (ret < 0)
1036 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001037 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001038 wl1271_io_reset(wl);
1039 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 /* We don't need a real memory partition here, because we only want
1042 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001043 memset(&partition, 0, sizeof(partition));
1044 partition.reg.start = REGISTERS_BASE;
1045 partition.reg.size = REGISTERS_DOWN_SIZE;
1046 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
1048 /* ELP module wake up */
1049 wl1271_fw_wakeup(wl);
1050
1051 /* whal_FwCtrl_BootSm() */
1052
1053 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001054 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 /* 1. check if chip id is valid */
1057
1058 switch (wl->chip.id) {
1059 case CHIP_ID_1271_PG10:
1060 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1061 wl->chip.id);
1062
1063 ret = wl1271_setup(wl);
1064 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001065 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001066 break;
1067 case CHIP_ID_1271_PG20:
1068 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1069 wl->chip.id);
1070
Shahar Levi564f5952011-04-04 10:20:39 +03001071 /* end-of-transaction flag should be set in wl127x AP mode */
1072 if (wl->bss_type == BSS_TYPE_AP_BSS)
1073 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1074
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001075 ret = wl1271_setup(wl);
1076 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001077 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001078 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001079 case CHIP_ID_1283_PG20:
1080 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1081 wl->chip.id);
1082
1083 ret = wl1271_setup(wl);
1084 if (ret < 0)
1085 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001086 if (wl1271_set_block_size(wl))
1087 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001088 break;
1089 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001090 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001091 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001092 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001093 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001094 }
1095
Arik Nemtsov166d5042010-10-16 21:44:57 +02001096 /* Make sure the firmware type matches the BSS type */
1097 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001098 ret = wl1271_fetch_firmware(wl);
1099 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001100 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001101 }
1102
1103 /* No NVS from netlink, try to get it from the filesystem */
1104 if (wl->nvs == NULL) {
1105 ret = wl1271_fetch_nvs(wl);
1106 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001107 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001108 }
1109
1110out:
1111 return ret;
1112}
1113
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001114static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1115{
1116 unsigned int quirks = 0;
1117 unsigned int *fw_ver = wl->chip.fw_ver;
1118
1119 /* Only for wl127x */
1120 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1121 /* Check STA version */
1122 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1123 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1124 /* Check AP version */
1125 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1126 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1127 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1128
1129 return quirks;
1130}
1131
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001132int wl1271_plt_start(struct wl1271 *wl)
1133{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001134 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001135 int ret;
1136
1137 mutex_lock(&wl->mutex);
1138
1139 wl1271_notice("power up");
1140
1141 if (wl->state != WL1271_STATE_OFF) {
1142 wl1271_error("cannot go into PLT state because not "
1143 "in off state: %d", wl->state);
1144 ret = -EBUSY;
1145 goto out;
1146 }
1147
Arik Nemtsov166d5042010-10-16 21:44:57 +02001148 wl->bss_type = BSS_TYPE_STA_BSS;
1149
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001150 while (retries) {
1151 retries--;
1152 ret = wl1271_chip_wakeup(wl);
1153 if (ret < 0)
1154 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001155
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001156 ret = wl1271_boot(wl);
1157 if (ret < 0)
1158 goto power_off;
1159
1160 ret = wl1271_plt_init(wl);
1161 if (ret < 0)
1162 goto irq_disable;
1163
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001164 wl->state = WL1271_STATE_PLT;
1165 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001166 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001167
1168 /* Check if any quirks are needed with older fw versions */
1169 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001170 goto out;
1171
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001172irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001173 mutex_unlock(&wl->mutex);
1174 /* Unlocking the mutex in the middle of handling is
1175 inherently unsafe. In this case we deem it safe to do,
1176 because we need to let any possibly pending IRQ out of
1177 the system (and while we are WL1271_STATE_OFF the IRQ
1178 work function will not do anything.) Also, any other
1179 possible concurrent operations will fail due to the
1180 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001181 wl1271_disable_interrupts(wl);
1182 wl1271_flush_deferred_work(wl);
1183 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001184 mutex_lock(&wl->mutex);
1185power_off:
1186 wl1271_power_off(wl);
1187 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001188
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001189 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1190 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001191out:
1192 mutex_unlock(&wl->mutex);
1193
1194 return ret;
1195}
1196
Luciano Coelho4623ec72011-03-21 19:26:41 +02001197static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001198{
1199 int ret = 0;
1200
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001201 wl1271_notice("power down");
1202
1203 if (wl->state != WL1271_STATE_PLT) {
1204 wl1271_error("cannot power down because not in PLT "
1205 "state: %d", wl->state);
1206 ret = -EBUSY;
1207 goto out;
1208 }
1209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001210 wl1271_power_off(wl);
1211
1212 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001213 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001214
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001216 wl1271_disable_interrupts(wl);
1217 wl1271_flush_deferred_work(wl);
1218 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001219 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001220 mutex_lock(&wl->mutex);
1221out:
1222 return ret;
1223}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001224
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001225int wl1271_plt_stop(struct wl1271 *wl)
1226{
1227 int ret;
1228
1229 mutex_lock(&wl->mutex);
1230 ret = __wl1271_plt_stop(wl);
1231 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return ret;
1233}
1234
Johannes Berg7bb45682011-02-24 14:42:06 +01001235static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236{
1237 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001238 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001239 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001240 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241
Ido Yarivb07d4032011-03-01 15:14:43 +02001242 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1243
1244 if (wl->bss_type == BSS_TYPE_AP_BSS)
1245 hlid = wl1271_tx_get_hlid(skb);
1246
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001247 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001248
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001249 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001250
1251 /*
1252 * The workqueue is slow to process the tx_queue and we need stop
1253 * the queue here, otherwise the queue will get too long.
1254 */
1255 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1256 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1257 ieee80211_stop_queues(wl->hw);
1258 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1259 }
1260
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001261 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001262 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001263 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1264 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1265 } else {
1266 skb_queue_tail(&wl->tx_queue[q], skb);
1267 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001268
1269 /*
1270 * The chip specific setup must run before the first TX packet -
1271 * before that, the tx_work will not be initialized!
1272 */
1273
Ido Yarivb07d4032011-03-01 15:14:43 +02001274 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1275 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001276 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001277
1278 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001279}
1280
Shahar Leviae47c452011-03-06 16:32:14 +02001281int wl1271_tx_dummy_packet(struct wl1271 *wl)
1282{
Ido Yariv990f5de2011-03-31 10:06:59 +02001283 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001284
Ido Yariv990f5de2011-03-31 10:06:59 +02001285 spin_lock_irqsave(&wl->wl_lock, flags);
1286 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1287 wl->tx_queue_count++;
1288 spin_unlock_irqrestore(&wl->wl_lock, flags);
1289
1290 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1291 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1292 wl1271_tx_work_locked(wl);
1293
1294 /*
1295 * If the FW TX is busy, TX work will be scheduled by the threaded
1296 * interrupt handler function
1297 */
1298 return 0;
1299}
1300
1301/*
1302 * The size of the dummy packet should be at least 1400 bytes. However, in
1303 * order to minimize the number of bus transactions, aligning it to 512 bytes
1304 * boundaries could be beneficial, performance wise
1305 */
1306#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1307
Luciano Coelhocf27d862011-04-01 21:08:23 +03001308static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001309{
1310 struct sk_buff *skb;
1311 struct ieee80211_hdr_3addr *hdr;
1312 unsigned int dummy_packet_size;
1313
1314 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1315 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1316
1317 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001318 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001319 wl1271_warning("Failed to allocate a dummy packet skb");
1320 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001321 }
1322
1323 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1324
1325 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1326 memset(hdr, 0, sizeof(*hdr));
1327 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001328 IEEE80211_STYPE_NULLFUNC |
1329 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001330
Ido Yariv990f5de2011-03-31 10:06:59 +02001331 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001332
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001333 /* Dummy packets require the TID to be management */
1334 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001335
1336 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001337 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001338 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001339
Ido Yariv990f5de2011-03-31 10:06:59 +02001340 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001341}
1342
Ido Yariv990f5de2011-03-31 10:06:59 +02001343
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001344static struct notifier_block wl1271_dev_notifier = {
1345 .notifier_call = wl1271_dev_notify,
1346};
1347
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348static int wl1271_op_start(struct ieee80211_hw *hw)
1349{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001350 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1351
1352 /*
1353 * We have to delay the booting of the hardware because
1354 * we need to know the local MAC address before downloading and
1355 * initializing the firmware. The MAC address cannot be changed
1356 * after boot, and without the proper MAC address, the firmware
1357 * will not function properly.
1358 *
1359 * The MAC address is first known when the corresponding interface
1360 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001361 *
1362 * In addition, we currently have different firmwares for AP and managed
1363 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001364 */
1365
1366 return 0;
1367}
1368
1369static void wl1271_op_stop(struct ieee80211_hw *hw)
1370{
1371 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1372}
1373
1374static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1375 struct ieee80211_vif *vif)
1376{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001378 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001379 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001381 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001383 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1384 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001385
1386 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001387 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001388 wl1271_debug(DEBUG_MAC80211,
1389 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001390 ret = -EBUSY;
1391 goto out;
1392 }
1393
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001394 /*
1395 * in some very corner case HW recovery scenarios its possible to
1396 * get here before __wl1271_op_remove_interface is complete, so
1397 * opt out if that is the case.
1398 */
1399 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1400 ret = -EBUSY;
1401 goto out;
1402 }
1403
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001404 switch (vif->type) {
1405 case NL80211_IFTYPE_STATION:
1406 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001407 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001408 break;
1409 case NL80211_IFTYPE_ADHOC:
1410 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001411 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001412 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001413 case NL80211_IFTYPE_AP:
1414 wl->bss_type = BSS_TYPE_AP_BSS;
1415 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001416 default:
1417 ret = -EOPNOTSUPP;
1418 goto out;
1419 }
1420
1421 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001422
1423 if (wl->state != WL1271_STATE_OFF) {
1424 wl1271_error("cannot start because not in off state: %d",
1425 wl->state);
1426 ret = -EBUSY;
1427 goto out;
1428 }
1429
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001430 while (retries) {
1431 retries--;
1432 ret = wl1271_chip_wakeup(wl);
1433 if (ret < 0)
1434 goto power_off;
1435
1436 ret = wl1271_boot(wl);
1437 if (ret < 0)
1438 goto power_off;
1439
1440 ret = wl1271_hw_init(wl);
1441 if (ret < 0)
1442 goto irq_disable;
1443
Eliad Peller71125ab2010-10-28 21:46:43 +02001444 booted = true;
1445 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001447irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001448 mutex_unlock(&wl->mutex);
1449 /* Unlocking the mutex in the middle of handling is
1450 inherently unsafe. In this case we deem it safe to do,
1451 because we need to let any possibly pending IRQ out of
1452 the system (and while we are WL1271_STATE_OFF the IRQ
1453 work function will not do anything.) Also, any other
1454 possible concurrent operations will fail due to the
1455 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001456 wl1271_disable_interrupts(wl);
1457 wl1271_flush_deferred_work(wl);
1458 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001459 mutex_lock(&wl->mutex);
1460power_off:
1461 wl1271_power_off(wl);
1462 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463
Eliad Peller71125ab2010-10-28 21:46:43 +02001464 if (!booted) {
1465 wl1271_error("firmware boot failed despite %d retries",
1466 WL1271_BOOT_RETRIES);
1467 goto out;
1468 }
1469
1470 wl->vif = vif;
1471 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001472 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001473 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001474
1475 /* update hw/fw version info in wiphy struct */
1476 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001477 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001478 sizeof(wiphy->fw_version));
1479
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001480 /* Check if any quirks are needed with older fw versions */
1481 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1482
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001483 /*
1484 * Now we know if 11a is supported (info from the NVS), so disable
1485 * 11a channels if not supported
1486 */
1487 if (!wl->enable_11a)
1488 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1489
1490 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1491 wl->enable_11a ? "" : "not ");
1492
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001493out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001494 mutex_unlock(&wl->mutex);
1495
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001496 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001497 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001498 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001499 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001501 return ret;
1502}
1503
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001504static void __wl1271_op_remove_interface(struct wl1271 *wl,
1505 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001507 int i;
1508
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001509 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001511 /* because of hardware recovery, we may get here twice */
1512 if (wl->state != WL1271_STATE_ON)
1513 return;
1514
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001515 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001517 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001518 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001519 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001520
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001521 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001522 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001523 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001524
Luciano Coelho08688d62010-07-08 17:50:07 +03001525 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001526 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001527 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001528 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001529 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530 }
1531
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001532 /*
1533 * this must be before the cancel_work calls below, so that the work
1534 * functions don't perform further work.
1535 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001536 wl->state = WL1271_STATE_OFF;
1537
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538 mutex_unlock(&wl->mutex);
1539
Ido Yariva6208652011-03-01 15:14:41 +02001540 wl1271_disable_interrupts(wl);
1541 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001542 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001543 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001544 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001545 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001546 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001547
1548 mutex_lock(&wl->mutex);
1549
1550 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001551 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 wl1271_power_off(wl);
1553
1554 memset(wl->bssid, 0, ETH_ALEN);
1555 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1556 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001557 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001558 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001559 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560
1561 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001562 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001563 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1564 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001565 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 wl->tx_results_count = 0;
1567 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001568 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001569 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001570 wl->time_offset = 0;
1571 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001572 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001573 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001574 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001575 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001576 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001577 wl->ap_fw_ps_map = 0;
1578 wl->ap_ps_map = 0;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001579
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001580 /*
1581 * this is performed after the cancel_work calls and the associated
1582 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1583 * get executed before all these vars have been reset.
1584 */
1585 wl->flags = 0;
1586
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001587 for (i = 0; i < NUM_TX_QUEUES; i++)
1588 wl->tx_blocks_freed[i] = 0;
1589
1590 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001591
1592 kfree(wl->fw_status);
1593 wl->fw_status = NULL;
1594 kfree(wl->tx_res_if);
1595 wl->tx_res_if = NULL;
1596 kfree(wl->target_mem_map);
1597 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001598}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001599
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001600static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1601 struct ieee80211_vif *vif)
1602{
1603 struct wl1271 *wl = hw->priv;
1604
1605 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001606 /*
1607 * wl->vif can be null here if someone shuts down the interface
1608 * just when hardware recovery has been started.
1609 */
1610 if (wl->vif) {
1611 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001612 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001613 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001614
Juuso Oikarinen67353292010-11-18 15:19:02 +02001615 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001616 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001617}
1618
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001619void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001620{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001621 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001622
1623 /* combine requested filters with current filter config */
1624 filters = wl->filters | filters;
1625
1626 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1627
1628 if (filters & FIF_PROMISC_IN_BSS) {
1629 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1630 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1631 wl->rx_config |= CFG_BSSID_FILTER_EN;
1632 }
1633 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1634 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1635 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1636 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1637 }
1638 if (filters & FIF_OTHER_BSS) {
1639 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1640 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1641 }
1642 if (filters & FIF_CONTROL) {
1643 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1644 wl->rx_filter |= CFG_RX_CTL_EN;
1645 }
1646 if (filters & FIF_FCSFAIL) {
1647 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1648 wl->rx_filter |= CFG_RX_FCS_ERROR;
1649 }
1650}
1651
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001652static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001653{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001654 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001655 /* we need to use a dummy BSSID for now */
1656 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1657 0xad, 0xbe, 0xef };
1658
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001659 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1660
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001661 /* pass through frames from all BSS */
1662 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1663
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001664 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001665 if (ret < 0)
1666 goto out;
1667
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001668 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001669
1670out:
1671 return ret;
1672}
1673
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001674static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001675{
1676 int ret;
1677
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001678 /*
1679 * One of the side effects of the JOIN command is that is clears
1680 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1681 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001682 * Currently the only valid scenario for JOIN during association
1683 * is on roaming, in which case we will also be given new keys.
1684 * Keep the below message for now, unless it starts bothering
1685 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001686 */
1687 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1688 wl1271_info("JOIN while associated.");
1689
1690 if (set_assoc)
1691 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1692
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001693 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1694 if (ret < 0)
1695 goto out;
1696
1697 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1698
1699 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1700 goto out;
1701
1702 /*
1703 * The join command disable the keep-alive mode, shut down its process,
1704 * and also clear the template config, so we need to reset it all after
1705 * the join. The acx_aid starts the keep-alive process, and the order
1706 * of the commands below is relevant.
1707 */
1708 ret = wl1271_acx_keep_alive_mode(wl, true);
1709 if (ret < 0)
1710 goto out;
1711
1712 ret = wl1271_acx_aid(wl, wl->aid);
1713 if (ret < 0)
1714 goto out;
1715
1716 ret = wl1271_cmd_build_klv_null_data(wl);
1717 if (ret < 0)
1718 goto out;
1719
1720 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1721 ACX_KEEP_ALIVE_TPL_VALID);
1722 if (ret < 0)
1723 goto out;
1724
1725out:
1726 return ret;
1727}
1728
1729static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001730{
1731 int ret;
1732
1733 /* to stop listening to a channel, we disconnect */
1734 ret = wl1271_cmd_disconnect(wl);
1735 if (ret < 0)
1736 goto out;
1737
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001738 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001739 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001740
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001741 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001742 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001743
1744out:
1745 return ret;
1746}
1747
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001748static void wl1271_set_band_rate(struct wl1271 *wl)
1749{
1750 if (wl->band == IEEE80211_BAND_2GHZ)
1751 wl->basic_rate_set = wl->conf.tx.basic_rate;
1752 else
1753 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1754}
1755
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001756static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001757{
1758 int ret;
1759
1760 if (idle) {
1761 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1762 ret = wl1271_unjoin(wl);
1763 if (ret < 0)
1764 goto out;
1765 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001766 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001767 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001768 if (ret < 0)
1769 goto out;
1770 ret = wl1271_acx_keep_alive_config(
1771 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1772 ACX_KEEP_ALIVE_TPL_INVALID);
1773 if (ret < 0)
1774 goto out;
1775 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1776 } else {
1777 /* increment the session counter */
1778 wl->session_counter++;
1779 if (wl->session_counter >= SESSION_COUNTER_MAX)
1780 wl->session_counter = 0;
1781 ret = wl1271_dummy_join(wl);
1782 if (ret < 0)
1783 goto out;
1784 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1785 }
1786
1787out:
1788 return ret;
1789}
1790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001791static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1792{
1793 struct wl1271 *wl = hw->priv;
1794 struct ieee80211_conf *conf = &hw->conf;
1795 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001796 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001797
1798 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1799
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001800 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1801 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 channel,
1803 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001804 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001805 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1806 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001808 /*
1809 * mac80211 will go to idle nearly immediately after transmitting some
1810 * frames, such as the deauth. To make sure those frames reach the air,
1811 * wait here until the TX queue is fully flushed.
1812 */
1813 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1814 (conf->flags & IEEE80211_CONF_IDLE))
1815 wl1271_tx_flush(wl);
1816
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001817 mutex_lock(&wl->mutex);
1818
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001819 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001820 /* we support configuring the channel and band while off */
1821 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1822 wl->band = conf->channel->band;
1823 wl->channel = channel;
1824 }
1825
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001826 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001827 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001828
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001829 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1830
Ido Yariva6208652011-03-01 15:14:41 +02001831 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 if (ret < 0)
1833 goto out;
1834
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001835 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001836 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1837 ((wl->band != conf->channel->band) ||
1838 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001839 wl->band = conf->channel->band;
1840 wl->channel = channel;
1841
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001842 if (!is_ap) {
1843 /*
1844 * FIXME: the mac80211 should really provide a fixed
1845 * rate to use here. for now, just use the smallest
1846 * possible rate for the band as a fixed rate for
1847 * association frames and other control messages.
1848 */
1849 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1850 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001851
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001852 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1853 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001854 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001855 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001856 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001857
1858 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1859 ret = wl1271_join(wl, false);
1860 if (ret < 0)
1861 wl1271_warning("cmd join on channel "
1862 "failed %d", ret);
1863 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001864 }
1865 }
1866
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001867 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1868 ret = wl1271_sta_handle_idle(wl,
1869 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001870 if (ret < 0)
1871 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872 }
1873
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001874 /*
1875 * if mac80211 changes the PSM mode, make sure the mode is not
1876 * incorrectly changed after the pspoll failure active window.
1877 */
1878 if (changed & IEEE80211_CONF_CHANGE_PS)
1879 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1880
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001881 if (conf->flags & IEEE80211_CONF_PS &&
1882 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1883 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001884
1885 /*
1886 * We enter PSM only if we're already associated.
1887 * If we're not, we'll enter it when joining an SSID,
1888 * through the bss_info_changed() hook.
1889 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001890 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001891 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001892 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001893 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001894 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001895 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001896 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001897 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001898
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001899 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001900
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001901 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001902 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001903 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001904 }
1905
1906 if (conf->power_level != wl->power_level) {
1907 ret = wl1271_acx_tx_power(wl, conf->power_level);
1908 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001909 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001910
1911 wl->power_level = conf->power_level;
1912 }
1913
1914out_sleep:
1915 wl1271_ps_elp_sleep(wl);
1916
1917out:
1918 mutex_unlock(&wl->mutex);
1919
1920 return ret;
1921}
1922
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001923struct wl1271_filter_params {
1924 bool enabled;
1925 int mc_list_length;
1926 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1927};
1928
Jiri Pirko22bedad32010-04-01 21:22:57 +00001929static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1930 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001931{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001932 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001933 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001934 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001935
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001936 if (unlikely(wl->state == WL1271_STATE_OFF))
1937 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001938
Juuso Oikarinen74441132009-10-13 12:47:53 +03001939 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001940 if (!fp) {
1941 wl1271_error("Out of memory setting filters.");
1942 return 0;
1943 }
1944
1945 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001946 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001947 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1948 fp->enabled = false;
1949 } else {
1950 fp->enabled = true;
1951 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001952 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001953 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001954 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001955 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001956 }
1957
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001958 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001959}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001960
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001961#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1962 FIF_ALLMULTI | \
1963 FIF_FCSFAIL | \
1964 FIF_BCN_PRBRESP_PROMISC | \
1965 FIF_CONTROL | \
1966 FIF_OTHER_BSS)
1967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1969 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001970 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001972 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001974 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
Arik Nemtsov7d057862010-10-16 19:25:35 +02001976 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
1977 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001978
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001979 mutex_lock(&wl->mutex);
1980
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001981 *total &= WL1271_SUPPORTED_FILTERS;
1982 changed &= WL1271_SUPPORTED_FILTERS;
1983
1984 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001985 goto out;
1986
Ido Yariva6208652011-03-01 15:14:41 +02001987 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001988 if (ret < 0)
1989 goto out;
1990
Arik Nemtsov7d057862010-10-16 19:25:35 +02001991 if (wl->bss_type != BSS_TYPE_AP_BSS) {
1992 if (*total & FIF_ALLMULTI)
1993 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
1994 else if (fp)
1995 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
1996 fp->mc_list,
1997 fp->mc_list_length);
1998 if (ret < 0)
1999 goto out_sleep;
2000 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002002 /* determine, whether supported filter values have changed */
2003 if (changed == 0)
2004 goto out_sleep;
2005
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002006 /* configure filters */
2007 wl->filters = *total;
2008 wl1271_configure_filters(wl, 0);
2009
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002010 /* apply configured filters */
2011 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2012 if (ret < 0)
2013 goto out_sleep;
2014
2015out_sleep:
2016 wl1271_ps_elp_sleep(wl);
2017
2018out:
2019 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002020 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002021}
2022
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002023static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2024 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2025 u16 tx_seq_16)
2026{
2027 struct wl1271_ap_key *ap_key;
2028 int i;
2029
2030 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2031
2032 if (key_size > MAX_KEY_SIZE)
2033 return -EINVAL;
2034
2035 /*
2036 * Find next free entry in ap_keys. Also check we are not replacing
2037 * an existing key.
2038 */
2039 for (i = 0; i < MAX_NUM_KEYS; i++) {
2040 if (wl->recorded_ap_keys[i] == NULL)
2041 break;
2042
2043 if (wl->recorded_ap_keys[i]->id == id) {
2044 wl1271_warning("trying to record key replacement");
2045 return -EINVAL;
2046 }
2047 }
2048
2049 if (i == MAX_NUM_KEYS)
2050 return -EBUSY;
2051
2052 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2053 if (!ap_key)
2054 return -ENOMEM;
2055
2056 ap_key->id = id;
2057 ap_key->key_type = key_type;
2058 ap_key->key_size = key_size;
2059 memcpy(ap_key->key, key, key_size);
2060 ap_key->hlid = hlid;
2061 ap_key->tx_seq_32 = tx_seq_32;
2062 ap_key->tx_seq_16 = tx_seq_16;
2063
2064 wl->recorded_ap_keys[i] = ap_key;
2065 return 0;
2066}
2067
2068static void wl1271_free_ap_keys(struct wl1271 *wl)
2069{
2070 int i;
2071
2072 for (i = 0; i < MAX_NUM_KEYS; i++) {
2073 kfree(wl->recorded_ap_keys[i]);
2074 wl->recorded_ap_keys[i] = NULL;
2075 }
2076}
2077
2078static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2079{
2080 int i, ret = 0;
2081 struct wl1271_ap_key *key;
2082 bool wep_key_added = false;
2083
2084 for (i = 0; i < MAX_NUM_KEYS; i++) {
2085 if (wl->recorded_ap_keys[i] == NULL)
2086 break;
2087
2088 key = wl->recorded_ap_keys[i];
2089 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2090 key->id, key->key_type,
2091 key->key_size, key->key,
2092 key->hlid, key->tx_seq_32,
2093 key->tx_seq_16);
2094 if (ret < 0)
2095 goto out;
2096
2097 if (key->key_type == KEY_WEP)
2098 wep_key_added = true;
2099 }
2100
2101 if (wep_key_added) {
2102 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2103 if (ret < 0)
2104 goto out;
2105 }
2106
2107out:
2108 wl1271_free_ap_keys(wl);
2109 return ret;
2110}
2111
2112static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2113 u8 key_size, const u8 *key, u32 tx_seq_32,
2114 u16 tx_seq_16, struct ieee80211_sta *sta)
2115{
2116 int ret;
2117 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2118
2119 if (is_ap) {
2120 struct wl1271_station *wl_sta;
2121 u8 hlid;
2122
2123 if (sta) {
2124 wl_sta = (struct wl1271_station *)sta->drv_priv;
2125 hlid = wl_sta->hlid;
2126 } else {
2127 hlid = WL1271_AP_BROADCAST_HLID;
2128 }
2129
2130 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2131 /*
2132 * We do not support removing keys after AP shutdown.
2133 * Pretend we do to make mac80211 happy.
2134 */
2135 if (action != KEY_ADD_OR_REPLACE)
2136 return 0;
2137
2138 ret = wl1271_record_ap_key(wl, id,
2139 key_type, key_size,
2140 key, hlid, tx_seq_32,
2141 tx_seq_16);
2142 } else {
2143 ret = wl1271_cmd_set_ap_key(wl, action,
2144 id, key_type, key_size,
2145 key, hlid, tx_seq_32,
2146 tx_seq_16);
2147 }
2148
2149 if (ret < 0)
2150 return ret;
2151 } else {
2152 const u8 *addr;
2153 static const u8 bcast_addr[ETH_ALEN] = {
2154 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2155 };
2156
2157 addr = sta ? sta->addr : bcast_addr;
2158
2159 if (is_zero_ether_addr(addr)) {
2160 /* We dont support TX only encryption */
2161 return -EOPNOTSUPP;
2162 }
2163
2164 /* The wl1271 does not allow to remove unicast keys - they
2165 will be cleared automatically on next CMD_JOIN. Ignore the
2166 request silently, as we dont want the mac80211 to emit
2167 an error message. */
2168 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2169 return 0;
2170
2171 ret = wl1271_cmd_set_sta_key(wl, action,
2172 id, key_type, key_size,
2173 key, addr, tx_seq_32,
2174 tx_seq_16);
2175 if (ret < 0)
2176 return ret;
2177
2178 /* the default WEP key needs to be configured at least once */
2179 if (key_type == KEY_WEP) {
2180 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2181 wl->default_key);
2182 if (ret < 0)
2183 return ret;
2184 }
2185 }
2186
2187 return 0;
2188}
2189
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002190static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2191 struct ieee80211_vif *vif,
2192 struct ieee80211_sta *sta,
2193 struct ieee80211_key_conf *key_conf)
2194{
2195 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002196 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002197 u32 tx_seq_32 = 0;
2198 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199 u8 key_type;
2200
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2202
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002203 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002204 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002205 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002206 key_conf->keylen, key_conf->flags);
2207 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2208
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209 mutex_lock(&wl->mutex);
2210
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002211 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2212 ret = -EAGAIN;
2213 goto out_unlock;
2214 }
2215
Ido Yariva6208652011-03-01 15:14:41 +02002216 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002217 if (ret < 0)
2218 goto out_unlock;
2219
Johannes Berg97359d12010-08-10 09:46:38 +02002220 switch (key_conf->cipher) {
2221 case WLAN_CIPHER_SUITE_WEP40:
2222 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002223 key_type = KEY_WEP;
2224
2225 key_conf->hw_key_idx = key_conf->keyidx;
2226 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002227 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002228 key_type = KEY_TKIP;
2229
2230 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002231 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2232 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002233 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002234 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002235 key_type = KEY_AES;
2236
2237 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002238 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2239 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002240 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002241 case WL1271_CIPHER_SUITE_GEM:
2242 key_type = KEY_GEM;
2243 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2244 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2245 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002246 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002247 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002248
2249 ret = -EOPNOTSUPP;
2250 goto out_sleep;
2251 }
2252
2253 switch (cmd) {
2254 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002255 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2256 key_conf->keyidx, key_type,
2257 key_conf->keylen, key_conf->key,
2258 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002259 if (ret < 0) {
2260 wl1271_error("Could not add or replace key");
2261 goto out_sleep;
2262 }
2263 break;
2264
2265 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002266 ret = wl1271_set_key(wl, KEY_REMOVE,
2267 key_conf->keyidx, key_type,
2268 key_conf->keylen, key_conf->key,
2269 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270 if (ret < 0) {
2271 wl1271_error("Could not remove key");
2272 goto out_sleep;
2273 }
2274 break;
2275
2276 default:
2277 wl1271_error("Unsupported key cmd 0x%x", cmd);
2278 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279 break;
2280 }
2281
2282out_sleep:
2283 wl1271_ps_elp_sleep(wl);
2284
2285out_unlock:
2286 mutex_unlock(&wl->mutex);
2287
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002288 return ret;
2289}
2290
2291static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002292 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293 struct cfg80211_scan_request *req)
2294{
2295 struct wl1271 *wl = hw->priv;
2296 int ret;
2297 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002298 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299
2300 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2301
2302 if (req->n_ssids) {
2303 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002304 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305 }
2306
2307 mutex_lock(&wl->mutex);
2308
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002309 if (wl->state == WL1271_STATE_OFF) {
2310 /*
2311 * We cannot return -EBUSY here because cfg80211 will expect
2312 * a call to ieee80211_scan_completed if we do - in this case
2313 * there won't be any call.
2314 */
2315 ret = -EAGAIN;
2316 goto out;
2317 }
2318
Ido Yariva6208652011-03-01 15:14:41 +02002319 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002320 if (ret < 0)
2321 goto out;
2322
Luciano Coelho5924f892010-08-04 03:46:22 +03002323 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002324
2325 wl1271_ps_elp_sleep(wl);
2326
2327out:
2328 mutex_unlock(&wl->mutex);
2329
2330 return ret;
2331}
2332
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002333static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2334{
2335 struct wl1271 *wl = hw->priv;
2336 int ret = 0;
2337
2338 mutex_lock(&wl->mutex);
2339
2340 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2341 ret = -EAGAIN;
2342 goto out;
2343 }
2344
Ido Yariva6208652011-03-01 15:14:41 +02002345 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002346 if (ret < 0)
2347 goto out;
2348
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002349 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002350 if (ret < 0)
2351 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2352
2353 wl1271_ps_elp_sleep(wl);
2354
2355out:
2356 mutex_unlock(&wl->mutex);
2357
2358 return ret;
2359}
2360
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2362{
2363 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002364 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365
2366 mutex_lock(&wl->mutex);
2367
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002368 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2369 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002370 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002371 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002372
Ido Yariva6208652011-03-01 15:14:41 +02002373 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002374 if (ret < 0)
2375 goto out;
2376
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002377 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002378 if (ret < 0)
2379 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2380
2381 wl1271_ps_elp_sleep(wl);
2382
2383out:
2384 mutex_unlock(&wl->mutex);
2385
2386 return ret;
2387}
2388
Arik Nemtsove78a2872010-10-16 19:07:21 +02002389static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002390 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002391{
Eliad Peller889cb362011-05-01 09:56:45 +03002392 u8 ssid_len;
2393 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2394 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002395
Eliad Peller889cb362011-05-01 09:56:45 +03002396 if (!ptr) {
2397 wl1271_error("No SSID in IEs!");
2398 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002399 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002400
Eliad Peller889cb362011-05-01 09:56:45 +03002401 ssid_len = ptr[1];
2402 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2403 wl1271_error("SSID is too long!");
2404 return -EINVAL;
2405 }
2406
2407 wl->ssid_len = ssid_len;
2408 memcpy(wl->ssid, ptr+2, ssid_len);
2409 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002410}
2411
Arik Nemtsove78a2872010-10-16 19:07:21 +02002412static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2413 struct ieee80211_bss_conf *bss_conf,
2414 u32 changed)
2415{
2416 int ret = 0;
2417
2418 if (changed & BSS_CHANGED_ERP_SLOT) {
2419 if (bss_conf->use_short_slot)
2420 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2421 else
2422 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2423 if (ret < 0) {
2424 wl1271_warning("Set slot time failed %d", ret);
2425 goto out;
2426 }
2427 }
2428
2429 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2430 if (bss_conf->use_short_preamble)
2431 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2432 else
2433 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2434 }
2435
2436 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2437 if (bss_conf->use_cts_prot)
2438 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2439 else
2440 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2441 if (ret < 0) {
2442 wl1271_warning("Set ctsprotect failed %d", ret);
2443 goto out;
2444 }
2445 }
2446
2447out:
2448 return ret;
2449}
2450
2451static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2452 struct ieee80211_vif *vif,
2453 struct ieee80211_bss_conf *bss_conf,
2454 u32 changed)
2455{
2456 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2457 int ret = 0;
2458
2459 if ((changed & BSS_CHANGED_BEACON_INT)) {
2460 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2461 bss_conf->beacon_int);
2462
2463 wl->beacon_int = bss_conf->beacon_int;
2464 }
2465
2466 if ((changed & BSS_CHANGED_BEACON)) {
2467 struct ieee80211_hdr *hdr;
2468 int ieoffset = offsetof(struct ieee80211_mgmt,
2469 u.beacon.variable);
2470 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2471 u16 tmpl_id;
2472
2473 if (!beacon)
2474 goto out;
2475
2476 wl1271_debug(DEBUG_MASTER, "beacon updated");
2477
2478 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2479 if (ret < 0) {
2480 dev_kfree_skb(beacon);
2481 goto out;
2482 }
2483 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2484 CMD_TEMPL_BEACON;
2485 ret = wl1271_cmd_template_set(wl, tmpl_id,
2486 beacon->data,
2487 beacon->len, 0,
2488 wl1271_tx_min_rate_get(wl));
2489 if (ret < 0) {
2490 dev_kfree_skb(beacon);
2491 goto out;
2492 }
2493
2494 hdr = (struct ieee80211_hdr *) beacon->data;
2495 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2496 IEEE80211_STYPE_PROBE_RESP);
2497
2498 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2499 CMD_TEMPL_PROBE_RESPONSE;
2500 ret = wl1271_cmd_template_set(wl,
2501 tmpl_id,
2502 beacon->data,
2503 beacon->len, 0,
2504 wl1271_tx_min_rate_get(wl));
2505 dev_kfree_skb(beacon);
2506 if (ret < 0)
2507 goto out;
2508 }
2509
2510out:
2511 return ret;
2512}
2513
2514/* AP mode changes */
2515static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002516 struct ieee80211_vif *vif,
2517 struct ieee80211_bss_conf *bss_conf,
2518 u32 changed)
2519{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002520 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521
Arik Nemtsove78a2872010-10-16 19:07:21 +02002522 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2523 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524
Arik Nemtsove78a2872010-10-16 19:07:21 +02002525 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2526 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002527
Arik Nemtsov70f47422011-04-18 14:15:25 +03002528 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002529 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002530 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002531 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002532 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002533
2534 ret = wl1271_ap_init_templates(wl);
2535 if (ret < 0)
2536 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002537 }
2538
Arik Nemtsove78a2872010-10-16 19:07:21 +02002539 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2540 if (ret < 0)
2541 goto out;
2542
2543 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2544 if (bss_conf->enable_beacon) {
2545 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2546 ret = wl1271_cmd_start_bss(wl);
2547 if (ret < 0)
2548 goto out;
2549
2550 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2551 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002552
2553 ret = wl1271_ap_init_hwenc(wl);
2554 if (ret < 0)
2555 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002556 }
2557 } else {
2558 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2559 ret = wl1271_cmd_stop_bss(wl);
2560 if (ret < 0)
2561 goto out;
2562
2563 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2564 wl1271_debug(DEBUG_AP, "stopped AP");
2565 }
2566 }
2567 }
2568
Eliad Pellercb5ae052011-04-07 15:52:05 +03002569 if (changed & BSS_CHANGED_IBSS) {
2570 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2571 bss_conf->ibss_joined);
2572
2573 if (bss_conf->ibss_joined) {
2574 u32 rates = bss_conf->basic_rates;
2575 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2576 rates);
2577 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2578
2579 /* by default, use 11b rates */
2580 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2581 ret = wl1271_acx_sta_rate_policies(wl);
2582 if (ret < 0)
2583 goto out;
2584 }
2585 }
2586
Arik Nemtsove78a2872010-10-16 19:07:21 +02002587 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2588 if (ret < 0)
2589 goto out;
2590out:
2591 return;
2592}
2593
2594/* STA/IBSS mode changes */
2595static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2596 struct ieee80211_vif *vif,
2597 struct ieee80211_bss_conf *bss_conf,
2598 u32 changed)
2599{
2600 bool do_join = false, set_assoc = false;
2601 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002602 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002603 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002604 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002605 bool sta_exists = false;
2606 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002607
2608 if (is_ibss) {
2609 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2610 changed);
2611 if (ret < 0)
2612 goto out;
2613 }
2614
2615 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2616 do_join = true;
2617
2618 /* Need to update the SSID (for filtering etc) */
2619 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2620 do_join = true;
2621
2622 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002623 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2624 bss_conf->enable_beacon ? "enabled" : "disabled");
2625
2626 if (bss_conf->enable_beacon)
2627 wl->set_bss_type = BSS_TYPE_IBSS;
2628 else
2629 wl->set_bss_type = BSS_TYPE_STA_BSS;
2630 do_join = true;
2631 }
2632
Arik Nemtsove78a2872010-10-16 19:07:21 +02002633 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002634 bool enable = false;
2635 if (bss_conf->cqm_rssi_thold)
2636 enable = true;
2637 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2638 bss_conf->cqm_rssi_thold,
2639 bss_conf->cqm_rssi_hyst);
2640 if (ret < 0)
2641 goto out;
2642 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2643 }
2644
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002645 if ((changed & BSS_CHANGED_BSSID) &&
2646 /*
2647 * Now we know the correct bssid, so we send a new join command
2648 * and enable the BSSID filter
2649 */
2650 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002651 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002652
Eliad Pellerfa287b82010-12-26 09:27:50 +01002653 if (!is_zero_ether_addr(wl->bssid)) {
2654 ret = wl1271_cmd_build_null_data(wl);
2655 if (ret < 0)
2656 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002657
Eliad Pellerfa287b82010-12-26 09:27:50 +01002658 ret = wl1271_build_qos_null_data(wl);
2659 if (ret < 0)
2660 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002661
Eliad Pellerfa287b82010-12-26 09:27:50 +01002662 /* filter out all packets not from this BSSID */
2663 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002664
Eliad Pellerfa287b82010-12-26 09:27:50 +01002665 /* Need to update the BSSID (for filtering etc) */
2666 do_join = true;
2667 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002668 }
2669
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002670 rcu_read_lock();
2671 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2672 if (sta) {
2673 /* save the supp_rates of the ap */
2674 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2675 if (sta->ht_cap.ht_supported)
2676 sta_rate_set |=
2677 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002678 sta_ht_cap = sta->ht_cap;
2679 sta_exists = true;
2680 }
2681 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002682
Arik Nemtsova1008852011-02-12 23:24:20 +02002683 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002684 /* handle new association with HT and HT information change */
2685 if ((changed & BSS_CHANGED_HT) &&
2686 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002687 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002688 true);
2689 if (ret < 0) {
2690 wl1271_warning("Set ht cap true failed %d",
2691 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002692 goto out;
2693 }
2694 ret = wl1271_acx_set_ht_information(wl,
2695 bss_conf->ht_operation_mode);
2696 if (ret < 0) {
2697 wl1271_warning("Set ht information failed %d",
2698 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002699 goto out;
2700 }
2701 }
2702 /* handle new association without HT and disassociation */
2703 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002704 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002705 false);
2706 if (ret < 0) {
2707 wl1271_warning("Set ht cap false failed %d",
2708 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002709 goto out;
2710 }
2711 }
2712 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002713
Arik Nemtsove78a2872010-10-16 19:07:21 +02002714 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002715 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002716 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002717 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002718 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002719 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002721 wl->ps_poll_failures = 0;
2722
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002723 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002724 * use basic rates from AP, and determine lowest rate
2725 * to use with control frames.
2726 */
2727 rates = bss_conf->basic_rates;
2728 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2729 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002730 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002731 if (sta_rate_set)
2732 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2733 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002734 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002735 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002736 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002737
2738 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002739 * with wl1271, we don't need to update the
2740 * beacon_int and dtim_period, because the firmware
2741 * updates it by itself when the first beacon is
2742 * received after a join.
2743 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002744 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2745 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002746 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002748 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002749 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002750 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002751 dev_kfree_skb(wl->probereq);
2752 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2753 ieoffset = offsetof(struct ieee80211_mgmt,
2754 u.probe_req.variable);
2755 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002756
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002757 /* enable the connection monitoring feature */
2758 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002759 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002760 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002761
2762 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002763 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2764 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002765 enum wl1271_cmd_ps_mode mode;
2766
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002767 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002768 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002769 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002770 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002771 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002772 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002773 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002774 } else {
2775 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002776 bool was_assoc =
2777 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2778 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002779 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002780 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002781
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002782 /* free probe-request template */
2783 dev_kfree_skb(wl->probereq);
2784 wl->probereq = NULL;
2785
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002786 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002787 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002788
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002789 /* revert back to minimum rates for the current band */
2790 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002791 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002792 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002793 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002794 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002795
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002796 /* disable connection monitor features */
2797 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002798
2799 /* Disable the keep-alive feature */
2800 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002801 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002802 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002803
2804 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002805 if (was_assoc) {
2806 wl1271_unjoin(wl);
2807 wl1271_dummy_join(wl);
2808 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809 }
2810 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002811
Arik Nemtsove78a2872010-10-16 19:07:21 +02002812 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2813 if (ret < 0)
2814 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002815
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002816 if (changed & BSS_CHANGED_ARP_FILTER) {
2817 __be32 addr = bss_conf->arp_addr_list[0];
2818 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2819
Eliad Pellerc5312772010-12-09 11:31:27 +02002820 if (bss_conf->arp_addr_cnt == 1 &&
2821 bss_conf->arp_filter_enabled) {
2822 /*
2823 * The template should have been configured only upon
2824 * association. however, it seems that the correct ip
2825 * isn't being set (when sending), so we have to
2826 * reconfigure the template upon every ip change.
2827 */
2828 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2829 if (ret < 0) {
2830 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002831 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002832 }
2833
2834 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002835 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002836 addr);
2837 } else
2838 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002839
2840 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002841 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002842 }
2843
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002844 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002845 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002846 if (ret < 0) {
2847 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002848 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002849 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002850 }
2851
Arik Nemtsove78a2872010-10-16 19:07:21 +02002852out:
2853 return;
2854}
2855
2856static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2857 struct ieee80211_vif *vif,
2858 struct ieee80211_bss_conf *bss_conf,
2859 u32 changed)
2860{
2861 struct wl1271 *wl = hw->priv;
2862 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2863 int ret;
2864
2865 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2866 (int)changed);
2867
2868 mutex_lock(&wl->mutex);
2869
2870 if (unlikely(wl->state == WL1271_STATE_OFF))
2871 goto out;
2872
Ido Yariva6208652011-03-01 15:14:41 +02002873 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002874 if (ret < 0)
2875 goto out;
2876
2877 if (is_ap)
2878 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2879 else
2880 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002882 wl1271_ps_elp_sleep(wl);
2883
2884out:
2885 mutex_unlock(&wl->mutex);
2886}
2887
Kalle Valoc6999d82010-02-18 13:25:41 +02002888static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2889 const struct ieee80211_tx_queue_params *params)
2890{
2891 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002892 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002893 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002894
2895 mutex_lock(&wl->mutex);
2896
2897 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2898
Kalle Valo4695dc92010-03-18 12:26:38 +02002899 if (params->uapsd)
2900 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2901 else
2902 ps_scheme = CONF_PS_SCHEME_LEGACY;
2903
Arik Nemtsov488fc542010-10-16 20:33:45 +02002904 if (wl->state == WL1271_STATE_OFF) {
2905 /*
2906 * If the state is off, the parameters will be recorded and
2907 * configured on init. This happens in AP-mode.
2908 */
2909 struct conf_tx_ac_category *conf_ac =
2910 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2911 struct conf_tx_tid *conf_tid =
2912 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2913
2914 conf_ac->ac = wl1271_tx_get_queue(queue);
2915 conf_ac->cw_min = (u8)params->cw_min;
2916 conf_ac->cw_max = params->cw_max;
2917 conf_ac->aifsn = params->aifs;
2918 conf_ac->tx_op_limit = params->txop << 5;
2919
2920 conf_tid->queue_id = wl1271_tx_get_queue(queue);
2921 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
2922 conf_tid->tsid = wl1271_tx_get_queue(queue);
2923 conf_tid->ps_scheme = ps_scheme;
2924 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
2925 conf_tid->apsd_conf[0] = 0;
2926 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002927 goto out;
2928 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02002929
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002930 ret = wl1271_ps_elp_wakeup(wl);
2931 if (ret < 0)
2932 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002933
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002934 /*
2935 * the txop is confed in units of 32us by the mac80211,
2936 * we need us
2937 */
2938 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
2939 params->cw_min, params->cw_max,
2940 params->aifs, params->txop << 5);
2941 if (ret < 0)
2942 goto out_sleep;
2943
2944 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
2945 CONF_CHANNEL_TYPE_EDCF,
2946 wl1271_tx_get_queue(queue),
2947 ps_scheme, CONF_ACK_POLICY_LEGACY,
2948 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02002949
2950out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02002951 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02002952
2953out:
2954 mutex_unlock(&wl->mutex);
2955
2956 return ret;
2957}
2958
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002959static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
2960{
2961
2962 struct wl1271 *wl = hw->priv;
2963 u64 mactime = ULLONG_MAX;
2964 int ret;
2965
2966 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
2967
2968 mutex_lock(&wl->mutex);
2969
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002970 if (unlikely(wl->state == WL1271_STATE_OFF))
2971 goto out;
2972
Ido Yariva6208652011-03-01 15:14:41 +02002973 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03002974 if (ret < 0)
2975 goto out;
2976
2977 ret = wl1271_acx_tsf_info(wl, &mactime);
2978 if (ret < 0)
2979 goto out_sleep;
2980
2981out_sleep:
2982 wl1271_ps_elp_sleep(wl);
2983
2984out:
2985 mutex_unlock(&wl->mutex);
2986 return mactime;
2987}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002988
John W. Linvilleece550d2010-07-28 16:41:06 -04002989static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
2990 struct survey_info *survey)
2991{
2992 struct wl1271 *wl = hw->priv;
2993 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002994
John W. Linvilleece550d2010-07-28 16:41:06 -04002995 if (idx != 0)
2996 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002997
John W. Linvilleece550d2010-07-28 16:41:06 -04002998 survey->channel = conf->channel;
2999 survey->filled = SURVEY_INFO_NOISE_DBM;
3000 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003001
John W. Linvilleece550d2010-07-28 16:41:06 -04003002 return 0;
3003}
3004
Arik Nemtsov409622e2011-02-23 00:22:29 +02003005static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003006 struct ieee80211_sta *sta,
3007 u8 *hlid)
3008{
3009 struct wl1271_station *wl_sta;
3010 int id;
3011
3012 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3013 if (id >= AP_MAX_STATIONS) {
3014 wl1271_warning("could not allocate HLID - too much stations");
3015 return -EBUSY;
3016 }
3017
3018 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003019 __set_bit(id, wl->ap_hlid_map);
3020 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3021 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003022 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003023 return 0;
3024}
3025
Arik Nemtsov409622e2011-02-23 00:22:29 +02003026static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003027{
3028 int id = hlid - WL1271_AP_STA_HLID_START;
3029
Arik Nemtsov409622e2011-02-23 00:22:29 +02003030 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3031 return;
3032
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003033 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003034 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003035 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003036 __clear_bit(hlid, &wl->ap_ps_map);
3037 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003038}
3039
3040static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3041 struct ieee80211_vif *vif,
3042 struct ieee80211_sta *sta)
3043{
3044 struct wl1271 *wl = hw->priv;
3045 int ret = 0;
3046 u8 hlid;
3047
3048 mutex_lock(&wl->mutex);
3049
3050 if (unlikely(wl->state == WL1271_STATE_OFF))
3051 goto out;
3052
3053 if (wl->bss_type != BSS_TYPE_AP_BSS)
3054 goto out;
3055
3056 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3057
Arik Nemtsov409622e2011-02-23 00:22:29 +02003058 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003059 if (ret < 0)
3060 goto out;
3061
Ido Yariva6208652011-03-01 15:14:41 +02003062 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003063 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003064 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003065
3066 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3067 if (ret < 0)
3068 goto out_sleep;
3069
3070out_sleep:
3071 wl1271_ps_elp_sleep(wl);
3072
Arik Nemtsov409622e2011-02-23 00:22:29 +02003073out_free_sta:
3074 if (ret < 0)
3075 wl1271_free_sta(wl, hlid);
3076
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003077out:
3078 mutex_unlock(&wl->mutex);
3079 return ret;
3080}
3081
3082static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3083 struct ieee80211_vif *vif,
3084 struct ieee80211_sta *sta)
3085{
3086 struct wl1271 *wl = hw->priv;
3087 struct wl1271_station *wl_sta;
3088 int ret = 0, id;
3089
3090 mutex_lock(&wl->mutex);
3091
3092 if (unlikely(wl->state == WL1271_STATE_OFF))
3093 goto out;
3094
3095 if (wl->bss_type != BSS_TYPE_AP_BSS)
3096 goto out;
3097
3098 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3099
3100 wl_sta = (struct wl1271_station *)sta->drv_priv;
3101 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3102 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3103 goto out;
3104
Ido Yariva6208652011-03-01 15:14:41 +02003105 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003106 if (ret < 0)
3107 goto out;
3108
3109 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3110 if (ret < 0)
3111 goto out_sleep;
3112
Arik Nemtsov409622e2011-02-23 00:22:29 +02003113 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003114
3115out_sleep:
3116 wl1271_ps_elp_sleep(wl);
3117
3118out:
3119 mutex_unlock(&wl->mutex);
3120 return ret;
3121}
3122
Luciano Coelho4623ec72011-03-21 19:26:41 +02003123static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3124 struct ieee80211_vif *vif,
3125 enum ieee80211_ampdu_mlme_action action,
3126 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3127 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003128{
3129 struct wl1271 *wl = hw->priv;
3130 int ret;
3131
3132 mutex_lock(&wl->mutex);
3133
3134 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3135 ret = -EAGAIN;
3136 goto out;
3137 }
3138
Ido Yariva6208652011-03-01 15:14:41 +02003139 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003140 if (ret < 0)
3141 goto out;
3142
3143 switch (action) {
3144 case IEEE80211_AMPDU_RX_START:
3145 if (wl->ba_support) {
3146 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3147 true);
3148 if (!ret)
3149 wl->ba_rx_bitmap |= BIT(tid);
3150 } else {
3151 ret = -ENOTSUPP;
3152 }
3153 break;
3154
3155 case IEEE80211_AMPDU_RX_STOP:
3156 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3157 if (!ret)
3158 wl->ba_rx_bitmap &= ~BIT(tid);
3159 break;
3160
3161 /*
3162 * The BA initiator session management in FW independently.
3163 * Falling break here on purpose for all TX APDU commands.
3164 */
3165 case IEEE80211_AMPDU_TX_START:
3166 case IEEE80211_AMPDU_TX_STOP:
3167 case IEEE80211_AMPDU_TX_OPERATIONAL:
3168 ret = -EINVAL;
3169 break;
3170
3171 default:
3172 wl1271_error("Incorrect ampdu action id=%x\n", action);
3173 ret = -EINVAL;
3174 }
3175
3176 wl1271_ps_elp_sleep(wl);
3177
3178out:
3179 mutex_unlock(&wl->mutex);
3180
3181 return ret;
3182}
3183
Arik Nemtsov33437892011-04-26 23:35:39 +03003184static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3185{
3186 struct wl1271 *wl = hw->priv;
3187 bool ret = false;
3188
3189 mutex_lock(&wl->mutex);
3190
3191 if (unlikely(wl->state == WL1271_STATE_OFF))
3192 goto out;
3193
3194 /* packets are considered pending if in the TX queue or the FW */
3195 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3196
3197 /* the above is appropriate for STA mode for PS purposes */
3198 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3199
3200out:
3201 mutex_unlock(&wl->mutex);
3202
3203 return ret;
3204}
3205
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206/* can't be const, mac80211 writes to this */
3207static struct ieee80211_rate wl1271_rates[] = {
3208 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003209 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3210 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003212 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3213 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003214 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3215 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003216 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3217 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3219 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003220 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3221 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003222 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3223 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003224 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3225 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003227 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3228 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003229 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003230 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3231 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003233 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3234 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003235 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003236 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3237 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003238 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003239 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3240 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003241 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003242 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3243 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003244 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003245 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3246 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003247};
3248
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003249/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003250static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003251 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003252 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003253 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3254 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3255 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003256 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003257 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3258 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3259 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003260 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003261 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3262 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3263 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003264 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003265};
3266
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003267/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003268static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003269 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003270 7, /* CONF_HW_RXTX_RATE_MCS7 */
3271 6, /* CONF_HW_RXTX_RATE_MCS6 */
3272 5, /* CONF_HW_RXTX_RATE_MCS5 */
3273 4, /* CONF_HW_RXTX_RATE_MCS4 */
3274 3, /* CONF_HW_RXTX_RATE_MCS3 */
3275 2, /* CONF_HW_RXTX_RATE_MCS2 */
3276 1, /* CONF_HW_RXTX_RATE_MCS1 */
3277 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003278
3279 11, /* CONF_HW_RXTX_RATE_54 */
3280 10, /* CONF_HW_RXTX_RATE_48 */
3281 9, /* CONF_HW_RXTX_RATE_36 */
3282 8, /* CONF_HW_RXTX_RATE_24 */
3283
3284 /* TI-specific rate */
3285 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3286
3287 7, /* CONF_HW_RXTX_RATE_18 */
3288 6, /* CONF_HW_RXTX_RATE_12 */
3289 3, /* CONF_HW_RXTX_RATE_11 */
3290 5, /* CONF_HW_RXTX_RATE_9 */
3291 4, /* CONF_HW_RXTX_RATE_6 */
3292 2, /* CONF_HW_RXTX_RATE_5_5 */
3293 1, /* CONF_HW_RXTX_RATE_2 */
3294 0 /* CONF_HW_RXTX_RATE_1 */
3295};
3296
Shahar Levie8b03a22010-10-13 16:09:39 +02003297/* 11n STA capabilities */
3298#define HW_RX_HIGHEST_RATE 72
3299
Shahar Levi00d20102010-11-08 11:20:10 +00003300#ifdef CONFIG_WL12XX_HT
3301#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003302 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3303 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003304 .ht_supported = true, \
3305 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3306 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3307 .mcs = { \
3308 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3309 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3310 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3311 }, \
3312}
Shahar Levi18357852010-10-13 16:09:41 +02003313#else
Shahar Levi00d20102010-11-08 11:20:10 +00003314#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003315 .ht_supported = false, \
3316}
3317#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003318
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319/* can't be const, mac80211 writes to this */
3320static struct ieee80211_supported_band wl1271_band_2ghz = {
3321 .channels = wl1271_channels,
3322 .n_channels = ARRAY_SIZE(wl1271_channels),
3323 .bitrates = wl1271_rates,
3324 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003325 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003326};
3327
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003328/* 5 GHz data rates for WL1273 */
3329static struct ieee80211_rate wl1271_rates_5ghz[] = {
3330 { .bitrate = 60,
3331 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3332 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3333 { .bitrate = 90,
3334 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3335 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3336 { .bitrate = 120,
3337 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3338 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3339 { .bitrate = 180,
3340 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3341 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3342 { .bitrate = 240,
3343 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3344 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3345 { .bitrate = 360,
3346 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3347 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3348 { .bitrate = 480,
3349 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3350 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3351 { .bitrate = 540,
3352 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3353 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3354};
3355
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003356/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003357static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003358 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003359 { .hw_value = 8, .center_freq = 5040},
3360 { .hw_value = 9, .center_freq = 5045},
3361 { .hw_value = 11, .center_freq = 5055},
3362 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003363 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003364 { .hw_value = 34, .center_freq = 5170},
3365 { .hw_value = 36, .center_freq = 5180},
3366 { .hw_value = 38, .center_freq = 5190},
3367 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003368 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003369 { .hw_value = 44, .center_freq = 5220},
3370 { .hw_value = 46, .center_freq = 5230},
3371 { .hw_value = 48, .center_freq = 5240},
3372 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003373 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003374 { .hw_value = 60, .center_freq = 5300},
3375 { .hw_value = 64, .center_freq = 5320},
3376 { .hw_value = 100, .center_freq = 5500},
3377 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003378 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003379 { .hw_value = 112, .center_freq = 5560},
3380 { .hw_value = 116, .center_freq = 5580},
3381 { .hw_value = 120, .center_freq = 5600},
3382 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003383 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003384 { .hw_value = 132, .center_freq = 5660},
3385 { .hw_value = 136, .center_freq = 5680},
3386 { .hw_value = 140, .center_freq = 5700},
3387 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003388 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003389 { .hw_value = 157, .center_freq = 5785},
3390 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003391 { .hw_value = 165, .center_freq = 5825},
3392};
3393
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003394/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003395static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003396 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003397 7, /* CONF_HW_RXTX_RATE_MCS7 */
3398 6, /* CONF_HW_RXTX_RATE_MCS6 */
3399 5, /* CONF_HW_RXTX_RATE_MCS5 */
3400 4, /* CONF_HW_RXTX_RATE_MCS4 */
3401 3, /* CONF_HW_RXTX_RATE_MCS3 */
3402 2, /* CONF_HW_RXTX_RATE_MCS2 */
3403 1, /* CONF_HW_RXTX_RATE_MCS1 */
3404 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003405
3406 7, /* CONF_HW_RXTX_RATE_54 */
3407 6, /* CONF_HW_RXTX_RATE_48 */
3408 5, /* CONF_HW_RXTX_RATE_36 */
3409 4, /* CONF_HW_RXTX_RATE_24 */
3410
3411 /* TI-specific rate */
3412 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3413
3414 3, /* CONF_HW_RXTX_RATE_18 */
3415 2, /* CONF_HW_RXTX_RATE_12 */
3416 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3417 1, /* CONF_HW_RXTX_RATE_9 */
3418 0, /* CONF_HW_RXTX_RATE_6 */
3419 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3420 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3421 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3422};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003423
3424static struct ieee80211_supported_band wl1271_band_5ghz = {
3425 .channels = wl1271_channels_5ghz,
3426 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3427 .bitrates = wl1271_rates_5ghz,
3428 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003429 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003430};
3431
Tobias Klausera0ea9492010-05-20 10:38:11 +02003432static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003433 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3434 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3435};
3436
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003437static const struct ieee80211_ops wl1271_ops = {
3438 .start = wl1271_op_start,
3439 .stop = wl1271_op_stop,
3440 .add_interface = wl1271_op_add_interface,
3441 .remove_interface = wl1271_op_remove_interface,
3442 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003443 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003444 .configure_filter = wl1271_op_configure_filter,
3445 .tx = wl1271_op_tx,
3446 .set_key = wl1271_op_set_key,
3447 .hw_scan = wl1271_op_hw_scan,
3448 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003449 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003450 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003451 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003452 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003453 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003454 .sta_add = wl1271_op_sta_add,
3455 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003456 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003457 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003458 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003459};
3460
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003461
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003462u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003463{
3464 u8 idx;
3465
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003466 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003467
3468 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3469 wl1271_error("Illegal RX rate from HW: %d", rate);
3470 return 0;
3471 }
3472
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003473 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003474 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3475 wl1271_error("Unsupported RX rate from HW: %d", rate);
3476 return 0;
3477 }
3478
3479 return idx;
3480}
3481
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003482static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3483 struct device_attribute *attr,
3484 char *buf)
3485{
3486 struct wl1271 *wl = dev_get_drvdata(dev);
3487 ssize_t len;
3488
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003489 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003490
3491 mutex_lock(&wl->mutex);
3492 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3493 wl->sg_enabled);
3494 mutex_unlock(&wl->mutex);
3495
3496 return len;
3497
3498}
3499
3500static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3501 struct device_attribute *attr,
3502 const char *buf, size_t count)
3503{
3504 struct wl1271 *wl = dev_get_drvdata(dev);
3505 unsigned long res;
3506 int ret;
3507
Luciano Coelho6277ed62011-04-01 17:49:54 +03003508 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003509 if (ret < 0) {
3510 wl1271_warning("incorrect value written to bt_coex_mode");
3511 return count;
3512 }
3513
3514 mutex_lock(&wl->mutex);
3515
3516 res = !!res;
3517
3518 if (res == wl->sg_enabled)
3519 goto out;
3520
3521 wl->sg_enabled = res;
3522
3523 if (wl->state == WL1271_STATE_OFF)
3524 goto out;
3525
Ido Yariva6208652011-03-01 15:14:41 +02003526 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003527 if (ret < 0)
3528 goto out;
3529
3530 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3531 wl1271_ps_elp_sleep(wl);
3532
3533 out:
3534 mutex_unlock(&wl->mutex);
3535 return count;
3536}
3537
3538static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3539 wl1271_sysfs_show_bt_coex_state,
3540 wl1271_sysfs_store_bt_coex_state);
3541
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003542static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3543 struct device_attribute *attr,
3544 char *buf)
3545{
3546 struct wl1271 *wl = dev_get_drvdata(dev);
3547 ssize_t len;
3548
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003549 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003550
3551 mutex_lock(&wl->mutex);
3552 if (wl->hw_pg_ver >= 0)
3553 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3554 else
3555 len = snprintf(buf, len, "n/a\n");
3556 mutex_unlock(&wl->mutex);
3557
3558 return len;
3559}
3560
3561static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3562 wl1271_sysfs_show_hw_pg_ver, NULL);
3563
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003564int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003565{
3566 int ret;
3567
3568 if (wl->mac80211_registered)
3569 return 0;
3570
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003571 ret = wl1271_fetch_nvs(wl);
3572 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003573 /* NOTE: The wl->nvs->nvs element must be first, in
3574 * order to simplify the casting, we assume it is at
3575 * the beginning of the wl->nvs structure.
3576 */
3577 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003578
3579 wl->mac_addr[0] = nvs_ptr[11];
3580 wl->mac_addr[1] = nvs_ptr[10];
3581 wl->mac_addr[2] = nvs_ptr[6];
3582 wl->mac_addr[3] = nvs_ptr[5];
3583 wl->mac_addr[4] = nvs_ptr[4];
3584 wl->mac_addr[5] = nvs_ptr[3];
3585 }
3586
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003587 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3588
3589 ret = ieee80211_register_hw(wl->hw);
3590 if (ret < 0) {
3591 wl1271_error("unable to register mac80211 hw: %d", ret);
3592 return ret;
3593 }
3594
3595 wl->mac80211_registered = true;
3596
Eliad Pellerd60080a2010-11-24 12:53:16 +02003597 wl1271_debugfs_init(wl);
3598
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003599 register_netdevice_notifier(&wl1271_dev_notifier);
3600
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003601 wl1271_notice("loaded");
3602
3603 return 0;
3604}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003605EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003606
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003607void wl1271_unregister_hw(struct wl1271 *wl)
3608{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003609 if (wl->state == WL1271_STATE_PLT)
3610 __wl1271_plt_stop(wl);
3611
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003612 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003613 ieee80211_unregister_hw(wl->hw);
3614 wl->mac80211_registered = false;
3615
3616}
3617EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3618
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003619int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003620{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003621 static const u32 cipher_suites[] = {
3622 WLAN_CIPHER_SUITE_WEP40,
3623 WLAN_CIPHER_SUITE_WEP104,
3624 WLAN_CIPHER_SUITE_TKIP,
3625 WLAN_CIPHER_SUITE_CCMP,
3626 WL1271_CIPHER_SUITE_GEM,
3627 };
3628
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003629 /* The tx descriptor buffer and the TKIP space. */
3630 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3631 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003632
3633 /* unit us */
3634 /* FIXME: find a proper value */
3635 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003636 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003637
3638 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003639 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003640 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003641 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003642 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003643 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003644 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003645 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003646 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003647 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003648
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003649 wl->hw->wiphy->cipher_suites = cipher_suites;
3650 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3651
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003652 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003653 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003654 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003655 /*
3656 * Maximum length of elements in scanning probe request templates
3657 * should be the maximum length possible for a template, without
3658 * the IEEE80211 header of the template
3659 */
3660 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3661 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003662
Luciano Coelho4a31c112011-03-21 23:16:14 +02003663 /* make sure all our channels fit in the scanned_ch bitmask */
3664 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3665 ARRAY_SIZE(wl1271_channels_5ghz) >
3666 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003667 /*
3668 * We keep local copies of the band structs because we need to
3669 * modify them on a per-device basis.
3670 */
3671 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3672 sizeof(wl1271_band_2ghz));
3673 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3674 sizeof(wl1271_band_5ghz));
3675
3676 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3677 &wl->bands[IEEE80211_BAND_2GHZ];
3678 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3679 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003680
Kalle Valo12bd8942010-03-18 12:26:33 +02003681 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003682 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003683
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003684 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3685
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003686 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003687
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003688 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3689
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003690 wl->hw->max_rx_aggregation_subframes = 8;
3691
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692 return 0;
3693}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003694EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003695
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003696#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003697
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003698struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003699{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003700 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003701 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003702 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003703 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003704 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705
3706 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3707 if (!hw) {
3708 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003709 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003710 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003711 }
3712
Julia Lawall929ebd32010-05-15 23:16:39 +02003713 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003714 if (!plat_dev) {
3715 wl1271_error("could not allocate platform_device");
3716 ret = -ENOMEM;
3717 goto err_plat_alloc;
3718 }
3719
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003720 wl = hw->priv;
3721 memset(wl, 0, sizeof(*wl));
3722
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003723 INIT_LIST_HEAD(&wl->list);
3724
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003725 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003726 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003727
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003728 for (i = 0; i < NUM_TX_QUEUES; i++)
3729 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003730
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003731 for (i = 0; i < NUM_TX_QUEUES; i++)
3732 for (j = 0; j < AP_MAX_LINKS; j++)
3733 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3734
Ido Yariva6208652011-03-01 15:14:41 +02003735 skb_queue_head_init(&wl->deferred_rx_queue);
3736 skb_queue_head_init(&wl->deferred_tx_queue);
3737
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003738 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003739 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003740 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003741 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3742 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3743 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003744 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003745 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003746 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003747 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003748 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3749 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003750 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003751 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003752 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003753 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003754 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003755 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003756 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003757 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003758 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003759 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003760 wl->bss_type = MAX_BSS_TYPE;
3761 wl->set_bss_type = MAX_BSS_TYPE;
3762 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003763 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003764 wl->ap_ps_map = 0;
3765 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003766 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003767 wl->platform_quirks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003768
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003769 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003770 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003771 wl->tx_frames[i] = NULL;
3772
3773 spin_lock_init(&wl->wl_lock);
3774
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003775 wl->state = WL1271_STATE_OFF;
3776 mutex_init(&wl->mutex);
3777
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003778 /* Apply default driver configuration. */
3779 wl1271_conf_init(wl);
3780
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003781 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3782 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3783 if (!wl->aggr_buf) {
3784 ret = -ENOMEM;
3785 goto err_hw;
3786 }
3787
Ido Yariv990f5de2011-03-31 10:06:59 +02003788 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3789 if (!wl->dummy_packet) {
3790 ret = -ENOMEM;
3791 goto err_aggr;
3792 }
3793
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003794 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003795 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003796 if (ret) {
3797 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003798 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003799 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003800 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003801
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003802 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003803 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003804 if (ret < 0) {
3805 wl1271_error("failed to create sysfs file bt_coex_state");
3806 goto err_platform;
3807 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003808
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003809 /* Create sysfs file to get HW PG version */
3810 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3811 if (ret < 0) {
3812 wl1271_error("failed to create sysfs file hw_pg_ver");
3813 goto err_bt_coex_state;
3814 }
3815
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003816 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003817
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003818err_bt_coex_state:
3819 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3820
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003821err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003822 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003823
Ido Yariv990f5de2011-03-31 10:06:59 +02003824err_dummy_packet:
3825 dev_kfree_skb(wl->dummy_packet);
3826
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003827err_aggr:
3828 free_pages((unsigned long)wl->aggr_buf, order);
3829
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003830err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003831 wl1271_debugfs_exit(wl);
3832 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003833
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003834err_plat_alloc:
3835 ieee80211_free_hw(hw);
3836
3837err_hw_alloc:
3838
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003839 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003840}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003841EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003842
3843int wl1271_free_hw(struct wl1271 *wl)
3844{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003845 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003846 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003847 free_pages((unsigned long)wl->aggr_buf,
3848 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003849 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003850
3851 wl1271_debugfs_exit(wl);
3852
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003853 vfree(wl->fw);
3854 wl->fw = NULL;
3855 kfree(wl->nvs);
3856 wl->nvs = NULL;
3857
3858 kfree(wl->fw_status);
3859 kfree(wl->tx_res_if);
3860
3861 ieee80211_free_hw(wl->hw);
3862
3863 return 0;
3864}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003865EXPORT_SYMBOL_GPL(wl1271_free_hw);
3866
Guy Eilam491bbd62011-01-12 10:33:29 +01003867u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003868EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003869module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003870MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3871
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003872MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003873MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003874MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");