blob: 610be03a198b99d05321502ee66e66963be184e8 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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 Coelho12419cc2010-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
Luciano Coelho33c2c062011-05-10 14:46:02 +0300991 if (wl->sched_scanning) {
992 ieee80211_sched_scan_stopped(wl->hw);
993 wl->sched_scanning = false;
994 }
995
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200996 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300997 __wl1271_op_remove_interface(wl, false);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200998 ieee80211_restart_hw(wl->hw);
999
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001000 /*
1001 * Its safe to enable TX now - the queues are stopped after a request
1002 * to restart the HW.
1003 */
1004 ieee80211_wake_queues(wl->hw);
1005
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001006out:
1007 mutex_unlock(&wl->mutex);
1008}
1009
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010static void wl1271_fw_wakeup(struct wl1271 *wl)
1011{
1012 u32 elp_reg;
1013
1014 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001015 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016}
1017
1018static int wl1271_setup(struct wl1271 *wl)
1019{
1020 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1021 if (!wl->fw_status)
1022 return -ENOMEM;
1023
1024 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1025 if (!wl->tx_res_if) {
1026 kfree(wl->fw_status);
1027 return -ENOMEM;
1028 }
1029
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 return 0;
1031}
1032
1033static int wl1271_chip_wakeup(struct wl1271 *wl)
1034{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001035 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 int ret = 0;
1037
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001038 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001039 ret = wl1271_power_on(wl);
1040 if (ret < 0)
1041 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001042 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001043 wl1271_io_reset(wl);
1044 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045
1046 /* We don't need a real memory partition here, because we only want
1047 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001048 memset(&partition, 0, sizeof(partition));
1049 partition.reg.start = REGISTERS_BASE;
1050 partition.reg.size = REGISTERS_DOWN_SIZE;
1051 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
1053 /* ELP module wake up */
1054 wl1271_fw_wakeup(wl);
1055
1056 /* whal_FwCtrl_BootSm() */
1057
1058 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001059 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001060
1061 /* 1. check if chip id is valid */
1062
1063 switch (wl->chip.id) {
1064 case CHIP_ID_1271_PG10:
1065 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1066 wl->chip.id);
1067
1068 ret = wl1271_setup(wl);
1069 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001070 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001071 break;
1072 case CHIP_ID_1271_PG20:
1073 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1074 wl->chip.id);
1075
Shahar Levi564f5952011-04-04 10:20:39 +03001076 /* end-of-transaction flag should be set in wl127x AP mode */
1077 if (wl->bss_type == BSS_TYPE_AP_BSS)
1078 wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
1079
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001080 ret = wl1271_setup(wl);
1081 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001082 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001084 case CHIP_ID_1283_PG20:
1085 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1086 wl->chip.id);
1087
1088 ret = wl1271_setup(wl);
1089 if (ret < 0)
1090 goto out;
Ido Yariv0da13da2011-03-31 10:06:58 +02001091 if (wl1271_set_block_size(wl))
1092 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001093 break;
1094 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001095 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001096 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001097 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001098 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001099 }
1100
Arik Nemtsov166d5042010-10-16 21:44:57 +02001101 /* Make sure the firmware type matches the BSS type */
1102 if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103 ret = wl1271_fetch_firmware(wl);
1104 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001105 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001106 }
1107
1108 /* No NVS from netlink, try to get it from the filesystem */
1109 if (wl->nvs == NULL) {
1110 ret = wl1271_fetch_nvs(wl);
1111 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001112 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001113 }
1114
1115out:
1116 return ret;
1117}
1118
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001119static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
1120{
1121 unsigned int quirks = 0;
1122 unsigned int *fw_ver = wl->chip.fw_ver;
1123
1124 /* Only for wl127x */
1125 if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
1126 /* Check STA version */
1127 (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
1128 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
1129 /* Check AP version */
1130 ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
1131 (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
1132 quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
1133
1134 return quirks;
1135}
1136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001137int wl1271_plt_start(struct wl1271 *wl)
1138{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001139 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001140 int ret;
1141
1142 mutex_lock(&wl->mutex);
1143
1144 wl1271_notice("power up");
1145
1146 if (wl->state != WL1271_STATE_OFF) {
1147 wl1271_error("cannot go into PLT state because not "
1148 "in off state: %d", wl->state);
1149 ret = -EBUSY;
1150 goto out;
1151 }
1152
Arik Nemtsov166d5042010-10-16 21:44:57 +02001153 wl->bss_type = BSS_TYPE_STA_BSS;
1154
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001155 while (retries) {
1156 retries--;
1157 ret = wl1271_chip_wakeup(wl);
1158 if (ret < 0)
1159 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001160
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001161 ret = wl1271_boot(wl);
1162 if (ret < 0)
1163 goto power_off;
1164
1165 ret = wl1271_plt_init(wl);
1166 if (ret < 0)
1167 goto irq_disable;
1168
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001169 wl->state = WL1271_STATE_PLT;
1170 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001171 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001172
1173 /* Check if any quirks are needed with older fw versions */
1174 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001175 goto out;
1176
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001177irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001178 mutex_unlock(&wl->mutex);
1179 /* Unlocking the mutex in the middle of handling is
1180 inherently unsafe. In this case we deem it safe to do,
1181 because we need to let any possibly pending IRQ out of
1182 the system (and while we are WL1271_STATE_OFF the IRQ
1183 work function will not do anything.) Also, any other
1184 possible concurrent operations will fail due to the
1185 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001186 wl1271_disable_interrupts(wl);
1187 wl1271_flush_deferred_work(wl);
1188 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001189 mutex_lock(&wl->mutex);
1190power_off:
1191 wl1271_power_off(wl);
1192 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001193
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001194 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1195 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001196out:
1197 mutex_unlock(&wl->mutex);
1198
1199 return ret;
1200}
1201
Luciano Coelho4623ec72011-03-21 19:26:41 +02001202static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001203{
1204 int ret = 0;
1205
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001206 wl1271_notice("power down");
1207
1208 if (wl->state != WL1271_STATE_PLT) {
1209 wl1271_error("cannot power down because not in PLT "
1210 "state: %d", wl->state);
1211 ret = -EBUSY;
1212 goto out;
1213 }
1214
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001215 wl1271_power_off(wl);
1216
1217 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001218 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001221 wl1271_disable_interrupts(wl);
1222 wl1271_flush_deferred_work(wl);
1223 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001224 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001225 mutex_lock(&wl->mutex);
1226out:
1227 return ret;
1228}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001229
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001230int wl1271_plt_stop(struct wl1271 *wl)
1231{
1232 int ret;
1233
1234 mutex_lock(&wl->mutex);
1235 ret = __wl1271_plt_stop(wl);
1236 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001237 return ret;
1238}
1239
Johannes Berg7bb45682011-02-24 14:42:06 +01001240static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001241{
1242 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001243 unsigned long flags;
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001244 int q;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001245 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
Ido Yarivb07d4032011-03-01 15:14:43 +02001247 q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
1248
1249 if (wl->bss_type == BSS_TYPE_AP_BSS)
1250 hlid = wl1271_tx_get_hlid(skb);
1251
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001252 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001253
Juuso Oikarinen6742f552010-12-13 09:52:37 +02001254 wl->tx_queue_count++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001255
1256 /*
1257 * The workqueue is slow to process the tx_queue and we need stop
1258 * the queue here, otherwise the queue will get too long.
1259 */
1260 if (wl->tx_queue_count >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1261 wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
1262 ieee80211_stop_queues(wl->hw);
1263 set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
1264 }
1265
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001266 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001267 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001268 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1269 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1270 } else {
1271 skb_queue_tail(&wl->tx_queue[q], skb);
1272 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001273
1274 /*
1275 * The chip specific setup must run before the first TX packet -
1276 * before that, the tx_work will not be initialized!
1277 */
1278
Ido Yarivb07d4032011-03-01 15:14:43 +02001279 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1280 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001281 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001282
1283 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284}
1285
Shahar Leviae47c452011-03-06 16:32:14 +02001286int wl1271_tx_dummy_packet(struct wl1271 *wl)
1287{
Ido Yariv990f5de2011-03-31 10:06:59 +02001288 unsigned long flags;
Shahar Leviae47c452011-03-06 16:32:14 +02001289
Ido Yariv990f5de2011-03-31 10:06:59 +02001290 spin_lock_irqsave(&wl->wl_lock, flags);
1291 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
1292 wl->tx_queue_count++;
1293 spin_unlock_irqrestore(&wl->wl_lock, flags);
1294
1295 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1296 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1297 wl1271_tx_work_locked(wl);
1298
1299 /*
1300 * If the FW TX is busy, TX work will be scheduled by the threaded
1301 * interrupt handler function
1302 */
1303 return 0;
1304}
1305
1306/*
1307 * The size of the dummy packet should be at least 1400 bytes. However, in
1308 * order to minimize the number of bus transactions, aligning it to 512 bytes
1309 * boundaries could be beneficial, performance wise
1310 */
1311#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1312
Luciano Coelhocf27d862011-04-01 21:08:23 +03001313static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001314{
1315 struct sk_buff *skb;
1316 struct ieee80211_hdr_3addr *hdr;
1317 unsigned int dummy_packet_size;
1318
1319 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1320 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1321
1322 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001323 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001324 wl1271_warning("Failed to allocate a dummy packet skb");
1325 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001326 }
1327
1328 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1329
1330 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1331 memset(hdr, 0, sizeof(*hdr));
1332 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001333 IEEE80211_STYPE_NULLFUNC |
1334 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001335
Ido Yariv990f5de2011-03-31 10:06:59 +02001336 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001337
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001338 /* Dummy packets require the TID to be management */
1339 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001340
1341 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001342 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001343 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001344
Ido Yariv990f5de2011-03-31 10:06:59 +02001345 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001346}
1347
Ido Yariv990f5de2011-03-31 10:06:59 +02001348
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001349static struct notifier_block wl1271_dev_notifier = {
1350 .notifier_call = wl1271_dev_notify,
1351};
1352
Eliad Peller94390642011-05-13 11:57:13 +03001353static int wl1271_configure_suspend(struct wl1271 *wl)
1354{
1355 int ret;
1356
1357 if (wl->bss_type != BSS_TYPE_STA_BSS)
1358 return 0;
1359
1360 mutex_lock(&wl->mutex);
1361
1362 ret = wl1271_ps_elp_wakeup(wl);
1363 if (ret < 0)
1364 goto out_unlock;
1365
1366 /* enter psm if needed*/
1367 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1368 DECLARE_COMPLETION_ONSTACK(compl);
1369
1370 wl->ps_compl = &compl;
1371 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1372 wl->basic_rate, true);
1373 if (ret < 0)
1374 goto out_sleep;
1375
1376 /* we must unlock here so we will be able to get events */
1377 wl1271_ps_elp_sleep(wl);
1378 mutex_unlock(&wl->mutex);
1379
1380 ret = wait_for_completion_timeout(
1381 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1382 if (ret <= 0) {
1383 wl1271_warning("couldn't enter ps mode!");
1384 ret = -EBUSY;
1385 goto out;
1386 }
1387
1388 /* take mutex again, and wakeup */
1389 mutex_lock(&wl->mutex);
1390
1391 ret = wl1271_ps_elp_wakeup(wl);
1392 if (ret < 0)
1393 goto out_unlock;
1394 }
1395out_sleep:
1396 wl1271_ps_elp_sleep(wl);
1397out_unlock:
1398 mutex_unlock(&wl->mutex);
1399out:
1400 return ret;
1401
1402}
1403
1404static void wl1271_configure_resume(struct wl1271 *wl)
1405{
1406 int ret;
1407
1408 if (wl->bss_type != BSS_TYPE_STA_BSS)
1409 return;
1410
1411 mutex_lock(&wl->mutex);
1412 ret = wl1271_ps_elp_wakeup(wl);
1413 if (ret < 0)
1414 goto out;
1415
1416 /* exit psm if it wasn't configured */
1417 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1418 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1419 wl->basic_rate, true);
1420
1421 wl1271_ps_elp_sleep(wl);
1422out:
1423 mutex_unlock(&wl->mutex);
1424}
1425
Eliad Peller402e48612011-05-13 11:57:09 +03001426static int wl1271_op_suspend(struct ieee80211_hw *hw,
1427 struct cfg80211_wowlan *wow)
1428{
1429 struct wl1271 *wl = hw->priv;
1430 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1431 wl->wow_enabled = !!wow;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001432 if (wl->wow_enabled) {
Eliad Peller94390642011-05-13 11:57:13 +03001433 int ret;
1434 ret = wl1271_configure_suspend(wl);
1435 if (ret < 0) {
1436 wl1271_warning("couldn't prepare device to suspend");
1437 return ret;
1438 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001439 /* flush any remaining work */
1440 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
1441 flush_delayed_work(&wl->scan_complete_work);
1442
1443 /*
1444 * disable and re-enable interrupts in order to flush
1445 * the threaded_irq
1446 */
1447 wl1271_disable_interrupts(wl);
1448
1449 /*
1450 * set suspended flag to avoid triggering a new threaded_irq
1451 * work. no need for spinlock as interrupts are disabled.
1452 */
1453 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1454
1455 wl1271_enable_interrupts(wl);
1456 flush_work(&wl->tx_work);
1457 flush_delayed_work(&wl->pspoll_work);
1458 flush_delayed_work(&wl->elp_work);
1459 }
Eliad Peller402e48612011-05-13 11:57:09 +03001460 return 0;
1461}
1462
1463static int wl1271_op_resume(struct ieee80211_hw *hw)
1464{
1465 struct wl1271 *wl = hw->priv;
1466 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1467 wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001468
1469 /*
1470 * re-enable irq_work enqueuing, and call irq_work directly if
1471 * there is a pending work.
1472 */
1473 if (wl->wow_enabled) {
1474 struct wl1271 *wl = hw->priv;
1475 unsigned long flags;
1476 bool run_irq_work = false;
1477
1478 spin_lock_irqsave(&wl->wl_lock, flags);
1479 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1480 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1481 run_irq_work = true;
1482 spin_unlock_irqrestore(&wl->wl_lock, flags);
1483
1484 if (run_irq_work) {
1485 wl1271_debug(DEBUG_MAC80211,
1486 "run postponed irq_work directly");
1487 wl1271_irq(0, wl);
1488 wl1271_enable_interrupts(wl);
1489 }
Eliad Peller94390642011-05-13 11:57:13 +03001490
1491 wl1271_configure_resume(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001492 }
1493
Eliad Peller402e48612011-05-13 11:57:09 +03001494 return 0;
1495}
1496
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001497static int wl1271_op_start(struct ieee80211_hw *hw)
1498{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001499 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1500
1501 /*
1502 * We have to delay the booting of the hardware because
1503 * we need to know the local MAC address before downloading and
1504 * initializing the firmware. The MAC address cannot be changed
1505 * after boot, and without the proper MAC address, the firmware
1506 * will not function properly.
1507 *
1508 * The MAC address is first known when the corresponding interface
1509 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001510 *
1511 * In addition, we currently have different firmwares for AP and managed
1512 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001513 */
1514
1515 return 0;
1516}
1517
1518static void wl1271_op_stop(struct ieee80211_hw *hw)
1519{
1520 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1521}
1522
1523static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1524 struct ieee80211_vif *vif)
1525{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001526 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001527 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001528 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001530 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001531
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001532 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1533 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001534
1535 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001536 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001537 wl1271_debug(DEBUG_MAC80211,
1538 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001539 ret = -EBUSY;
1540 goto out;
1541 }
1542
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001543 /*
1544 * in some very corner case HW recovery scenarios its possible to
1545 * get here before __wl1271_op_remove_interface is complete, so
1546 * opt out if that is the case.
1547 */
1548 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1549 ret = -EBUSY;
1550 goto out;
1551 }
1552
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001553 switch (vif->type) {
1554 case NL80211_IFTYPE_STATION:
1555 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001556 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001557 break;
1558 case NL80211_IFTYPE_ADHOC:
1559 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001560 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001561 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001562 case NL80211_IFTYPE_AP:
1563 wl->bss_type = BSS_TYPE_AP_BSS;
1564 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001565 default:
1566 ret = -EOPNOTSUPP;
1567 goto out;
1568 }
1569
1570 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001571
1572 if (wl->state != WL1271_STATE_OFF) {
1573 wl1271_error("cannot start because not in off state: %d",
1574 wl->state);
1575 ret = -EBUSY;
1576 goto out;
1577 }
1578
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001579 while (retries) {
1580 retries--;
1581 ret = wl1271_chip_wakeup(wl);
1582 if (ret < 0)
1583 goto power_off;
1584
1585 ret = wl1271_boot(wl);
1586 if (ret < 0)
1587 goto power_off;
1588
1589 ret = wl1271_hw_init(wl);
1590 if (ret < 0)
1591 goto irq_disable;
1592
Eliad Peller71125ab2010-10-28 21:46:43 +02001593 booted = true;
1594 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001595
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001596irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001597 mutex_unlock(&wl->mutex);
1598 /* Unlocking the mutex in the middle of handling is
1599 inherently unsafe. In this case we deem it safe to do,
1600 because we need to let any possibly pending IRQ out of
1601 the system (and while we are WL1271_STATE_OFF the IRQ
1602 work function will not do anything.) Also, any other
1603 possible concurrent operations will fail due to the
1604 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001605 wl1271_disable_interrupts(wl);
1606 wl1271_flush_deferred_work(wl);
1607 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001608 mutex_lock(&wl->mutex);
1609power_off:
1610 wl1271_power_off(wl);
1611 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001612
Eliad Peller71125ab2010-10-28 21:46:43 +02001613 if (!booted) {
1614 wl1271_error("firmware boot failed despite %d retries",
1615 WL1271_BOOT_RETRIES);
1616 goto out;
1617 }
1618
1619 wl->vif = vif;
1620 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001621 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001622 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001623
1624 /* update hw/fw version info in wiphy struct */
1625 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001626 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001627 sizeof(wiphy->fw_version));
1628
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001629 /* Check if any quirks are needed with older fw versions */
1630 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1631
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001632 /*
1633 * Now we know if 11a is supported (info from the NVS), so disable
1634 * 11a channels if not supported
1635 */
1636 if (!wl->enable_11a)
1637 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1638
1639 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1640 wl->enable_11a ? "" : "not ");
1641
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001642out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001643 mutex_unlock(&wl->mutex);
1644
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001645 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001646 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001647 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001648 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001650 return ret;
1651}
1652
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001653static void __wl1271_op_remove_interface(struct wl1271 *wl,
1654 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001655{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001656 int i;
1657
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001658 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001659
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001660 /* because of hardware recovery, we may get here twice */
1661 if (wl->state != WL1271_STATE_ON)
1662 return;
1663
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001664 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001665
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001666 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001667 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001668 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001669
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001670 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001671 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001672 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001673
Luciano Coelho08688d62010-07-08 17:50:07 +03001674 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001675 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001676 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001677 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001678 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001679 }
1680
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001681 /*
1682 * this must be before the cancel_work calls below, so that the work
1683 * functions don't perform further work.
1684 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001685 wl->state = WL1271_STATE_OFF;
1686
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001687 mutex_unlock(&wl->mutex);
1688
Ido Yariva6208652011-03-01 15:14:41 +02001689 wl1271_disable_interrupts(wl);
1690 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001691 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001692 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001693 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001694 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001695 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001696
1697 mutex_lock(&wl->mutex);
1698
1699 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001700 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001701 wl1271_power_off(wl);
1702
1703 memset(wl->bssid, 0, ETH_ALEN);
1704 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1705 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001706 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001707 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001708 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001709
1710 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001711 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001712 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1713 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001714 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001715 wl->tx_results_count = 0;
1716 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001717 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001718 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001719 wl->time_offset = 0;
1720 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001721 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001722 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001723 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001724 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001725 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001726 wl->ap_fw_ps_map = 0;
1727 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001728 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001729
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001730 /*
1731 * this is performed after the cancel_work calls and the associated
1732 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1733 * get executed before all these vars have been reset.
1734 */
1735 wl->flags = 0;
1736
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001737 for (i = 0; i < NUM_TX_QUEUES; i++)
1738 wl->tx_blocks_freed[i] = 0;
1739
1740 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001741
1742 kfree(wl->fw_status);
1743 wl->fw_status = NULL;
1744 kfree(wl->tx_res_if);
1745 wl->tx_res_if = NULL;
1746 kfree(wl->target_mem_map);
1747 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001748}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001749
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001750static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1751 struct ieee80211_vif *vif)
1752{
1753 struct wl1271 *wl = hw->priv;
1754
1755 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001756 /*
1757 * wl->vif can be null here if someone shuts down the interface
1758 * just when hardware recovery has been started.
1759 */
1760 if (wl->vif) {
1761 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001762 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001763 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001764
Juuso Oikarinen67353292010-11-18 15:19:02 +02001765 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001766 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001767}
1768
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001769void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001770{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001771 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001772
1773 /* combine requested filters with current filter config */
1774 filters = wl->filters | filters;
1775
1776 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1777
1778 if (filters & FIF_PROMISC_IN_BSS) {
1779 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1780 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1781 wl->rx_config |= CFG_BSSID_FILTER_EN;
1782 }
1783 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1784 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1785 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1786 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1787 }
1788 if (filters & FIF_OTHER_BSS) {
1789 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1790 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1791 }
1792 if (filters & FIF_CONTROL) {
1793 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1794 wl->rx_filter |= CFG_RX_CTL_EN;
1795 }
1796 if (filters & FIF_FCSFAIL) {
1797 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1798 wl->rx_filter |= CFG_RX_FCS_ERROR;
1799 }
1800}
1801
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001802static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001803{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001804 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001805 /* we need to use a dummy BSSID for now */
1806 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1807 0xad, 0xbe, 0xef };
1808
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001809 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1810
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001811 /* pass through frames from all BSS */
1812 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1813
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001814 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001815 if (ret < 0)
1816 goto out;
1817
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001818 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001819
1820out:
1821 return ret;
1822}
1823
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001824static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001825{
1826 int ret;
1827
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001828 /*
1829 * One of the side effects of the JOIN command is that is clears
1830 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1831 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001832 * Currently the only valid scenario for JOIN during association
1833 * is on roaming, in which case we will also be given new keys.
1834 * Keep the below message for now, unless it starts bothering
1835 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001836 */
1837 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1838 wl1271_info("JOIN while associated.");
1839
1840 if (set_assoc)
1841 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1842
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001843 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1844 if (ret < 0)
1845 goto out;
1846
1847 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1848
1849 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1850 goto out;
1851
1852 /*
1853 * The join command disable the keep-alive mode, shut down its process,
1854 * and also clear the template config, so we need to reset it all after
1855 * the join. The acx_aid starts the keep-alive process, and the order
1856 * of the commands below is relevant.
1857 */
1858 ret = wl1271_acx_keep_alive_mode(wl, true);
1859 if (ret < 0)
1860 goto out;
1861
1862 ret = wl1271_acx_aid(wl, wl->aid);
1863 if (ret < 0)
1864 goto out;
1865
1866 ret = wl1271_cmd_build_klv_null_data(wl);
1867 if (ret < 0)
1868 goto out;
1869
1870 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1871 ACX_KEEP_ALIVE_TPL_VALID);
1872 if (ret < 0)
1873 goto out;
1874
1875out:
1876 return ret;
1877}
1878
1879static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001880{
1881 int ret;
1882
1883 /* to stop listening to a channel, we disconnect */
1884 ret = wl1271_cmd_disconnect(wl);
1885 if (ret < 0)
1886 goto out;
1887
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001888 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001889 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001890
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001891 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001892 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001893
1894out:
1895 return ret;
1896}
1897
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001898static void wl1271_set_band_rate(struct wl1271 *wl)
1899{
1900 if (wl->band == IEEE80211_BAND_2GHZ)
1901 wl->basic_rate_set = wl->conf.tx.basic_rate;
1902 else
1903 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1904}
1905
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001906static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001907{
1908 int ret;
1909
1910 if (idle) {
1911 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1912 ret = wl1271_unjoin(wl);
1913 if (ret < 0)
1914 goto out;
1915 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001916 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001917 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001918 if (ret < 0)
1919 goto out;
1920 ret = wl1271_acx_keep_alive_config(
1921 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1922 ACX_KEEP_ALIVE_TPL_INVALID);
1923 if (ret < 0)
1924 goto out;
1925 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1926 } else {
1927 /* increment the session counter */
1928 wl->session_counter++;
1929 if (wl->session_counter >= SESSION_COUNTER_MAX)
1930 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001931
1932 /* The current firmware only supports sched_scan in idle */
1933 if (wl->sched_scanning) {
1934 wl1271_scan_sched_scan_stop(wl);
1935 ieee80211_sched_scan_stopped(wl->hw);
1936 }
1937
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001938 ret = wl1271_dummy_join(wl);
1939 if (ret < 0)
1940 goto out;
1941 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1942 }
1943
1944out:
1945 return ret;
1946}
1947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001948static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1949{
1950 struct wl1271 *wl = hw->priv;
1951 struct ieee80211_conf *conf = &hw->conf;
1952 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001953 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001954
1955 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1956
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001957 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1958 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 channel,
1960 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001961 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001962 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1963 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001964
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001965 /*
1966 * mac80211 will go to idle nearly immediately after transmitting some
1967 * frames, such as the deauth. To make sure those frames reach the air,
1968 * wait here until the TX queue is fully flushed.
1969 */
1970 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1971 (conf->flags & IEEE80211_CONF_IDLE))
1972 wl1271_tx_flush(wl);
1973
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974 mutex_lock(&wl->mutex);
1975
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001976 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001977 /* we support configuring the channel and band while off */
1978 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1979 wl->band = conf->channel->band;
1980 wl->channel = channel;
1981 }
1982
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001983 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001984 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001985
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001986 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1987
Ido Yariva6208652011-03-01 15:14:41 +02001988 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001989 if (ret < 0)
1990 goto out;
1991
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001992 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001993 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1994 ((wl->band != conf->channel->band) ||
1995 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001996 wl->band = conf->channel->band;
1997 wl->channel = channel;
1998
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001999 if (!is_ap) {
2000 /*
2001 * FIXME: the mac80211 should really provide a fixed
2002 * rate to use here. for now, just use the smallest
2003 * possible rate for the band as a fixed rate for
2004 * association frames and other control messages.
2005 */
2006 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2007 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002008
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002009 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2010 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002011 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002012 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002013 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002014
2015 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2016 ret = wl1271_join(wl, false);
2017 if (ret < 0)
2018 wl1271_warning("cmd join on channel "
2019 "failed %d", ret);
2020 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002021 }
2022 }
2023
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002024 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2025 ret = wl1271_sta_handle_idle(wl,
2026 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002027 if (ret < 0)
2028 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002029 }
2030
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002031 /*
2032 * if mac80211 changes the PSM mode, make sure the mode is not
2033 * incorrectly changed after the pspoll failure active window.
2034 */
2035 if (changed & IEEE80211_CONF_CHANGE_PS)
2036 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2037
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002038 if (conf->flags & IEEE80211_CONF_PS &&
2039 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2040 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002041
2042 /*
2043 * We enter PSM only if we're already associated.
2044 * If we're not, we'll enter it when joining an SSID,
2045 * through the bss_info_changed() hook.
2046 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002047 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002048 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002049 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002050 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002051 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002053 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002054 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002056 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002057
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002058 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002059 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002060 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002061 }
2062
2063 if (conf->power_level != wl->power_level) {
2064 ret = wl1271_acx_tx_power(wl, conf->power_level);
2065 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002066 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067
2068 wl->power_level = conf->power_level;
2069 }
2070
2071out_sleep:
2072 wl1271_ps_elp_sleep(wl);
2073
2074out:
2075 mutex_unlock(&wl->mutex);
2076
2077 return ret;
2078}
2079
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002080struct wl1271_filter_params {
2081 bool enabled;
2082 int mc_list_length;
2083 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2084};
2085
Jiri Pirko22bedad2010-04-01 21:22:57 +00002086static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2087 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002088{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002089 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002090 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002091 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002092
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002093 if (unlikely(wl->state == WL1271_STATE_OFF))
2094 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002095
Juuso Oikarinen74441132009-10-13 12:47:53 +03002096 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002097 if (!fp) {
2098 wl1271_error("Out of memory setting filters.");
2099 return 0;
2100 }
2101
2102 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002103 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002104 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2105 fp->enabled = false;
2106 } else {
2107 fp->enabled = true;
2108 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002109 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002110 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002111 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002112 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002113 }
2114
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002115 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002116}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002117
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002118#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2119 FIF_ALLMULTI | \
2120 FIF_FCSFAIL | \
2121 FIF_BCN_PRBRESP_PROMISC | \
2122 FIF_CONTROL | \
2123 FIF_OTHER_BSS)
2124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002125static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2126 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002127 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002128{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002129 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002130 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002131 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002132
Arik Nemtsov7d057862010-10-16 19:25:35 +02002133 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2134 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002135
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002136 mutex_lock(&wl->mutex);
2137
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002138 *total &= WL1271_SUPPORTED_FILTERS;
2139 changed &= WL1271_SUPPORTED_FILTERS;
2140
2141 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002142 goto out;
2143
Ido Yariva6208652011-03-01 15:14:41 +02002144 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002145 if (ret < 0)
2146 goto out;
2147
Arik Nemtsov7d057862010-10-16 19:25:35 +02002148 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2149 if (*total & FIF_ALLMULTI)
2150 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2151 else if (fp)
2152 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2153 fp->mc_list,
2154 fp->mc_list_length);
2155 if (ret < 0)
2156 goto out_sleep;
2157 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002158
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002159 /* determine, whether supported filter values have changed */
2160 if (changed == 0)
2161 goto out_sleep;
2162
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002163 /* configure filters */
2164 wl->filters = *total;
2165 wl1271_configure_filters(wl, 0);
2166
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002167 /* apply configured filters */
2168 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2169 if (ret < 0)
2170 goto out_sleep;
2171
2172out_sleep:
2173 wl1271_ps_elp_sleep(wl);
2174
2175out:
2176 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002177 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178}
2179
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002180static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2181 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2182 u16 tx_seq_16)
2183{
2184 struct wl1271_ap_key *ap_key;
2185 int i;
2186
2187 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2188
2189 if (key_size > MAX_KEY_SIZE)
2190 return -EINVAL;
2191
2192 /*
2193 * Find next free entry in ap_keys. Also check we are not replacing
2194 * an existing key.
2195 */
2196 for (i = 0; i < MAX_NUM_KEYS; i++) {
2197 if (wl->recorded_ap_keys[i] == NULL)
2198 break;
2199
2200 if (wl->recorded_ap_keys[i]->id == id) {
2201 wl1271_warning("trying to record key replacement");
2202 return -EINVAL;
2203 }
2204 }
2205
2206 if (i == MAX_NUM_KEYS)
2207 return -EBUSY;
2208
2209 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2210 if (!ap_key)
2211 return -ENOMEM;
2212
2213 ap_key->id = id;
2214 ap_key->key_type = key_type;
2215 ap_key->key_size = key_size;
2216 memcpy(ap_key->key, key, key_size);
2217 ap_key->hlid = hlid;
2218 ap_key->tx_seq_32 = tx_seq_32;
2219 ap_key->tx_seq_16 = tx_seq_16;
2220
2221 wl->recorded_ap_keys[i] = ap_key;
2222 return 0;
2223}
2224
2225static void wl1271_free_ap_keys(struct wl1271 *wl)
2226{
2227 int i;
2228
2229 for (i = 0; i < MAX_NUM_KEYS; i++) {
2230 kfree(wl->recorded_ap_keys[i]);
2231 wl->recorded_ap_keys[i] = NULL;
2232 }
2233}
2234
2235static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2236{
2237 int i, ret = 0;
2238 struct wl1271_ap_key *key;
2239 bool wep_key_added = false;
2240
2241 for (i = 0; i < MAX_NUM_KEYS; i++) {
2242 if (wl->recorded_ap_keys[i] == NULL)
2243 break;
2244
2245 key = wl->recorded_ap_keys[i];
2246 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2247 key->id, key->key_type,
2248 key->key_size, key->key,
2249 key->hlid, key->tx_seq_32,
2250 key->tx_seq_16);
2251 if (ret < 0)
2252 goto out;
2253
2254 if (key->key_type == KEY_WEP)
2255 wep_key_added = true;
2256 }
2257
2258 if (wep_key_added) {
2259 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2260 if (ret < 0)
2261 goto out;
2262 }
2263
2264out:
2265 wl1271_free_ap_keys(wl);
2266 return ret;
2267}
2268
2269static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2270 u8 key_size, const u8 *key, u32 tx_seq_32,
2271 u16 tx_seq_16, struct ieee80211_sta *sta)
2272{
2273 int ret;
2274 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2275
2276 if (is_ap) {
2277 struct wl1271_station *wl_sta;
2278 u8 hlid;
2279
2280 if (sta) {
2281 wl_sta = (struct wl1271_station *)sta->drv_priv;
2282 hlid = wl_sta->hlid;
2283 } else {
2284 hlid = WL1271_AP_BROADCAST_HLID;
2285 }
2286
2287 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2288 /*
2289 * We do not support removing keys after AP shutdown.
2290 * Pretend we do to make mac80211 happy.
2291 */
2292 if (action != KEY_ADD_OR_REPLACE)
2293 return 0;
2294
2295 ret = wl1271_record_ap_key(wl, id,
2296 key_type, key_size,
2297 key, hlid, tx_seq_32,
2298 tx_seq_16);
2299 } else {
2300 ret = wl1271_cmd_set_ap_key(wl, action,
2301 id, key_type, key_size,
2302 key, hlid, tx_seq_32,
2303 tx_seq_16);
2304 }
2305
2306 if (ret < 0)
2307 return ret;
2308 } else {
2309 const u8 *addr;
2310 static const u8 bcast_addr[ETH_ALEN] = {
2311 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2312 };
2313
2314 addr = sta ? sta->addr : bcast_addr;
2315
2316 if (is_zero_ether_addr(addr)) {
2317 /* We dont support TX only encryption */
2318 return -EOPNOTSUPP;
2319 }
2320
2321 /* The wl1271 does not allow to remove unicast keys - they
2322 will be cleared automatically on next CMD_JOIN. Ignore the
2323 request silently, as we dont want the mac80211 to emit
2324 an error message. */
2325 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2326 return 0;
2327
2328 ret = wl1271_cmd_set_sta_key(wl, action,
2329 id, key_type, key_size,
2330 key, addr, tx_seq_32,
2331 tx_seq_16);
2332 if (ret < 0)
2333 return ret;
2334
2335 /* the default WEP key needs to be configured at least once */
2336 if (key_type == KEY_WEP) {
2337 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2338 wl->default_key);
2339 if (ret < 0)
2340 return ret;
2341 }
2342 }
2343
2344 return 0;
2345}
2346
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002347static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2348 struct ieee80211_vif *vif,
2349 struct ieee80211_sta *sta,
2350 struct ieee80211_key_conf *key_conf)
2351{
2352 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002353 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002354 u32 tx_seq_32 = 0;
2355 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002356 u8 key_type;
2357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002358 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2359
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002360 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002362 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363 key_conf->keylen, key_conf->flags);
2364 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2365
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366 mutex_lock(&wl->mutex);
2367
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002368 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2369 ret = -EAGAIN;
2370 goto out_unlock;
2371 }
2372
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_unlock;
2376
Johannes Berg97359d12010-08-10 09:46:38 +02002377 switch (key_conf->cipher) {
2378 case WLAN_CIPHER_SUITE_WEP40:
2379 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002380 key_type = KEY_WEP;
2381
2382 key_conf->hw_key_idx = key_conf->keyidx;
2383 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002384 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002385 key_type = KEY_TKIP;
2386
2387 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002388 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2389 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002390 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002391 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002392 key_type = KEY_AES;
2393
2394 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002395 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2396 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002397 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002398 case WL1271_CIPHER_SUITE_GEM:
2399 key_type = KEY_GEM;
2400 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2401 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2402 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002404 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002405
2406 ret = -EOPNOTSUPP;
2407 goto out_sleep;
2408 }
2409
2410 switch (cmd) {
2411 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002412 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2413 key_conf->keyidx, key_type,
2414 key_conf->keylen, key_conf->key,
2415 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002416 if (ret < 0) {
2417 wl1271_error("Could not add or replace key");
2418 goto out_sleep;
2419 }
2420 break;
2421
2422 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002423 ret = wl1271_set_key(wl, KEY_REMOVE,
2424 key_conf->keyidx, key_type,
2425 key_conf->keylen, key_conf->key,
2426 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002427 if (ret < 0) {
2428 wl1271_error("Could not remove key");
2429 goto out_sleep;
2430 }
2431 break;
2432
2433 default:
2434 wl1271_error("Unsupported key cmd 0x%x", cmd);
2435 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002436 break;
2437 }
2438
2439out_sleep:
2440 wl1271_ps_elp_sleep(wl);
2441
2442out_unlock:
2443 mutex_unlock(&wl->mutex);
2444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445 return ret;
2446}
2447
2448static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002449 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450 struct cfg80211_scan_request *req)
2451{
2452 struct wl1271 *wl = hw->priv;
2453 int ret;
2454 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002455 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002456
2457 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2458
2459 if (req->n_ssids) {
2460 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002461 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002462 }
2463
2464 mutex_lock(&wl->mutex);
2465
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002466 if (wl->state == WL1271_STATE_OFF) {
2467 /*
2468 * We cannot return -EBUSY here because cfg80211 will expect
2469 * a call to ieee80211_scan_completed if we do - in this case
2470 * there won't be any call.
2471 */
2472 ret = -EAGAIN;
2473 goto out;
2474 }
2475
Ido Yariva6208652011-03-01 15:14:41 +02002476 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002477 if (ret < 0)
2478 goto out;
2479
Luciano Coelho5924f892010-08-04 03:46:22 +03002480 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002481
2482 wl1271_ps_elp_sleep(wl);
2483
2484out:
2485 mutex_unlock(&wl->mutex);
2486
2487 return ret;
2488}
2489
Luciano Coelho33c2c062011-05-10 14:46:02 +03002490static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2491 struct ieee80211_vif *vif,
2492 struct cfg80211_sched_scan_request *req,
2493 struct ieee80211_sched_scan_ies *ies)
2494{
2495 struct wl1271 *wl = hw->priv;
2496 int ret;
2497
2498 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2499
2500 mutex_lock(&wl->mutex);
2501
2502 ret = wl1271_ps_elp_wakeup(wl);
2503 if (ret < 0)
2504 goto out;
2505
2506 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2507 if (ret < 0)
2508 goto out_sleep;
2509
2510 ret = wl1271_scan_sched_scan_start(wl);
2511 if (ret < 0)
2512 goto out_sleep;
2513
2514 wl->sched_scanning = true;
2515
2516out_sleep:
2517 wl1271_ps_elp_sleep(wl);
2518out:
2519 mutex_unlock(&wl->mutex);
2520 return ret;
2521}
2522
2523static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2524 struct ieee80211_vif *vif)
2525{
2526 struct wl1271 *wl = hw->priv;
2527 int ret;
2528
2529 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2530
2531 mutex_lock(&wl->mutex);
2532
2533 ret = wl1271_ps_elp_wakeup(wl);
2534 if (ret < 0)
2535 goto out;
2536
2537 wl1271_scan_sched_scan_stop(wl);
2538
2539 wl1271_ps_elp_sleep(wl);
2540out:
2541 mutex_unlock(&wl->mutex);
2542}
2543
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002544static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2545{
2546 struct wl1271 *wl = hw->priv;
2547 int ret = 0;
2548
2549 mutex_lock(&wl->mutex);
2550
2551 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2552 ret = -EAGAIN;
2553 goto out;
2554 }
2555
Ido Yariva6208652011-03-01 15:14:41 +02002556 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002557 if (ret < 0)
2558 goto out;
2559
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002560 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002561 if (ret < 0)
2562 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2563
2564 wl1271_ps_elp_sleep(wl);
2565
2566out:
2567 mutex_unlock(&wl->mutex);
2568
2569 return ret;
2570}
2571
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002572static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2573{
2574 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002575 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002576
2577 mutex_lock(&wl->mutex);
2578
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002579 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2580 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002581 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002582 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002583
Ido Yariva6208652011-03-01 15:14:41 +02002584 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002585 if (ret < 0)
2586 goto out;
2587
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002588 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589 if (ret < 0)
2590 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2591
2592 wl1271_ps_elp_sleep(wl);
2593
2594out:
2595 mutex_unlock(&wl->mutex);
2596
2597 return ret;
2598}
2599
Arik Nemtsove78a2872010-10-16 19:07:21 +02002600static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002601 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002602{
Eliad Peller889cb362011-05-01 09:56:45 +03002603 u8 ssid_len;
2604 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2605 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002606
Eliad Peller889cb362011-05-01 09:56:45 +03002607 if (!ptr) {
2608 wl1271_error("No SSID in IEs!");
2609 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002610 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002611
Eliad Peller889cb362011-05-01 09:56:45 +03002612 ssid_len = ptr[1];
2613 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2614 wl1271_error("SSID is too long!");
2615 return -EINVAL;
2616 }
2617
2618 wl->ssid_len = ssid_len;
2619 memcpy(wl->ssid, ptr+2, ssid_len);
2620 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002621}
2622
Arik Nemtsove78a2872010-10-16 19:07:21 +02002623static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2624 struct ieee80211_bss_conf *bss_conf,
2625 u32 changed)
2626{
2627 int ret = 0;
2628
2629 if (changed & BSS_CHANGED_ERP_SLOT) {
2630 if (bss_conf->use_short_slot)
2631 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2632 else
2633 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2634 if (ret < 0) {
2635 wl1271_warning("Set slot time failed %d", ret);
2636 goto out;
2637 }
2638 }
2639
2640 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2641 if (bss_conf->use_short_preamble)
2642 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2643 else
2644 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2645 }
2646
2647 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2648 if (bss_conf->use_cts_prot)
2649 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2650 else
2651 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2652 if (ret < 0) {
2653 wl1271_warning("Set ctsprotect failed %d", ret);
2654 goto out;
2655 }
2656 }
2657
2658out:
2659 return ret;
2660}
2661
2662static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2663 struct ieee80211_vif *vif,
2664 struct ieee80211_bss_conf *bss_conf,
2665 u32 changed)
2666{
2667 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2668 int ret = 0;
2669
2670 if ((changed & BSS_CHANGED_BEACON_INT)) {
2671 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2672 bss_conf->beacon_int);
2673
2674 wl->beacon_int = bss_conf->beacon_int;
2675 }
2676
2677 if ((changed & BSS_CHANGED_BEACON)) {
2678 struct ieee80211_hdr *hdr;
2679 int ieoffset = offsetof(struct ieee80211_mgmt,
2680 u.beacon.variable);
2681 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2682 u16 tmpl_id;
2683
2684 if (!beacon)
2685 goto out;
2686
2687 wl1271_debug(DEBUG_MASTER, "beacon updated");
2688
2689 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2690 if (ret < 0) {
2691 dev_kfree_skb(beacon);
2692 goto out;
2693 }
2694 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2695 CMD_TEMPL_BEACON;
2696 ret = wl1271_cmd_template_set(wl, tmpl_id,
2697 beacon->data,
2698 beacon->len, 0,
2699 wl1271_tx_min_rate_get(wl));
2700 if (ret < 0) {
2701 dev_kfree_skb(beacon);
2702 goto out;
2703 }
2704
2705 hdr = (struct ieee80211_hdr *) beacon->data;
2706 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2707 IEEE80211_STYPE_PROBE_RESP);
2708
2709 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2710 CMD_TEMPL_PROBE_RESPONSE;
2711 ret = wl1271_cmd_template_set(wl,
2712 tmpl_id,
2713 beacon->data,
2714 beacon->len, 0,
2715 wl1271_tx_min_rate_get(wl));
2716 dev_kfree_skb(beacon);
2717 if (ret < 0)
2718 goto out;
2719 }
2720
2721out:
2722 return ret;
2723}
2724
2725/* AP mode changes */
2726static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002727 struct ieee80211_vif *vif,
2728 struct ieee80211_bss_conf *bss_conf,
2729 u32 changed)
2730{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002731 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002732
Arik Nemtsove78a2872010-10-16 19:07:21 +02002733 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2734 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002735
Arik Nemtsove78a2872010-10-16 19:07:21 +02002736 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2737 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002738
Arik Nemtsov70f47422011-04-18 14:15:25 +03002739 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002740 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002741 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002742 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002743 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002744
2745 ret = wl1271_ap_init_templates(wl);
2746 if (ret < 0)
2747 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002748 }
2749
Arik Nemtsove78a2872010-10-16 19:07:21 +02002750 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2751 if (ret < 0)
2752 goto out;
2753
2754 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2755 if (bss_conf->enable_beacon) {
2756 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2757 ret = wl1271_cmd_start_bss(wl);
2758 if (ret < 0)
2759 goto out;
2760
2761 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2762 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002763
2764 ret = wl1271_ap_init_hwenc(wl);
2765 if (ret < 0)
2766 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002767 }
2768 } else {
2769 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2770 ret = wl1271_cmd_stop_bss(wl);
2771 if (ret < 0)
2772 goto out;
2773
2774 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2775 wl1271_debug(DEBUG_AP, "stopped AP");
2776 }
2777 }
2778 }
2779
Eliad Pellercb5ae052011-04-07 15:52:05 +03002780 if (changed & BSS_CHANGED_IBSS) {
2781 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2782 bss_conf->ibss_joined);
2783
2784 if (bss_conf->ibss_joined) {
2785 u32 rates = bss_conf->basic_rates;
2786 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2787 rates);
2788 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2789
2790 /* by default, use 11b rates */
2791 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2792 ret = wl1271_acx_sta_rate_policies(wl);
2793 if (ret < 0)
2794 goto out;
2795 }
2796 }
2797
Arik Nemtsove78a2872010-10-16 19:07:21 +02002798 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2799 if (ret < 0)
2800 goto out;
2801out:
2802 return;
2803}
2804
2805/* STA/IBSS mode changes */
2806static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2807 struct ieee80211_vif *vif,
2808 struct ieee80211_bss_conf *bss_conf,
2809 u32 changed)
2810{
2811 bool do_join = false, set_assoc = false;
2812 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002813 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002814 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002815 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002816 bool sta_exists = false;
2817 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002818
2819 if (is_ibss) {
2820 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2821 changed);
2822 if (ret < 0)
2823 goto out;
2824 }
2825
2826 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2827 do_join = true;
2828
2829 /* Need to update the SSID (for filtering etc) */
2830 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2831 do_join = true;
2832
2833 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002834 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2835 bss_conf->enable_beacon ? "enabled" : "disabled");
2836
2837 if (bss_conf->enable_beacon)
2838 wl->set_bss_type = BSS_TYPE_IBSS;
2839 else
2840 wl->set_bss_type = BSS_TYPE_STA_BSS;
2841 do_join = true;
2842 }
2843
Arik Nemtsove78a2872010-10-16 19:07:21 +02002844 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002845 bool enable = false;
2846 if (bss_conf->cqm_rssi_thold)
2847 enable = true;
2848 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2849 bss_conf->cqm_rssi_thold,
2850 bss_conf->cqm_rssi_hyst);
2851 if (ret < 0)
2852 goto out;
2853 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2854 }
2855
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002856 if ((changed & BSS_CHANGED_BSSID) &&
2857 /*
2858 * Now we know the correct bssid, so we send a new join command
2859 * and enable the BSSID filter
2860 */
2861 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002862 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002863
Eliad Pellerfa287b82010-12-26 09:27:50 +01002864 if (!is_zero_ether_addr(wl->bssid)) {
2865 ret = wl1271_cmd_build_null_data(wl);
2866 if (ret < 0)
2867 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002868
Eliad Pellerfa287b82010-12-26 09:27:50 +01002869 ret = wl1271_build_qos_null_data(wl);
2870 if (ret < 0)
2871 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002872
Eliad Pellerfa287b82010-12-26 09:27:50 +01002873 /* filter out all packets not from this BSSID */
2874 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002875
Eliad Pellerfa287b82010-12-26 09:27:50 +01002876 /* Need to update the BSSID (for filtering etc) */
2877 do_join = true;
2878 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002879 }
2880
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002881 rcu_read_lock();
2882 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2883 if (sta) {
2884 /* save the supp_rates of the ap */
2885 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2886 if (sta->ht_cap.ht_supported)
2887 sta_rate_set |=
2888 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002889 sta_ht_cap = sta->ht_cap;
2890 sta_exists = true;
2891 }
2892 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002893
Arik Nemtsova1008852011-02-12 23:24:20 +02002894 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002895 /* handle new association with HT and HT information change */
2896 if ((changed & BSS_CHANGED_HT) &&
2897 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002898 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002899 true);
2900 if (ret < 0) {
2901 wl1271_warning("Set ht cap true failed %d",
2902 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002903 goto out;
2904 }
2905 ret = wl1271_acx_set_ht_information(wl,
2906 bss_conf->ht_operation_mode);
2907 if (ret < 0) {
2908 wl1271_warning("Set ht information failed %d",
2909 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002910 goto out;
2911 }
2912 }
2913 /* handle new association without HT and disassociation */
2914 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002915 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002916 false);
2917 if (ret < 0) {
2918 wl1271_warning("Set ht cap false failed %d",
2919 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002920 goto out;
2921 }
2922 }
2923 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002924
Arik Nemtsove78a2872010-10-16 19:07:21 +02002925 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002927 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002928 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002930 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002932 wl->ps_poll_failures = 0;
2933
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002934 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002935 * use basic rates from AP, and determine lowest rate
2936 * to use with control frames.
2937 */
2938 rates = bss_conf->basic_rates;
2939 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2940 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002941 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002942 if (sta_rate_set)
2943 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2944 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002945 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002946 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002947 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002948
2949 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002950 * with wl1271, we don't need to update the
2951 * beacon_int and dtim_period, because the firmware
2952 * updates it by itself when the first beacon is
2953 * received after a join.
2954 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2956 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002957 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002959 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002960 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002961 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002962 dev_kfree_skb(wl->probereq);
2963 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2964 ieoffset = offsetof(struct ieee80211_mgmt,
2965 u.probe_req.variable);
2966 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002967
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002968 /* enable the connection monitoring feature */
2969 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002971 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972
2973 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002974 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2975 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002976 enum wl1271_cmd_ps_mode mode;
2977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002978 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002979 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002980 wl->basic_rate,
Juuso Oikarinen65cddbf12010-08-24 06:28:03 +03002981 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002982 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002983 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002985 } else {
2986 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002987 bool was_assoc =
2988 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2989 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002990 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002991 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002992
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002993 /* free probe-request template */
2994 dev_kfree_skb(wl->probereq);
2995 wl->probereq = NULL;
2996
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002997 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002998 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002999
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003000 /* revert back to minimum rates for the current band */
3001 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003002 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003003 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003004 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003005 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003006
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003007 /* disable connection monitor features */
3008 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003009
3010 /* Disable the keep-alive feature */
3011 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003012 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003013 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003014
3015 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003016 if (was_assoc) {
3017 wl1271_unjoin(wl);
3018 wl1271_dummy_join(wl);
3019 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003020 }
3021 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003022
Arik Nemtsove78a2872010-10-16 19:07:21 +02003023 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3024 if (ret < 0)
3025 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003026
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003027 if (changed & BSS_CHANGED_ARP_FILTER) {
3028 __be32 addr = bss_conf->arp_addr_list[0];
3029 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3030
Eliad Pellerc5312772010-12-09 11:31:27 +02003031 if (bss_conf->arp_addr_cnt == 1 &&
3032 bss_conf->arp_filter_enabled) {
3033 /*
3034 * The template should have been configured only upon
3035 * association. however, it seems that the correct ip
3036 * isn't being set (when sending), so we have to
3037 * reconfigure the template upon every ip change.
3038 */
3039 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3040 if (ret < 0) {
3041 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003042 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003043 }
3044
3045 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003046 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003047 addr);
3048 } else
3049 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003050
3051 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003052 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003053 }
3054
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003055 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003056 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003057 if (ret < 0) {
3058 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003059 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003060 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003061 }
3062
Arik Nemtsove78a2872010-10-16 19:07:21 +02003063out:
3064 return;
3065}
3066
3067static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3068 struct ieee80211_vif *vif,
3069 struct ieee80211_bss_conf *bss_conf,
3070 u32 changed)
3071{
3072 struct wl1271 *wl = hw->priv;
3073 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3074 int ret;
3075
3076 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3077 (int)changed);
3078
3079 mutex_lock(&wl->mutex);
3080
3081 if (unlikely(wl->state == WL1271_STATE_OFF))
3082 goto out;
3083
Ido Yariva6208652011-03-01 15:14:41 +02003084 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003085 if (ret < 0)
3086 goto out;
3087
3088 if (is_ap)
3089 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3090 else
3091 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3092
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003093 wl1271_ps_elp_sleep(wl);
3094
3095out:
3096 mutex_unlock(&wl->mutex);
3097}
3098
Kalle Valoc6999d82010-02-18 13:25:41 +02003099static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3100 const struct ieee80211_tx_queue_params *params)
3101{
3102 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003103 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003104 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003105
3106 mutex_lock(&wl->mutex);
3107
3108 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3109
Kalle Valo4695dc92010-03-18 12:26:38 +02003110 if (params->uapsd)
3111 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3112 else
3113 ps_scheme = CONF_PS_SCHEME_LEGACY;
3114
Arik Nemtsov488fc542010-10-16 20:33:45 +02003115 if (wl->state == WL1271_STATE_OFF) {
3116 /*
3117 * If the state is off, the parameters will be recorded and
3118 * configured on init. This happens in AP-mode.
3119 */
3120 struct conf_tx_ac_category *conf_ac =
3121 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3122 struct conf_tx_tid *conf_tid =
3123 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3124
3125 conf_ac->ac = wl1271_tx_get_queue(queue);
3126 conf_ac->cw_min = (u8)params->cw_min;
3127 conf_ac->cw_max = params->cw_max;
3128 conf_ac->aifsn = params->aifs;
3129 conf_ac->tx_op_limit = params->txop << 5;
3130
3131 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3132 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3133 conf_tid->tsid = wl1271_tx_get_queue(queue);
3134 conf_tid->ps_scheme = ps_scheme;
3135 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3136 conf_tid->apsd_conf[0] = 0;
3137 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003138 goto out;
3139 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003140
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003141 ret = wl1271_ps_elp_wakeup(wl);
3142 if (ret < 0)
3143 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003144
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003145 /*
3146 * the txop is confed in units of 32us by the mac80211,
3147 * we need us
3148 */
3149 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3150 params->cw_min, params->cw_max,
3151 params->aifs, params->txop << 5);
3152 if (ret < 0)
3153 goto out_sleep;
3154
3155 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3156 CONF_CHANNEL_TYPE_EDCF,
3157 wl1271_tx_get_queue(queue),
3158 ps_scheme, CONF_ACK_POLICY_LEGACY,
3159 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003160
3161out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003162 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003163
3164out:
3165 mutex_unlock(&wl->mutex);
3166
3167 return ret;
3168}
3169
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003170static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3171{
3172
3173 struct wl1271 *wl = hw->priv;
3174 u64 mactime = ULLONG_MAX;
3175 int ret;
3176
3177 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3178
3179 mutex_lock(&wl->mutex);
3180
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003181 if (unlikely(wl->state == WL1271_STATE_OFF))
3182 goto out;
3183
Ido Yariva6208652011-03-01 15:14:41 +02003184 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003185 if (ret < 0)
3186 goto out;
3187
3188 ret = wl1271_acx_tsf_info(wl, &mactime);
3189 if (ret < 0)
3190 goto out_sleep;
3191
3192out_sleep:
3193 wl1271_ps_elp_sleep(wl);
3194
3195out:
3196 mutex_unlock(&wl->mutex);
3197 return mactime;
3198}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003199
John W. Linvilleece550d2010-07-28 16:41:06 -04003200static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3201 struct survey_info *survey)
3202{
3203 struct wl1271 *wl = hw->priv;
3204 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003205
John W. Linvilleece550d2010-07-28 16:41:06 -04003206 if (idx != 0)
3207 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003208
John W. Linvilleece550d2010-07-28 16:41:06 -04003209 survey->channel = conf->channel;
3210 survey->filled = SURVEY_INFO_NOISE_DBM;
3211 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003212
John W. Linvilleece550d2010-07-28 16:41:06 -04003213 return 0;
3214}
3215
Arik Nemtsov409622e2011-02-23 00:22:29 +02003216static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003217 struct ieee80211_sta *sta,
3218 u8 *hlid)
3219{
3220 struct wl1271_station *wl_sta;
3221 int id;
3222
3223 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3224 if (id >= AP_MAX_STATIONS) {
3225 wl1271_warning("could not allocate HLID - too much stations");
3226 return -EBUSY;
3227 }
3228
3229 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003230 __set_bit(id, wl->ap_hlid_map);
3231 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3232 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003233 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003234 return 0;
3235}
3236
Arik Nemtsov409622e2011-02-23 00:22:29 +02003237static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003238{
3239 int id = hlid - WL1271_AP_STA_HLID_START;
3240
Arik Nemtsov409622e2011-02-23 00:22:29 +02003241 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3242 return;
3243
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003244 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003245 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003246 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003247 __clear_bit(hlid, &wl->ap_ps_map);
3248 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003249}
3250
3251static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3252 struct ieee80211_vif *vif,
3253 struct ieee80211_sta *sta)
3254{
3255 struct wl1271 *wl = hw->priv;
3256 int ret = 0;
3257 u8 hlid;
3258
3259 mutex_lock(&wl->mutex);
3260
3261 if (unlikely(wl->state == WL1271_STATE_OFF))
3262 goto out;
3263
3264 if (wl->bss_type != BSS_TYPE_AP_BSS)
3265 goto out;
3266
3267 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3268
Arik Nemtsov409622e2011-02-23 00:22:29 +02003269 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003270 if (ret < 0)
3271 goto out;
3272
Ido Yariva6208652011-03-01 15:14:41 +02003273 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003274 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003275 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003276
3277 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3278 if (ret < 0)
3279 goto out_sleep;
3280
3281out_sleep:
3282 wl1271_ps_elp_sleep(wl);
3283
Arik Nemtsov409622e2011-02-23 00:22:29 +02003284out_free_sta:
3285 if (ret < 0)
3286 wl1271_free_sta(wl, hlid);
3287
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003288out:
3289 mutex_unlock(&wl->mutex);
3290 return ret;
3291}
3292
3293static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3294 struct ieee80211_vif *vif,
3295 struct ieee80211_sta *sta)
3296{
3297 struct wl1271 *wl = hw->priv;
3298 struct wl1271_station *wl_sta;
3299 int ret = 0, id;
3300
3301 mutex_lock(&wl->mutex);
3302
3303 if (unlikely(wl->state == WL1271_STATE_OFF))
3304 goto out;
3305
3306 if (wl->bss_type != BSS_TYPE_AP_BSS)
3307 goto out;
3308
3309 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3310
3311 wl_sta = (struct wl1271_station *)sta->drv_priv;
3312 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3313 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3314 goto out;
3315
Ido Yariva6208652011-03-01 15:14:41 +02003316 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003317 if (ret < 0)
3318 goto out;
3319
3320 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3321 if (ret < 0)
3322 goto out_sleep;
3323
Arik Nemtsov409622e2011-02-23 00:22:29 +02003324 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003325
3326out_sleep:
3327 wl1271_ps_elp_sleep(wl);
3328
3329out:
3330 mutex_unlock(&wl->mutex);
3331 return ret;
3332}
3333
Luciano Coelho4623ec72011-03-21 19:26:41 +02003334static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3335 struct ieee80211_vif *vif,
3336 enum ieee80211_ampdu_mlme_action action,
3337 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3338 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003339{
3340 struct wl1271 *wl = hw->priv;
3341 int ret;
3342
3343 mutex_lock(&wl->mutex);
3344
3345 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3346 ret = -EAGAIN;
3347 goto out;
3348 }
3349
Ido Yariva6208652011-03-01 15:14:41 +02003350 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003351 if (ret < 0)
3352 goto out;
3353
3354 switch (action) {
3355 case IEEE80211_AMPDU_RX_START:
3356 if (wl->ba_support) {
3357 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3358 true);
3359 if (!ret)
3360 wl->ba_rx_bitmap |= BIT(tid);
3361 } else {
3362 ret = -ENOTSUPP;
3363 }
3364 break;
3365
3366 case IEEE80211_AMPDU_RX_STOP:
3367 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3368 if (!ret)
3369 wl->ba_rx_bitmap &= ~BIT(tid);
3370 break;
3371
3372 /*
3373 * The BA initiator session management in FW independently.
3374 * Falling break here on purpose for all TX APDU commands.
3375 */
3376 case IEEE80211_AMPDU_TX_START:
3377 case IEEE80211_AMPDU_TX_STOP:
3378 case IEEE80211_AMPDU_TX_OPERATIONAL:
3379 ret = -EINVAL;
3380 break;
3381
3382 default:
3383 wl1271_error("Incorrect ampdu action id=%x\n", action);
3384 ret = -EINVAL;
3385 }
3386
3387 wl1271_ps_elp_sleep(wl);
3388
3389out:
3390 mutex_unlock(&wl->mutex);
3391
3392 return ret;
3393}
3394
Arik Nemtsov33437892011-04-26 23:35:39 +03003395static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3396{
3397 struct wl1271 *wl = hw->priv;
3398 bool ret = false;
3399
3400 mutex_lock(&wl->mutex);
3401
3402 if (unlikely(wl->state == WL1271_STATE_OFF))
3403 goto out;
3404
3405 /* packets are considered pending if in the TX queue or the FW */
3406 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3407
3408 /* the above is appropriate for STA mode for PS purposes */
3409 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3410
3411out:
3412 mutex_unlock(&wl->mutex);
3413
3414 return ret;
3415}
3416
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003417/* can't be const, mac80211 writes to this */
3418static struct ieee80211_rate wl1271_rates[] = {
3419 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003420 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3421 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003422 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003423 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3424 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003425 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3426 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003427 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3428 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003429 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3430 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003431 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3432 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003433 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3434 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003435 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3436 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003437 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003438 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3439 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003440 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003441 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3442 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003443 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003444 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3445 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003446 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003447 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3448 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003449 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003450 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3451 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003452 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003453 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3454 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003455 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003456 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3457 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003458};
3459
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003460/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003461static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003462 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003463 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003464 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3465 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3466 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003467 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003468 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3469 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3470 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003471 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003472 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3473 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3474 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003475 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003476};
3477
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003478/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003479static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003480 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003481 7, /* CONF_HW_RXTX_RATE_MCS7 */
3482 6, /* CONF_HW_RXTX_RATE_MCS6 */
3483 5, /* CONF_HW_RXTX_RATE_MCS5 */
3484 4, /* CONF_HW_RXTX_RATE_MCS4 */
3485 3, /* CONF_HW_RXTX_RATE_MCS3 */
3486 2, /* CONF_HW_RXTX_RATE_MCS2 */
3487 1, /* CONF_HW_RXTX_RATE_MCS1 */
3488 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003489
3490 11, /* CONF_HW_RXTX_RATE_54 */
3491 10, /* CONF_HW_RXTX_RATE_48 */
3492 9, /* CONF_HW_RXTX_RATE_36 */
3493 8, /* CONF_HW_RXTX_RATE_24 */
3494
3495 /* TI-specific rate */
3496 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3497
3498 7, /* CONF_HW_RXTX_RATE_18 */
3499 6, /* CONF_HW_RXTX_RATE_12 */
3500 3, /* CONF_HW_RXTX_RATE_11 */
3501 5, /* CONF_HW_RXTX_RATE_9 */
3502 4, /* CONF_HW_RXTX_RATE_6 */
3503 2, /* CONF_HW_RXTX_RATE_5_5 */
3504 1, /* CONF_HW_RXTX_RATE_2 */
3505 0 /* CONF_HW_RXTX_RATE_1 */
3506};
3507
Shahar Levie8b03a22010-10-13 16:09:39 +02003508/* 11n STA capabilities */
3509#define HW_RX_HIGHEST_RATE 72
3510
Shahar Levi00d20102010-11-08 11:20:10 +00003511#ifdef CONFIG_WL12XX_HT
3512#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003513 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3514 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003515 .ht_supported = true, \
3516 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3517 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3518 .mcs = { \
3519 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3520 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3521 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3522 }, \
3523}
Shahar Levi18357852010-10-13 16:09:41 +02003524#else
Shahar Levi00d20102010-11-08 11:20:10 +00003525#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003526 .ht_supported = false, \
3527}
3528#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003529
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530/* can't be const, mac80211 writes to this */
3531static struct ieee80211_supported_band wl1271_band_2ghz = {
3532 .channels = wl1271_channels,
3533 .n_channels = ARRAY_SIZE(wl1271_channels),
3534 .bitrates = wl1271_rates,
3535 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003536 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537};
3538
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003539/* 5 GHz data rates for WL1273 */
3540static struct ieee80211_rate wl1271_rates_5ghz[] = {
3541 { .bitrate = 60,
3542 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3543 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3544 { .bitrate = 90,
3545 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3546 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3547 { .bitrate = 120,
3548 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3549 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3550 { .bitrate = 180,
3551 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3552 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3553 { .bitrate = 240,
3554 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3555 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3556 { .bitrate = 360,
3557 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3558 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3559 { .bitrate = 480,
3560 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3561 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3562 { .bitrate = 540,
3563 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3564 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3565};
3566
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003567/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003568static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003569 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003570 { .hw_value = 8, .center_freq = 5040},
3571 { .hw_value = 9, .center_freq = 5045},
3572 { .hw_value = 11, .center_freq = 5055},
3573 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003574 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003575 { .hw_value = 34, .center_freq = 5170},
3576 { .hw_value = 36, .center_freq = 5180},
3577 { .hw_value = 38, .center_freq = 5190},
3578 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003579 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003580 { .hw_value = 44, .center_freq = 5220},
3581 { .hw_value = 46, .center_freq = 5230},
3582 { .hw_value = 48, .center_freq = 5240},
3583 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003584 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003585 { .hw_value = 60, .center_freq = 5300},
3586 { .hw_value = 64, .center_freq = 5320},
3587 { .hw_value = 100, .center_freq = 5500},
3588 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003589 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003590 { .hw_value = 112, .center_freq = 5560},
3591 { .hw_value = 116, .center_freq = 5580},
3592 { .hw_value = 120, .center_freq = 5600},
3593 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003594 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003595 { .hw_value = 132, .center_freq = 5660},
3596 { .hw_value = 136, .center_freq = 5680},
3597 { .hw_value = 140, .center_freq = 5700},
3598 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003599 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003600 { .hw_value = 157, .center_freq = 5785},
3601 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003602 { .hw_value = 165, .center_freq = 5825},
3603};
3604
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003605/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003606static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003607 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003608 7, /* CONF_HW_RXTX_RATE_MCS7 */
3609 6, /* CONF_HW_RXTX_RATE_MCS6 */
3610 5, /* CONF_HW_RXTX_RATE_MCS5 */
3611 4, /* CONF_HW_RXTX_RATE_MCS4 */
3612 3, /* CONF_HW_RXTX_RATE_MCS3 */
3613 2, /* CONF_HW_RXTX_RATE_MCS2 */
3614 1, /* CONF_HW_RXTX_RATE_MCS1 */
3615 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003616
3617 7, /* CONF_HW_RXTX_RATE_54 */
3618 6, /* CONF_HW_RXTX_RATE_48 */
3619 5, /* CONF_HW_RXTX_RATE_36 */
3620 4, /* CONF_HW_RXTX_RATE_24 */
3621
3622 /* TI-specific rate */
3623 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3624
3625 3, /* CONF_HW_RXTX_RATE_18 */
3626 2, /* CONF_HW_RXTX_RATE_12 */
3627 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3628 1, /* CONF_HW_RXTX_RATE_9 */
3629 0, /* CONF_HW_RXTX_RATE_6 */
3630 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3631 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3632 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3633};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003634
3635static struct ieee80211_supported_band wl1271_band_5ghz = {
3636 .channels = wl1271_channels_5ghz,
3637 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3638 .bitrates = wl1271_rates_5ghz,
3639 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003640 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003641};
3642
Tobias Klausera0ea9492010-05-20 10:38:11 +02003643static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003644 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3645 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3646};
3647
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003648static const struct ieee80211_ops wl1271_ops = {
3649 .start = wl1271_op_start,
3650 .stop = wl1271_op_stop,
3651 .add_interface = wl1271_op_add_interface,
3652 .remove_interface = wl1271_op_remove_interface,
Eliad Peller402e48612011-05-13 11:57:09 +03003653 .suspend = wl1271_op_suspend,
3654 .resume = wl1271_op_resume,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003655 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003656 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003657 .configure_filter = wl1271_op_configure_filter,
3658 .tx = wl1271_op_tx,
3659 .set_key = wl1271_op_set_key,
3660 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003661 .sched_scan_start = wl1271_op_sched_scan_start,
3662 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003663 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003664 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003665 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003666 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003667 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003668 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003669 .sta_add = wl1271_op_sta_add,
3670 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003671 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003672 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003673 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003674};
3675
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003676
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003677u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003678{
3679 u8 idx;
3680
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003681 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003682
3683 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3684 wl1271_error("Illegal RX rate from HW: %d", rate);
3685 return 0;
3686 }
3687
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003688 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003689 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3690 wl1271_error("Unsupported RX rate from HW: %d", rate);
3691 return 0;
3692 }
3693
3694 return idx;
3695}
3696
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003697static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3698 struct device_attribute *attr,
3699 char *buf)
3700{
3701 struct wl1271 *wl = dev_get_drvdata(dev);
3702 ssize_t len;
3703
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003704 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003705
3706 mutex_lock(&wl->mutex);
3707 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3708 wl->sg_enabled);
3709 mutex_unlock(&wl->mutex);
3710
3711 return len;
3712
3713}
3714
3715static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3716 struct device_attribute *attr,
3717 const char *buf, size_t count)
3718{
3719 struct wl1271 *wl = dev_get_drvdata(dev);
3720 unsigned long res;
3721 int ret;
3722
Luciano Coelho6277ed62011-04-01 17:49:54 +03003723 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003724 if (ret < 0) {
3725 wl1271_warning("incorrect value written to bt_coex_mode");
3726 return count;
3727 }
3728
3729 mutex_lock(&wl->mutex);
3730
3731 res = !!res;
3732
3733 if (res == wl->sg_enabled)
3734 goto out;
3735
3736 wl->sg_enabled = res;
3737
3738 if (wl->state == WL1271_STATE_OFF)
3739 goto out;
3740
Ido Yariva6208652011-03-01 15:14:41 +02003741 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003742 if (ret < 0)
3743 goto out;
3744
3745 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3746 wl1271_ps_elp_sleep(wl);
3747
3748 out:
3749 mutex_unlock(&wl->mutex);
3750 return count;
3751}
3752
3753static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3754 wl1271_sysfs_show_bt_coex_state,
3755 wl1271_sysfs_store_bt_coex_state);
3756
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003757static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3758 struct device_attribute *attr,
3759 char *buf)
3760{
3761 struct wl1271 *wl = dev_get_drvdata(dev);
3762 ssize_t len;
3763
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003764 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003765
3766 mutex_lock(&wl->mutex);
3767 if (wl->hw_pg_ver >= 0)
3768 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3769 else
3770 len = snprintf(buf, len, "n/a\n");
3771 mutex_unlock(&wl->mutex);
3772
3773 return len;
3774}
3775
3776static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3777 wl1271_sysfs_show_hw_pg_ver, NULL);
3778
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003779int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003780{
3781 int ret;
3782
3783 if (wl->mac80211_registered)
3784 return 0;
3785
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003786 ret = wl1271_fetch_nvs(wl);
3787 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003788 /* NOTE: The wl->nvs->nvs element must be first, in
3789 * order to simplify the casting, we assume it is at
3790 * the beginning of the wl->nvs structure.
3791 */
3792 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003793
3794 wl->mac_addr[0] = nvs_ptr[11];
3795 wl->mac_addr[1] = nvs_ptr[10];
3796 wl->mac_addr[2] = nvs_ptr[6];
3797 wl->mac_addr[3] = nvs_ptr[5];
3798 wl->mac_addr[4] = nvs_ptr[4];
3799 wl->mac_addr[5] = nvs_ptr[3];
3800 }
3801
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003802 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3803
3804 ret = ieee80211_register_hw(wl->hw);
3805 if (ret < 0) {
3806 wl1271_error("unable to register mac80211 hw: %d", ret);
3807 return ret;
3808 }
3809
3810 wl->mac80211_registered = true;
3811
Eliad Pellerd60080a2010-11-24 12:53:16 +02003812 wl1271_debugfs_init(wl);
3813
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003814 register_netdevice_notifier(&wl1271_dev_notifier);
3815
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003816 wl1271_notice("loaded");
3817
3818 return 0;
3819}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003820EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003821
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003822void wl1271_unregister_hw(struct wl1271 *wl)
3823{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003824 if (wl->state == WL1271_STATE_PLT)
3825 __wl1271_plt_stop(wl);
3826
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003827 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003828 ieee80211_unregister_hw(wl->hw);
3829 wl->mac80211_registered = false;
3830
3831}
3832EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3833
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003834int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003835{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003836 static const u32 cipher_suites[] = {
3837 WLAN_CIPHER_SUITE_WEP40,
3838 WLAN_CIPHER_SUITE_WEP104,
3839 WLAN_CIPHER_SUITE_TKIP,
3840 WLAN_CIPHER_SUITE_CCMP,
3841 WL1271_CIPHER_SUITE_GEM,
3842 };
3843
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003844 /* The tx descriptor buffer and the TKIP space. */
3845 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3846 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003847
3848 /* unit us */
3849 /* FIXME: find a proper value */
3850 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003851 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003852
3853 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003854 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003855 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003856 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003857 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003858 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003859 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003860 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003861 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003862 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003863
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003864 wl->hw->wiphy->cipher_suites = cipher_suites;
3865 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3866
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003867 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003868 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003869 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003870 /*
3871 * Maximum length of elements in scanning probe request templates
3872 * should be the maximum length possible for a template, without
3873 * the IEEE80211 header of the template
3874 */
3875 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3876 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003877
Luciano Coelho4a31c112011-03-21 23:16:14 +02003878 /* make sure all our channels fit in the scanned_ch bitmask */
3879 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3880 ARRAY_SIZE(wl1271_channels_5ghz) >
3881 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003882 /*
3883 * We keep local copies of the band structs because we need to
3884 * modify them on a per-device basis.
3885 */
3886 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3887 sizeof(wl1271_band_2ghz));
3888 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3889 sizeof(wl1271_band_5ghz));
3890
3891 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3892 &wl->bands[IEEE80211_BAND_2GHZ];
3893 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3894 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003895
Kalle Valo12bd8942010-03-18 12:26:33 +02003896 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003897 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003898
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003899 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3900
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003901 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003902
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003903 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3904
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003905 wl->hw->max_rx_aggregation_subframes = 8;
3906
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003907 return 0;
3908}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003909EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003910
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003911#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003912
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003913struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003914{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003915 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003916 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003917 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003918 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003919 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003920
3921 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3922 if (!hw) {
3923 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003924 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003925 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003926 }
3927
Julia Lawall929ebd32010-05-15 23:16:39 +02003928 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003929 if (!plat_dev) {
3930 wl1271_error("could not allocate platform_device");
3931 ret = -ENOMEM;
3932 goto err_plat_alloc;
3933 }
3934
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003935 wl = hw->priv;
3936 memset(wl, 0, sizeof(*wl));
3937
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003938 INIT_LIST_HEAD(&wl->list);
3939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003940 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003941 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003942
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003943 for (i = 0; i < NUM_TX_QUEUES; i++)
3944 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003945
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003946 for (i = 0; i < NUM_TX_QUEUES; i++)
3947 for (j = 0; j < AP_MAX_LINKS; j++)
3948 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3949
Ido Yariva6208652011-03-01 15:14:41 +02003950 skb_queue_head_init(&wl->deferred_rx_queue);
3951 skb_queue_head_init(&wl->deferred_tx_queue);
3952
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003953 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003954 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003955 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003956 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3957 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3958 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003959 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003960 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003961 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003962 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003963 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3964 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003965 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003966 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003967 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003968 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003969 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003970 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003971 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003972 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003973 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003974 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003975 wl->bss_type = MAX_BSS_TYPE;
3976 wl->set_bss_type = MAX_BSS_TYPE;
3977 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003978 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003979 wl->ap_ps_map = 0;
3980 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003981 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003982 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003983 wl->sched_scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003984
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003985 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003986 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003987 wl->tx_frames[i] = NULL;
3988
3989 spin_lock_init(&wl->wl_lock);
3990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003991 wl->state = WL1271_STATE_OFF;
3992 mutex_init(&wl->mutex);
3993
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003994 /* Apply default driver configuration. */
3995 wl1271_conf_init(wl);
3996
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003997 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3998 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3999 if (!wl->aggr_buf) {
4000 ret = -ENOMEM;
4001 goto err_hw;
4002 }
4003
Ido Yariv990f5de2011-03-31 10:06:59 +02004004 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4005 if (!wl->dummy_packet) {
4006 ret = -ENOMEM;
4007 goto err_aggr;
4008 }
4009
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004010 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004011 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004012 if (ret) {
4013 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02004014 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004015 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004016 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004017
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004018 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004019 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004020 if (ret < 0) {
4021 wl1271_error("failed to create sysfs file bt_coex_state");
4022 goto err_platform;
4023 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004024
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004025 /* Create sysfs file to get HW PG version */
4026 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4027 if (ret < 0) {
4028 wl1271_error("failed to create sysfs file hw_pg_ver");
4029 goto err_bt_coex_state;
4030 }
4031
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004032 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004033
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004034err_bt_coex_state:
4035 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4036
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004037err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004038 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004039
Ido Yariv990f5de2011-03-31 10:06:59 +02004040err_dummy_packet:
4041 dev_kfree_skb(wl->dummy_packet);
4042
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004043err_aggr:
4044 free_pages((unsigned long)wl->aggr_buf, order);
4045
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004046err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004047 wl1271_debugfs_exit(wl);
4048 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004049
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004050err_plat_alloc:
4051 ieee80211_free_hw(hw);
4052
4053err_hw_alloc:
4054
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004055 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004056}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004057EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004058
4059int wl1271_free_hw(struct wl1271 *wl)
4060{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004061 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02004062 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004063 free_pages((unsigned long)wl->aggr_buf,
4064 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004065 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004066
4067 wl1271_debugfs_exit(wl);
4068
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004069 vfree(wl->fw);
4070 wl->fw = NULL;
4071 kfree(wl->nvs);
4072 wl->nvs = NULL;
4073
4074 kfree(wl->fw_status);
4075 kfree(wl->tx_res_if);
4076
4077 ieee80211_free_hw(wl->hw);
4078
4079 return 0;
4080}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004081EXPORT_SYMBOL_GPL(wl1271_free_hw);
4082
Guy Eilam491bbd62011-01-12 10:33:29 +01004083u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004084EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004085module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004086MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4087
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004088MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004089MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004090MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");