blob: 4b421d801873396037596f7c89d72b1849e6e26b [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030034
Shahar Levi00d20102010-11-08 11:20:10 +000035#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "reg.h"
38#include "io.h"
39#include "event.h"
40#include "tx.h"
41#include "rx.h"
42#include "ps.h"
43#include "init.h"
44#include "debugfs.h"
45#include "cmd.h"
46#include "boot.h"
47#include "testmode.h"
48#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030049
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020050#define WL1271_BOOT_RETRIES 3
51
Juuso Oikarinen8a080482009-10-13 12:47:44 +030052static struct conf_drv_settings default_conf = {
53 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030054 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020055 [CONF_SG_BT_PER_THRESHOLD] = 7500,
56 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
57 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020058 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030059 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020060 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
61 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
62 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
63 [CONF_SG_BEACON_MISS_PERCENT] = 60,
64 [CONF_SG_RATE_ADAPT_THRESH] = 12,
65 [CONF_SG_RATE_ADAPT_SNR] = 0,
66 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
68 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
69 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
71 /* Note: with UPSD, this should be 4 */
72 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
73 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
75 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
76 /* Note: with UPDS, this should be 15 */
77 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
78 /* Note: with UPDS, this should be 50 */
79 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
80 /* Note: with UPDS, this should be 10 */
81 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
82 [CONF_SG_RXT] = 1200,
83 [CONF_SG_TXT] = 1000,
84 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
85 [CONF_SG_PS_POLL_TIMEOUT] = 10,
86 [CONF_SG_UPSD_TIMEOUT] = 10,
87 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
89 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
92 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
93 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
95 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
96 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
98 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
99 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
100 [CONF_SG_HV3_MAX_SERVED] = 6,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
103 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300104 .ap_params = {
105 [CONF_SG_BT_PER_THRESHOLD] = 7500,
106 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
107 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
108 [CONF_SG_BT_LOAD_RATIO] = 50,
109 [CONF_SG_AUTO_PS_MODE] = 1,
110 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
111 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
112 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
113 [CONF_SG_BEACON_MISS_PERCENT] = 60,
114 [CONF_SG_RATE_ADAPT_THRESH] = 64,
115 [CONF_SG_RATE_ADAPT_SNR] = 1,
116 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
118 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
119 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
121 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
122 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
124 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
125 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
127 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
128 [CONF_SG_RXT] = 1200,
129 [CONF_SG_TXT] = 1000,
130 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
131 [CONF_SG_PS_POLL_TIMEOUT] = 10,
132 [CONF_SG_UPSD_TIMEOUT] = 10,
133 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
135 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
138 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
139 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
141 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
142 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
144 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
145 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
146 [CONF_SG_HV3_MAX_SERVED] = 6,
147 [CONF_SG_DHCP_TIME] = 5000,
148 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
149 [CONF_SG_TEMP_PARAM_1] = 0,
150 [CONF_SG_TEMP_PARAM_2] = 0,
151 [CONF_SG_TEMP_PARAM_3] = 0,
152 [CONF_SG_TEMP_PARAM_4] = 0,
153 [CONF_SG_TEMP_PARAM_5] = 0,
154 [CONF_SG_AP_BEACON_MISS_TX] = 3,
155 [CONF_SG_RX_WINDOW_LENGTH] = 6,
156 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
157 [CONF_SG_TEMP_PARAM_6] = 1,
158 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200159 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300160 },
161 .rx = {
162 .rx_msdu_life_time = 512000,
163 .packet_detection_threshold = 0,
164 .ps_poll_timeout = 15,
165 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300166 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200167 .rx_cca_threshold = 0,
168 .irq_blk_threshold = 0xFFFF,
169 .irq_pkt_threshold = 0,
170 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300171 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
172 },
173 .tx = {
174 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200175 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300176 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300177 .short_retry_limit = 10,
178 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200179 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300180 },
181 .ac_conf_count = 4,
182 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200183 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300184 .ac = CONF_TX_AC_BE,
185 .cw_min = 15,
186 .cw_max = 63,
187 .aifsn = 3,
188 .tx_op_limit = 0,
189 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200190 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300191 .ac = CONF_TX_AC_BK,
192 .cw_min = 15,
193 .cw_max = 63,
194 .aifsn = 7,
195 .tx_op_limit = 0,
196 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200197 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300198 .ac = CONF_TX_AC_VI,
199 .cw_min = 15,
200 .cw_max = 63,
201 .aifsn = CONF_TX_AIFS_PIFS,
202 .tx_op_limit = 3008,
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300205 .ac = CONF_TX_AC_VO,
206 .cw_min = 15,
207 .cw_max = 63,
208 .aifsn = CONF_TX_AIFS_PIFS,
209 .tx_op_limit = 1504,
210 },
211 },
Luciano Coelho25eaea302011-05-02 12:37:33 +0300212 .ap_max_tx_retries = 100,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200213 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300214 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 [CONF_TX_AC_BE] = {
216 .queue_id = CONF_TX_AC_BE,
217 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300218 .tsid = CONF_TX_AC_BE,
219 .ps_scheme = CONF_PS_SCHEME_LEGACY,
220 .ack_policy = CONF_ACK_POLICY_LEGACY,
221 .apsd_conf = {0, 0},
222 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200223 [CONF_TX_AC_BK] = {
224 .queue_id = CONF_TX_AC_BK,
225 .channel_type = CONF_CHANNEL_TYPE_EDCF,
226 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300227 .ps_scheme = CONF_PS_SCHEME_LEGACY,
228 .ack_policy = CONF_ACK_POLICY_LEGACY,
229 .apsd_conf = {0, 0},
230 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200231 [CONF_TX_AC_VI] = {
232 .queue_id = CONF_TX_AC_VI,
233 .channel_type = CONF_CHANNEL_TYPE_EDCF,
234 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300235 .ps_scheme = CONF_PS_SCHEME_LEGACY,
236 .ack_policy = CONF_ACK_POLICY_LEGACY,
237 .apsd_conf = {0, 0},
238 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200239 [CONF_TX_AC_VO] = {
240 .queue_id = CONF_TX_AC_VO,
241 .channel_type = CONF_CHANNEL_TYPE_EDCF,
242 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300243 .ps_scheme = CONF_PS_SCHEME_LEGACY,
244 .ack_policy = CONF_ACK_POLICY_LEGACY,
245 .apsd_conf = {0, 0},
246 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300247 },
248 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200249 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300250 .tx_compl_threshold = 4,
251 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
252 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200253 .tmpl_short_retry_limit = 10,
254 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300255 },
256 .conn = {
257 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300258 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300259 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300260 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_ie = {
262 [0] = {
263 .ie = WLAN_EID_CHANNEL_SWITCH,
264 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300265 },
266 [1] = {
267 .ie = WLAN_EID_HT_INFORMATION,
268 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
269 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300270 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200271 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 .bss_lose_timeout = 100,
273 .beacon_rx_timeout = 10000,
274 .broadcast_timeout = 20000,
275 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300276 .ps_poll_threshold = 10,
277 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300278 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200279 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200280 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300281 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_nullfunc_retries = 3,
283 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300284 .keep_alive_interval = 55000,
285 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300286 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200287 .itrim = {
288 .enable = false,
289 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200290 },
291 .pm_config = {
292 .host_clk_settling_time = 5000,
293 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300294 },
295 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 .trigger_pacing = 1,
297 .avg_weight_rssi_beacon = 20,
298 .avg_weight_rssi_data = 10,
299 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200301 },
302 .scan = {
303 .min_dwell_time_active = 7500,
304 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100305 .min_dwell_time_passive = 100000,
306 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200307 .num_probe_reqs = 2,
308 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300309 .sched_scan = {
310 /* sched_scan requires dwell times in TU instead of TU/1000 */
311 .min_dwell_time_active = 8,
312 .max_dwell_time_active = 30,
313 .dwell_time_passive = 100,
314 .num_probe_reqs = 2,
315 .rssi_threshold = -90,
316 .snr_threshold = 0,
317 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200318 .rf = {
319 .tx_per_channel_power_compensation_2 = {
320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321 },
322 .tx_per_channel_power_compensation_5 = {
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 },
327 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100328 .ht = {
329 .tx_ba_win_size = 64,
330 .inactivity_timeout = 10000,
331 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200332 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200333 .num_stations = 1,
334 .ssid_profiles = 1,
335 .rx_block_num = 70,
336 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300337 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200338 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200339 .min_req_rx_blocks = 22,
340 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200341 },
342 .mem_wl128x = {
343 .num_stations = 1,
344 .ssid_profiles = 1,
345 .rx_block_num = 40,
346 .tx_min_block_num = 40,
347 .dynamic_memory = 1,
348 .min_req_tx_blocks = 45,
349 .min_req_rx_blocks = 22,
350 .tx_min = 27,
351 },
Shahar Leviff868432011-04-11 15:41:46 +0300352 .fm_coex = {
353 .enable = true,
354 .swallow_period = 5,
355 .n_divider_fref_set_1 = 0xff, /* default */
356 .n_divider_fref_set_2 = 12,
357 .m_divider_fref_set_1 = 148,
358 .m_divider_fref_set_2 = 0xffff, /* default */
359 .coex_pll_stabilization_time = 0xffffffff, /* default */
360 .ldo_stabilization_time = 0xffff, /* default */
361 .fm_disturbed_band_margin = 0xff, /* default */
362 .swallow_clk_diff = 0xff, /* default */
363 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300364 .hci_io_ds = HCI_IO_DS_6MA,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300365};
366
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300367static void __wl1271_op_remove_interface(struct wl1271 *wl,
368 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200369static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200370
371
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200372static void wl1271_device_release(struct device *dev)
373{
374
375}
376
377static struct platform_device wl1271_device = {
378 .name = "wl1271",
379 .id = -1,
380
381 /* device model insists to have a release function */
382 .dev = {
383 .release = wl1271_device_release,
384 },
385};
386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300390static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
391 void *arg)
392{
393 struct net_device *dev = arg;
394 struct wireless_dev *wdev;
395 struct wiphy *wiphy;
396 struct ieee80211_hw *hw;
397 struct wl1271 *wl;
398 struct wl1271 *wl_temp;
399 int ret = 0;
400
401 /* Check that this notification is for us. */
402 if (what != NETDEV_CHANGE)
403 return NOTIFY_DONE;
404
405 wdev = dev->ieee80211_ptr;
406 if (wdev == NULL)
407 return NOTIFY_DONE;
408
409 wiphy = wdev->wiphy;
410 if (wiphy == NULL)
411 return NOTIFY_DONE;
412
413 hw = wiphy_priv(wiphy);
414 if (hw == NULL)
415 return NOTIFY_DONE;
416
417 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200418 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300419 list_for_each_entry(wl, &wl_list, list) {
420 if (wl == wl_temp)
421 break;
422 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200423 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300424 if (wl != wl_temp)
425 return NOTIFY_DONE;
426
427 mutex_lock(&wl->mutex);
428
429 if (wl->state == WL1271_STATE_OFF)
430 goto out;
431
432 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
433 goto out;
434
Ido Yariva6208652011-03-01 15:14:41 +0200435 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300436 if (ret < 0)
437 goto out;
438
439 if ((dev->operstate == IF_OPER_UP) &&
440 !test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) {
441 wl1271_cmd_set_sta_state(wl);
442 wl1271_info("Association completed.");
443 }
444
445 wl1271_ps_elp_sleep(wl);
446
447out:
448 mutex_unlock(&wl->mutex);
449
450 return NOTIFY_OK;
451}
452
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100453static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200454 struct regulatory_request *request)
455{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100456 struct ieee80211_supported_band *band;
457 struct ieee80211_channel *ch;
458 int i;
459
460 band = wiphy->bands[IEEE80211_BAND_5GHZ];
461 for (i = 0; i < band->n_channels; i++) {
462 ch = &band->channels[i];
463 if (ch->flags & IEEE80211_CHAN_DISABLED)
464 continue;
465
466 if (ch->flags & IEEE80211_CHAN_RADAR)
467 ch->flags |= IEEE80211_CHAN_NO_IBSS |
468 IEEE80211_CHAN_PASSIVE_SCAN;
469
470 }
471
472 return 0;
473}
474
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300475static void wl1271_conf_init(struct wl1271 *wl)
476{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300477
478 /*
479 * This function applies the default configuration to the driver. This
480 * function is invoked upon driver load (spi probe.)
481 *
482 * The configuration is stored in a run-time structure in order to
483 * facilitate for run-time adjustment of any of the parameters. Making
484 * changes to the configuration structure will apply the new values on
485 * the next interface up (wl1271_op_start.)
486 */
487
488 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300489 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300490}
491
492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300493static int wl1271_plt_init(struct wl1271 *wl)
494{
Luciano 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 Peller402e48612011-05-13 11:57:09 +03001353static int wl1271_op_suspend(struct ieee80211_hw *hw,
1354 struct cfg80211_wowlan *wow)
1355{
1356 struct wl1271 *wl = hw->priv;
1357 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
1358 wl->wow_enabled = !!wow;
1359 return 0;
1360}
1361
1362static int wl1271_op_resume(struct ieee80211_hw *hw)
1363{
1364 struct wl1271 *wl = hw->priv;
1365 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1366 wl->wow_enabled);
1367 return 0;
1368}
1369
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370static int wl1271_op_start(struct ieee80211_hw *hw)
1371{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001372 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1373
1374 /*
1375 * We have to delay the booting of the hardware because
1376 * we need to know the local MAC address before downloading and
1377 * initializing the firmware. The MAC address cannot be changed
1378 * after boot, and without the proper MAC address, the firmware
1379 * will not function properly.
1380 *
1381 * The MAC address is first known when the corresponding interface
1382 * is added. That is where we will initialize the hardware.
Arik Nemtsov166d5042010-10-16 21:44:57 +02001383 *
1384 * In addition, we currently have different firmwares for AP and managed
1385 * operation. We will know which to boot according to interface type.
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001386 */
1387
1388 return 0;
1389}
1390
1391static void wl1271_op_stop(struct ieee80211_hw *hw)
1392{
1393 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1394}
1395
1396static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1397 struct ieee80211_vif *vif)
1398{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001400 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001403 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001405 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1406 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407
1408 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001409 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001410 wl1271_debug(DEBUG_MAC80211,
1411 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001412 ret = -EBUSY;
1413 goto out;
1414 }
1415
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001416 /*
1417 * in some very corner case HW recovery scenarios its possible to
1418 * get here before __wl1271_op_remove_interface is complete, so
1419 * opt out if that is the case.
1420 */
1421 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1422 ret = -EBUSY;
1423 goto out;
1424 }
1425
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001426 switch (vif->type) {
1427 case NL80211_IFTYPE_STATION:
1428 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001429 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001430 break;
1431 case NL80211_IFTYPE_ADHOC:
1432 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001433 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001434 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001435 case NL80211_IFTYPE_AP:
1436 wl->bss_type = BSS_TYPE_AP_BSS;
1437 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001438 default:
1439 ret = -EOPNOTSUPP;
1440 goto out;
1441 }
1442
1443 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001444
1445 if (wl->state != WL1271_STATE_OFF) {
1446 wl1271_error("cannot start because not in off state: %d",
1447 wl->state);
1448 ret = -EBUSY;
1449 goto out;
1450 }
1451
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001452 while (retries) {
1453 retries--;
1454 ret = wl1271_chip_wakeup(wl);
1455 if (ret < 0)
1456 goto power_off;
1457
1458 ret = wl1271_boot(wl);
1459 if (ret < 0)
1460 goto power_off;
1461
1462 ret = wl1271_hw_init(wl);
1463 if (ret < 0)
1464 goto irq_disable;
1465
Eliad Peller71125ab2010-10-28 21:46:43 +02001466 booted = true;
1467 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001468
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001469irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001470 mutex_unlock(&wl->mutex);
1471 /* Unlocking the mutex in the middle of handling is
1472 inherently unsafe. In this case we deem it safe to do,
1473 because we need to let any possibly pending IRQ out of
1474 the system (and while we are WL1271_STATE_OFF the IRQ
1475 work function will not do anything.) Also, any other
1476 possible concurrent operations will fail due to the
1477 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001478 wl1271_disable_interrupts(wl);
1479 wl1271_flush_deferred_work(wl);
1480 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001481 mutex_lock(&wl->mutex);
1482power_off:
1483 wl1271_power_off(wl);
1484 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485
Eliad Peller71125ab2010-10-28 21:46:43 +02001486 if (!booted) {
1487 wl1271_error("firmware boot failed despite %d retries",
1488 WL1271_BOOT_RETRIES);
1489 goto out;
1490 }
1491
1492 wl->vif = vif;
1493 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001494 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001495 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001496
1497 /* update hw/fw version info in wiphy struct */
1498 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001499 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001500 sizeof(wiphy->fw_version));
1501
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001502 /* Check if any quirks are needed with older fw versions */
1503 wl->quirks |= wl1271_get_fw_ver_quirks(wl);
1504
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001505 /*
1506 * Now we know if 11a is supported (info from the NVS), so disable
1507 * 11a channels if not supported
1508 */
1509 if (!wl->enable_11a)
1510 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1511
1512 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1513 wl->enable_11a ? "" : "not ");
1514
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001515out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001516 mutex_unlock(&wl->mutex);
1517
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001518 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001519 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001520 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001521 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001522
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001523 return ret;
1524}
1525
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001526static void __wl1271_op_remove_interface(struct wl1271 *wl,
1527 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001529 int i;
1530
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001531 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001533 /* because of hardware recovery, we may get here twice */
1534 if (wl->state != WL1271_STATE_ON)
1535 return;
1536
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001537 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001538
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001539 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001540 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001541 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001542
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001543 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001544 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001545 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001546
Luciano Coelho08688d62010-07-08 17:50:07 +03001547 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001548 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001549 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001550 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001551 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001552 }
1553
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001554 /*
1555 * this must be before the cancel_work calls below, so that the work
1556 * functions don't perform further work.
1557 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001558 wl->state = WL1271_STATE_OFF;
1559
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001560 mutex_unlock(&wl->mutex);
1561
Ido Yariva6208652011-03-01 15:14:41 +02001562 wl1271_disable_interrupts(wl);
1563 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001564 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001565 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001566 cancel_work_sync(&wl->tx_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001567 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001568 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001569
1570 mutex_lock(&wl->mutex);
1571
1572 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001573 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001574 wl1271_power_off(wl);
1575
1576 memset(wl->bssid, 0, ETH_ALEN);
1577 memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
1578 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001579 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001580 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001581 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001582
1583 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001584 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001585 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1586 wl->tx_blocks_available = 0;
Ido Yarivd2f4d472011-03-31 10:07:00 +02001587 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001588 wl->tx_results_count = 0;
1589 wl->tx_packets_count = 0;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03001590 wl->tx_security_last_seq = 0;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02001591 wl->tx_security_seq = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001592 wl->time_offset = 0;
1593 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001594 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001595 wl->vif = NULL;
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001596 wl->filters = 0;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001597 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001598 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001599 wl->ap_fw_ps_map = 0;
1600 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001601 wl->sched_scanning = false;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03001602
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001603 /*
1604 * this is performed after the cancel_work calls and the associated
1605 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1606 * get executed before all these vars have been reset.
1607 */
1608 wl->flags = 0;
1609
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001610 for (i = 0; i < NUM_TX_QUEUES; i++)
1611 wl->tx_blocks_freed[i] = 0;
1612
1613 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001614
1615 kfree(wl->fw_status);
1616 wl->fw_status = NULL;
1617 kfree(wl->tx_res_if);
1618 wl->tx_res_if = NULL;
1619 kfree(wl->target_mem_map);
1620 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001621}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03001622
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02001623static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1624 struct ieee80211_vif *vif)
1625{
1626 struct wl1271 *wl = hw->priv;
1627
1628 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001629 /*
1630 * wl->vif can be null here if someone shuts down the interface
1631 * just when hardware recovery has been started.
1632 */
1633 if (wl->vif) {
1634 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001635 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02001636 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001637
Juuso Oikarinen67353292010-11-18 15:19:02 +02001638 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001639 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001640}
1641
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001642void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001643{
Arik Nemtsovae113b52010-10-16 18:45:07 +02001644 wl1271_set_default_filters(wl);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001645
1646 /* combine requested filters with current filter config */
1647 filters = wl->filters | filters;
1648
1649 wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
1650
1651 if (filters & FIF_PROMISC_IN_BSS) {
1652 wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
1653 wl->rx_config &= ~CFG_UNI_FILTER_EN;
1654 wl->rx_config |= CFG_BSSID_FILTER_EN;
1655 }
1656 if (filters & FIF_BCN_PRBRESP_PROMISC) {
1657 wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
1658 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1659 wl->rx_config &= ~CFG_SSID_FILTER_EN;
1660 }
1661 if (filters & FIF_OTHER_BSS) {
1662 wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
1663 wl->rx_config &= ~CFG_BSSID_FILTER_EN;
1664 }
1665 if (filters & FIF_CONTROL) {
1666 wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
1667 wl->rx_filter |= CFG_RX_CTL_EN;
1668 }
1669 if (filters & FIF_FCSFAIL) {
1670 wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
1671 wl->rx_filter |= CFG_RX_FCS_ERROR;
1672 }
1673}
1674
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001675static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001676{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02001677 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001678 /* we need to use a dummy BSSID for now */
1679 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
1680 0xad, 0xbe, 0xef };
1681
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001682 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
1683
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001684 /* pass through frames from all BSS */
1685 wl1271_configure_filters(wl, FIF_OTHER_BSS);
1686
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001687 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001688 if (ret < 0)
1689 goto out;
1690
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001691 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001692
1693out:
1694 return ret;
1695}
1696
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001697static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001698{
1699 int ret;
1700
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001701 /*
1702 * One of the side effects of the JOIN command is that is clears
1703 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
1704 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02001705 * Currently the only valid scenario for JOIN during association
1706 * is on roaming, in which case we will also be given new keys.
1707 * Keep the below message for now, unless it starts bothering
1708 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001709 */
1710 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1711 wl1271_info("JOIN while associated.");
1712
1713 if (set_assoc)
1714 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
1715
Juuso Oikarinen82429d32010-04-28 09:50:01 +03001716 ret = wl1271_cmd_join(wl, wl->set_bss_type);
1717 if (ret < 0)
1718 goto out;
1719
1720 set_bit(WL1271_FLAG_JOINED, &wl->flags);
1721
1722 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1723 goto out;
1724
1725 /*
1726 * The join command disable the keep-alive mode, shut down its process,
1727 * and also clear the template config, so we need to reset it all after
1728 * the join. The acx_aid starts the keep-alive process, and the order
1729 * of the commands below is relevant.
1730 */
1731 ret = wl1271_acx_keep_alive_mode(wl, true);
1732 if (ret < 0)
1733 goto out;
1734
1735 ret = wl1271_acx_aid(wl, wl->aid);
1736 if (ret < 0)
1737 goto out;
1738
1739 ret = wl1271_cmd_build_klv_null_data(wl);
1740 if (ret < 0)
1741 goto out;
1742
1743 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1744 ACX_KEEP_ALIVE_TPL_VALID);
1745 if (ret < 0)
1746 goto out;
1747
1748out:
1749 return ret;
1750}
1751
1752static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001753{
1754 int ret;
1755
1756 /* to stop listening to a channel, we disconnect */
1757 ret = wl1271_cmd_disconnect(wl);
1758 if (ret < 0)
1759 goto out;
1760
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001761 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001762 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001763
Ohad Ben-Cohenc5745182011-03-30 16:35:59 +02001764 /* stop filtering packets based on bssid */
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02001765 wl1271_configure_filters(wl, FIF_OTHER_BSS);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001766
1767out:
1768 return ret;
1769}
1770
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001771static void wl1271_set_band_rate(struct wl1271 *wl)
1772{
1773 if (wl->band == IEEE80211_BAND_2GHZ)
1774 wl->basic_rate_set = wl->conf.tx.basic_rate;
1775 else
1776 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
1777}
1778
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001779static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001780{
1781 int ret;
1782
1783 if (idle) {
1784 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1785 ret = wl1271_unjoin(wl);
1786 if (ret < 0)
1787 goto out;
1788 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02001789 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02001790 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001791 if (ret < 0)
1792 goto out;
1793 ret = wl1271_acx_keep_alive_config(
1794 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
1795 ACX_KEEP_ALIVE_TPL_INVALID);
1796 if (ret < 0)
1797 goto out;
1798 set_bit(WL1271_FLAG_IDLE, &wl->flags);
1799 } else {
1800 /* increment the session counter */
1801 wl->session_counter++;
1802 if (wl->session_counter >= SESSION_COUNTER_MAX)
1803 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001804
1805 /* The current firmware only supports sched_scan in idle */
1806 if (wl->sched_scanning) {
1807 wl1271_scan_sched_scan_stop(wl);
1808 ieee80211_sched_scan_stopped(wl->hw);
1809 }
1810
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001811 ret = wl1271_dummy_join(wl);
1812 if (ret < 0)
1813 goto out;
1814 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
1815 }
1816
1817out:
1818 return ret;
1819}
1820
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
1822{
1823 struct wl1271 *wl = hw->priv;
1824 struct ieee80211_conf *conf = &hw->conf;
1825 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001826 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827
1828 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
1829
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001830 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
1831 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832 channel,
1833 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02001834 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001835 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
1836 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001837
Juuso Oikarinen781608c2010-05-24 11:18:17 +03001838 /*
1839 * mac80211 will go to idle nearly immediately after transmitting some
1840 * frames, such as the deauth. To make sure those frames reach the air,
1841 * wait here until the TX queue is fully flushed.
1842 */
1843 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
1844 (conf->flags & IEEE80211_CONF_IDLE))
1845 wl1271_tx_flush(wl);
1846
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001847 mutex_lock(&wl->mutex);
1848
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001849 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02001850 /* we support configuring the channel and band while off */
1851 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
1852 wl->band = conf->channel->band;
1853 wl->channel = channel;
1854 }
1855
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001856 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02001857 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001858
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001859 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
1860
Ido Yariva6208652011-03-01 15:14:41 +02001861 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001862 if (ret < 0)
1863 goto out;
1864
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001865 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03001866 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
1867 ((wl->band != conf->channel->band) ||
1868 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001869 wl->band = conf->channel->band;
1870 wl->channel = channel;
1871
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001872 if (!is_ap) {
1873 /*
1874 * FIXME: the mac80211 should really provide a fixed
1875 * rate to use here. for now, just use the smallest
1876 * possible rate for the band as a fixed rate for
1877 * association frames and other control messages.
1878 */
1879 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1880 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001881
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001882 wl->basic_rate = wl1271_tx_min_rate_get(wl);
1883 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001884 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001885 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001886 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001887
1888 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
1889 ret = wl1271_join(wl, false);
1890 if (ret < 0)
1891 wl1271_warning("cmd join on channel "
1892 "failed %d", ret);
1893 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03001894 }
1895 }
1896
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02001897 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
1898 ret = wl1271_sta_handle_idle(wl,
1899 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03001900 if (ret < 0)
1901 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001902 }
1903
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001904 /*
1905 * if mac80211 changes the PSM mode, make sure the mode is not
1906 * incorrectly changed after the pspoll failure active window.
1907 */
1908 if (changed & IEEE80211_CONF_CHANGE_PS)
1909 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
1910
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001911 if (conf->flags & IEEE80211_CONF_PS &&
1912 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
1913 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914
1915 /*
1916 * We enter PSM only if we're already associated.
1917 * If we're not, we'll enter it when joining an SSID,
1918 * through the bss_info_changed() hook.
1919 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001920 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001921 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001922 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001923 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02001924 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001925 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001926 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02001927 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001928
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001929 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001930
Juuso Oikarinen71449f82009-12-11 15:41:07 +02001931 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02001932 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02001933 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001934 }
1935
1936 if (conf->power_level != wl->power_level) {
1937 ret = wl1271_acx_tx_power(wl, conf->power_level);
1938 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02001939 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001940
1941 wl->power_level = conf->power_level;
1942 }
1943
1944out_sleep:
1945 wl1271_ps_elp_sleep(wl);
1946
1947out:
1948 mutex_unlock(&wl->mutex);
1949
1950 return ret;
1951}
1952
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001953struct wl1271_filter_params {
1954 bool enabled;
1955 int mc_list_length;
1956 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
1957};
1958
Jiri Pirko22bedad32010-04-01 21:22:57 +00001959static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
1960 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001961{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001962 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001963 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001964 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001965
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03001966 if (unlikely(wl->state == WL1271_STATE_OFF))
1967 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001968
Juuso Oikarinen74441132009-10-13 12:47:53 +03001969 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001970 if (!fp) {
1971 wl1271_error("Out of memory setting filters.");
1972 return 0;
1973 }
1974
1975 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001976 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001977 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
1978 fp->enabled = false;
1979 } else {
1980 fp->enabled = true;
1981 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001982 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00001983 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001984 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00001985 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001986 }
1987
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001988 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03001989}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001990
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03001991#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
1992 FIF_ALLMULTI | \
1993 FIF_FCSFAIL | \
1994 FIF_BCN_PRBRESP_PROMISC | \
1995 FIF_CONTROL | \
1996 FIF_OTHER_BSS)
1997
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001998static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
1999 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002000 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002001{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002002 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002003 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002004 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002005
Arik Nemtsov7d057862010-10-16 19:25:35 +02002006 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2007 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002009 mutex_lock(&wl->mutex);
2010
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002011 *total &= WL1271_SUPPORTED_FILTERS;
2012 changed &= WL1271_SUPPORTED_FILTERS;
2013
2014 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002015 goto out;
2016
Ido Yariva6208652011-03-01 15:14:41 +02002017 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002018 if (ret < 0)
2019 goto out;
2020
Arik Nemtsov7d057862010-10-16 19:25:35 +02002021 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2022 if (*total & FIF_ALLMULTI)
2023 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2024 else if (fp)
2025 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2026 fp->mc_list,
2027 fp->mc_list_length);
2028 if (ret < 0)
2029 goto out_sleep;
2030 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002032 /* determine, whether supported filter values have changed */
2033 if (changed == 0)
2034 goto out_sleep;
2035
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002036 /* configure filters */
2037 wl->filters = *total;
2038 wl1271_configure_filters(wl, 0);
2039
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002040 /* apply configured filters */
2041 ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
2042 if (ret < 0)
2043 goto out_sleep;
2044
2045out_sleep:
2046 wl1271_ps_elp_sleep(wl);
2047
2048out:
2049 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002050 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002051}
2052
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002053static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2054 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2055 u16 tx_seq_16)
2056{
2057 struct wl1271_ap_key *ap_key;
2058 int i;
2059
2060 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2061
2062 if (key_size > MAX_KEY_SIZE)
2063 return -EINVAL;
2064
2065 /*
2066 * Find next free entry in ap_keys. Also check we are not replacing
2067 * an existing key.
2068 */
2069 for (i = 0; i < MAX_NUM_KEYS; i++) {
2070 if (wl->recorded_ap_keys[i] == NULL)
2071 break;
2072
2073 if (wl->recorded_ap_keys[i]->id == id) {
2074 wl1271_warning("trying to record key replacement");
2075 return -EINVAL;
2076 }
2077 }
2078
2079 if (i == MAX_NUM_KEYS)
2080 return -EBUSY;
2081
2082 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2083 if (!ap_key)
2084 return -ENOMEM;
2085
2086 ap_key->id = id;
2087 ap_key->key_type = key_type;
2088 ap_key->key_size = key_size;
2089 memcpy(ap_key->key, key, key_size);
2090 ap_key->hlid = hlid;
2091 ap_key->tx_seq_32 = tx_seq_32;
2092 ap_key->tx_seq_16 = tx_seq_16;
2093
2094 wl->recorded_ap_keys[i] = ap_key;
2095 return 0;
2096}
2097
2098static void wl1271_free_ap_keys(struct wl1271 *wl)
2099{
2100 int i;
2101
2102 for (i = 0; i < MAX_NUM_KEYS; i++) {
2103 kfree(wl->recorded_ap_keys[i]);
2104 wl->recorded_ap_keys[i] = NULL;
2105 }
2106}
2107
2108static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2109{
2110 int i, ret = 0;
2111 struct wl1271_ap_key *key;
2112 bool wep_key_added = false;
2113
2114 for (i = 0; i < MAX_NUM_KEYS; i++) {
2115 if (wl->recorded_ap_keys[i] == NULL)
2116 break;
2117
2118 key = wl->recorded_ap_keys[i];
2119 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2120 key->id, key->key_type,
2121 key->key_size, key->key,
2122 key->hlid, key->tx_seq_32,
2123 key->tx_seq_16);
2124 if (ret < 0)
2125 goto out;
2126
2127 if (key->key_type == KEY_WEP)
2128 wep_key_added = true;
2129 }
2130
2131 if (wep_key_added) {
2132 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2133 if (ret < 0)
2134 goto out;
2135 }
2136
2137out:
2138 wl1271_free_ap_keys(wl);
2139 return ret;
2140}
2141
2142static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2143 u8 key_size, const u8 *key, u32 tx_seq_32,
2144 u16 tx_seq_16, struct ieee80211_sta *sta)
2145{
2146 int ret;
2147 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2148
2149 if (is_ap) {
2150 struct wl1271_station *wl_sta;
2151 u8 hlid;
2152
2153 if (sta) {
2154 wl_sta = (struct wl1271_station *)sta->drv_priv;
2155 hlid = wl_sta->hlid;
2156 } else {
2157 hlid = WL1271_AP_BROADCAST_HLID;
2158 }
2159
2160 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2161 /*
2162 * We do not support removing keys after AP shutdown.
2163 * Pretend we do to make mac80211 happy.
2164 */
2165 if (action != KEY_ADD_OR_REPLACE)
2166 return 0;
2167
2168 ret = wl1271_record_ap_key(wl, id,
2169 key_type, key_size,
2170 key, hlid, tx_seq_32,
2171 tx_seq_16);
2172 } else {
2173 ret = wl1271_cmd_set_ap_key(wl, action,
2174 id, key_type, key_size,
2175 key, hlid, tx_seq_32,
2176 tx_seq_16);
2177 }
2178
2179 if (ret < 0)
2180 return ret;
2181 } else {
2182 const u8 *addr;
2183 static const u8 bcast_addr[ETH_ALEN] = {
2184 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2185 };
2186
2187 addr = sta ? sta->addr : bcast_addr;
2188
2189 if (is_zero_ether_addr(addr)) {
2190 /* We dont support TX only encryption */
2191 return -EOPNOTSUPP;
2192 }
2193
2194 /* The wl1271 does not allow to remove unicast keys - they
2195 will be cleared automatically on next CMD_JOIN. Ignore the
2196 request silently, as we dont want the mac80211 to emit
2197 an error message. */
2198 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2199 return 0;
2200
2201 ret = wl1271_cmd_set_sta_key(wl, action,
2202 id, key_type, key_size,
2203 key, addr, tx_seq_32,
2204 tx_seq_16);
2205 if (ret < 0)
2206 return ret;
2207
2208 /* the default WEP key needs to be configured at least once */
2209 if (key_type == KEY_WEP) {
2210 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2211 wl->default_key);
2212 if (ret < 0)
2213 return ret;
2214 }
2215 }
2216
2217 return 0;
2218}
2219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002220static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2221 struct ieee80211_vif *vif,
2222 struct ieee80211_sta *sta,
2223 struct ieee80211_key_conf *key_conf)
2224{
2225 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002226 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002227 u32 tx_seq_32 = 0;
2228 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002229 u8 key_type;
2230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002231 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2232
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002233 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002234 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002235 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236 key_conf->keylen, key_conf->flags);
2237 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002239 mutex_lock(&wl->mutex);
2240
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002241 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2242 ret = -EAGAIN;
2243 goto out_unlock;
2244 }
2245
Ido Yariva6208652011-03-01 15:14:41 +02002246 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002247 if (ret < 0)
2248 goto out_unlock;
2249
Johannes Berg97359d12010-08-10 09:46:38 +02002250 switch (key_conf->cipher) {
2251 case WLAN_CIPHER_SUITE_WEP40:
2252 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002253 key_type = KEY_WEP;
2254
2255 key_conf->hw_key_idx = key_conf->keyidx;
2256 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002257 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258 key_type = KEY_TKIP;
2259
2260 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002261 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2262 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002263 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002264 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002265 key_type = KEY_AES;
2266
2267 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002268 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2269 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002271 case WL1271_CIPHER_SUITE_GEM:
2272 key_type = KEY_GEM;
2273 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2274 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2275 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002276 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002277 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002278
2279 ret = -EOPNOTSUPP;
2280 goto out_sleep;
2281 }
2282
2283 switch (cmd) {
2284 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002285 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2286 key_conf->keyidx, key_type,
2287 key_conf->keylen, key_conf->key,
2288 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002289 if (ret < 0) {
2290 wl1271_error("Could not add or replace key");
2291 goto out_sleep;
2292 }
2293 break;
2294
2295 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002296 ret = wl1271_set_key(wl, KEY_REMOVE,
2297 key_conf->keyidx, key_type,
2298 key_conf->keylen, key_conf->key,
2299 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002300 if (ret < 0) {
2301 wl1271_error("Could not remove key");
2302 goto out_sleep;
2303 }
2304 break;
2305
2306 default:
2307 wl1271_error("Unsupported key cmd 0x%x", cmd);
2308 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002309 break;
2310 }
2311
2312out_sleep:
2313 wl1271_ps_elp_sleep(wl);
2314
2315out_unlock:
2316 mutex_unlock(&wl->mutex);
2317
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002318 return ret;
2319}
2320
2321static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002322 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002323 struct cfg80211_scan_request *req)
2324{
2325 struct wl1271 *wl = hw->priv;
2326 int ret;
2327 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002328 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002329
2330 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2331
2332 if (req->n_ssids) {
2333 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002334 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002335 }
2336
2337 mutex_lock(&wl->mutex);
2338
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002339 if (wl->state == WL1271_STATE_OFF) {
2340 /*
2341 * We cannot return -EBUSY here because cfg80211 will expect
2342 * a call to ieee80211_scan_completed if we do - in this case
2343 * there won't be any call.
2344 */
2345 ret = -EAGAIN;
2346 goto out;
2347 }
2348
Ido Yariva6208652011-03-01 15:14:41 +02002349 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350 if (ret < 0)
2351 goto out;
2352
Luciano Coelho5924f892010-08-04 03:46:22 +03002353 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002354
2355 wl1271_ps_elp_sleep(wl);
2356
2357out:
2358 mutex_unlock(&wl->mutex);
2359
2360 return ret;
2361}
2362
Luciano Coelho33c2c062011-05-10 14:46:02 +03002363static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2364 struct ieee80211_vif *vif,
2365 struct cfg80211_sched_scan_request *req,
2366 struct ieee80211_sched_scan_ies *ies)
2367{
2368 struct wl1271 *wl = hw->priv;
2369 int ret;
2370
2371 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2372
2373 mutex_lock(&wl->mutex);
2374
2375 ret = wl1271_ps_elp_wakeup(wl);
2376 if (ret < 0)
2377 goto out;
2378
2379 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2380 if (ret < 0)
2381 goto out_sleep;
2382
2383 ret = wl1271_scan_sched_scan_start(wl);
2384 if (ret < 0)
2385 goto out_sleep;
2386
2387 wl->sched_scanning = true;
2388
2389out_sleep:
2390 wl1271_ps_elp_sleep(wl);
2391out:
2392 mutex_unlock(&wl->mutex);
2393 return ret;
2394}
2395
2396static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2397 struct ieee80211_vif *vif)
2398{
2399 struct wl1271 *wl = hw->priv;
2400 int ret;
2401
2402 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2403
2404 mutex_lock(&wl->mutex);
2405
2406 ret = wl1271_ps_elp_wakeup(wl);
2407 if (ret < 0)
2408 goto out;
2409
2410 wl1271_scan_sched_scan_stop(wl);
2411
2412 wl1271_ps_elp_sleep(wl);
2413out:
2414 mutex_unlock(&wl->mutex);
2415}
2416
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002417static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2418{
2419 struct wl1271 *wl = hw->priv;
2420 int ret = 0;
2421
2422 mutex_lock(&wl->mutex);
2423
2424 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2425 ret = -EAGAIN;
2426 goto out;
2427 }
2428
Ido Yariva6208652011-03-01 15:14:41 +02002429 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002430 if (ret < 0)
2431 goto out;
2432
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002433 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002434 if (ret < 0)
2435 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2436
2437 wl1271_ps_elp_sleep(wl);
2438
2439out:
2440 mutex_unlock(&wl->mutex);
2441
2442 return ret;
2443}
2444
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002445static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2446{
2447 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002448 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002449
2450 mutex_lock(&wl->mutex);
2451
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002452 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2453 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002454 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002455 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002456
Ido Yariva6208652011-03-01 15:14:41 +02002457 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002458 if (ret < 0)
2459 goto out;
2460
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002461 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002462 if (ret < 0)
2463 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2464
2465 wl1271_ps_elp_sleep(wl);
2466
2467out:
2468 mutex_unlock(&wl->mutex);
2469
2470 return ret;
2471}
2472
Arik Nemtsove78a2872010-10-16 19:07:21 +02002473static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002474 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002475{
Eliad Peller889cb362011-05-01 09:56:45 +03002476 u8 ssid_len;
2477 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2478 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002479
Eliad Peller889cb362011-05-01 09:56:45 +03002480 if (!ptr) {
2481 wl1271_error("No SSID in IEs!");
2482 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002483 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002484
Eliad Peller889cb362011-05-01 09:56:45 +03002485 ssid_len = ptr[1];
2486 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2487 wl1271_error("SSID is too long!");
2488 return -EINVAL;
2489 }
2490
2491 wl->ssid_len = ssid_len;
2492 memcpy(wl->ssid, ptr+2, ssid_len);
2493 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002494}
2495
Arik Nemtsove78a2872010-10-16 19:07:21 +02002496static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2497 struct ieee80211_bss_conf *bss_conf,
2498 u32 changed)
2499{
2500 int ret = 0;
2501
2502 if (changed & BSS_CHANGED_ERP_SLOT) {
2503 if (bss_conf->use_short_slot)
2504 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2505 else
2506 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2507 if (ret < 0) {
2508 wl1271_warning("Set slot time failed %d", ret);
2509 goto out;
2510 }
2511 }
2512
2513 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2514 if (bss_conf->use_short_preamble)
2515 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2516 else
2517 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2518 }
2519
2520 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2521 if (bss_conf->use_cts_prot)
2522 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2523 else
2524 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2525 if (ret < 0) {
2526 wl1271_warning("Set ctsprotect failed %d", ret);
2527 goto out;
2528 }
2529 }
2530
2531out:
2532 return ret;
2533}
2534
2535static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2536 struct ieee80211_vif *vif,
2537 struct ieee80211_bss_conf *bss_conf,
2538 u32 changed)
2539{
2540 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2541 int ret = 0;
2542
2543 if ((changed & BSS_CHANGED_BEACON_INT)) {
2544 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2545 bss_conf->beacon_int);
2546
2547 wl->beacon_int = bss_conf->beacon_int;
2548 }
2549
2550 if ((changed & BSS_CHANGED_BEACON)) {
2551 struct ieee80211_hdr *hdr;
2552 int ieoffset = offsetof(struct ieee80211_mgmt,
2553 u.beacon.variable);
2554 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2555 u16 tmpl_id;
2556
2557 if (!beacon)
2558 goto out;
2559
2560 wl1271_debug(DEBUG_MASTER, "beacon updated");
2561
2562 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2563 if (ret < 0) {
2564 dev_kfree_skb(beacon);
2565 goto out;
2566 }
2567 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2568 CMD_TEMPL_BEACON;
2569 ret = wl1271_cmd_template_set(wl, tmpl_id,
2570 beacon->data,
2571 beacon->len, 0,
2572 wl1271_tx_min_rate_get(wl));
2573 if (ret < 0) {
2574 dev_kfree_skb(beacon);
2575 goto out;
2576 }
2577
2578 hdr = (struct ieee80211_hdr *) beacon->data;
2579 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2580 IEEE80211_STYPE_PROBE_RESP);
2581
2582 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2583 CMD_TEMPL_PROBE_RESPONSE;
2584 ret = wl1271_cmd_template_set(wl,
2585 tmpl_id,
2586 beacon->data,
2587 beacon->len, 0,
2588 wl1271_tx_min_rate_get(wl));
2589 dev_kfree_skb(beacon);
2590 if (ret < 0)
2591 goto out;
2592 }
2593
2594out:
2595 return ret;
2596}
2597
2598/* AP mode changes */
2599static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002600 struct ieee80211_vif *vif,
2601 struct ieee80211_bss_conf *bss_conf,
2602 u32 changed)
2603{
Arik Nemtsove78a2872010-10-16 19:07:21 +02002604 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605
Arik Nemtsove78a2872010-10-16 19:07:21 +02002606 if ((changed & BSS_CHANGED_BASIC_RATES)) {
2607 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002608
Arik Nemtsove78a2872010-10-16 19:07:21 +02002609 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
2610 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002611
Arik Nemtsov70f47422011-04-18 14:15:25 +03002612 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002613 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03002614 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002615 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002616 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03002617
2618 ret = wl1271_ap_init_templates(wl);
2619 if (ret < 0)
2620 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002621 }
2622
Arik Nemtsove78a2872010-10-16 19:07:21 +02002623 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
2624 if (ret < 0)
2625 goto out;
2626
2627 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
2628 if (bss_conf->enable_beacon) {
2629 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2630 ret = wl1271_cmd_start_bss(wl);
2631 if (ret < 0)
2632 goto out;
2633
2634 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2635 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002636
2637 ret = wl1271_ap_init_hwenc(wl);
2638 if (ret < 0)
2639 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002640 }
2641 } else {
2642 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2643 ret = wl1271_cmd_stop_bss(wl);
2644 if (ret < 0)
2645 goto out;
2646
2647 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
2648 wl1271_debug(DEBUG_AP, "stopped AP");
2649 }
2650 }
2651 }
2652
Eliad Pellercb5ae052011-04-07 15:52:05 +03002653 if (changed & BSS_CHANGED_IBSS) {
2654 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
2655 bss_conf->ibss_joined);
2656
2657 if (bss_conf->ibss_joined) {
2658 u32 rates = bss_conf->basic_rates;
2659 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2660 rates);
2661 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2662
2663 /* by default, use 11b rates */
2664 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
2665 ret = wl1271_acx_sta_rate_policies(wl);
2666 if (ret < 0)
2667 goto out;
2668 }
2669 }
2670
Arik Nemtsove78a2872010-10-16 19:07:21 +02002671 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2672 if (ret < 0)
2673 goto out;
2674out:
2675 return;
2676}
2677
2678/* STA/IBSS mode changes */
2679static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
2680 struct ieee80211_vif *vif,
2681 struct ieee80211_bss_conf *bss_conf,
2682 u32 changed)
2683{
2684 bool do_join = false, set_assoc = false;
2685 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002686 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002687 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01002688 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02002689 bool sta_exists = false;
2690 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02002691
2692 if (is_ibss) {
2693 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
2694 changed);
2695 if (ret < 0)
2696 goto out;
2697 }
2698
2699 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
2700 do_join = true;
2701
2702 /* Need to update the SSID (for filtering etc) */
2703 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
2704 do_join = true;
2705
2706 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002707 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
2708 bss_conf->enable_beacon ? "enabled" : "disabled");
2709
2710 if (bss_conf->enable_beacon)
2711 wl->set_bss_type = BSS_TYPE_IBSS;
2712 else
2713 wl->set_bss_type = BSS_TYPE_STA_BSS;
2714 do_join = true;
2715 }
2716
Arik Nemtsove78a2872010-10-16 19:07:21 +02002717 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03002718 bool enable = false;
2719 if (bss_conf->cqm_rssi_thold)
2720 enable = true;
2721 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
2722 bss_conf->cqm_rssi_thold,
2723 bss_conf->cqm_rssi_hyst);
2724 if (ret < 0)
2725 goto out;
2726 wl->rssi_thold = bss_conf->cqm_rssi_thold;
2727 }
2728
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002729 if ((changed & BSS_CHANGED_BSSID) &&
2730 /*
2731 * Now we know the correct bssid, so we send a new join command
2732 * and enable the BSSID filter
2733 */
2734 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002735 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02002736
Eliad Pellerfa287b82010-12-26 09:27:50 +01002737 if (!is_zero_ether_addr(wl->bssid)) {
2738 ret = wl1271_cmd_build_null_data(wl);
2739 if (ret < 0)
2740 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002741
Eliad Pellerfa287b82010-12-26 09:27:50 +01002742 ret = wl1271_build_qos_null_data(wl);
2743 if (ret < 0)
2744 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03002745
Eliad Pellerfa287b82010-12-26 09:27:50 +01002746 /* filter out all packets not from this BSSID */
2747 wl1271_configure_filters(wl, 0);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002748
Eliad Pellerfa287b82010-12-26 09:27:50 +01002749 /* Need to update the BSSID (for filtering etc) */
2750 do_join = true;
2751 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002752 }
2753
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002754 rcu_read_lock();
2755 sta = ieee80211_find_sta(vif, bss_conf->bssid);
2756 if (sta) {
2757 /* save the supp_rates of the ap */
2758 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
2759 if (sta->ht_cap.ht_supported)
2760 sta_rate_set |=
2761 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02002762 sta_ht_cap = sta->ht_cap;
2763 sta_exists = true;
2764 }
2765 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002766
Arik Nemtsova1008852011-02-12 23:24:20 +02002767 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002768 /* handle new association with HT and HT information change */
2769 if ((changed & BSS_CHANGED_HT) &&
2770 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002771 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002772 true);
2773 if (ret < 0) {
2774 wl1271_warning("Set ht cap true failed %d",
2775 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002776 goto out;
2777 }
2778 ret = wl1271_acx_set_ht_information(wl,
2779 bss_conf->ht_operation_mode);
2780 if (ret < 0) {
2781 wl1271_warning("Set ht information failed %d",
2782 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002783 goto out;
2784 }
2785 }
2786 /* handle new association without HT and disassociation */
2787 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02002788 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002789 false);
2790 if (ret < 0) {
2791 wl1271_warning("Set ht cap false failed %d",
2792 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002793 goto out;
2794 }
2795 }
2796 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002797
Arik Nemtsove78a2872010-10-16 19:07:21 +02002798 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002799 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002800 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002801 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002803 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002804
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002805 wl->ps_poll_failures = 0;
2806
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002807 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002808 * use basic rates from AP, and determine lowest rate
2809 * to use with control frames.
2810 */
2811 rates = bss_conf->basic_rates;
2812 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
2813 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002814 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02002815 if (sta_rate_set)
2816 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
2817 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002818 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002819 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002820 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002821
2822 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03002823 * with wl1271, we don't need to update the
2824 * beacon_int and dtim_period, because the firmware
2825 * updates it by itself when the first beacon is
2826 * received after a join.
2827 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002828 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
2829 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002830 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002831
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002832 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002833 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002834 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002835 dev_kfree_skb(wl->probereq);
2836 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
2837 ieoffset = offsetof(struct ieee80211_mgmt,
2838 u.probe_req.variable);
2839 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02002840
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002841 /* enable the connection monitoring feature */
2842 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002843 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002844 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002845
2846 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002847 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
2848 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02002849 enum wl1271_cmd_ps_mode mode;
2850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002851 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002852 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002853 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03002854 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002855 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002856 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002857 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002858 } else {
2859 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03002860 bool was_assoc =
2861 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
2862 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03002863 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03002864 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002865
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002866 /* free probe-request template */
2867 dev_kfree_skb(wl->probereq);
2868 wl->probereq = NULL;
2869
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002870 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03002871 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002872
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002873 /* revert back to minimum rates for the current band */
2874 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002875 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002876 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002877 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002878 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002879
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002880 /* disable connection monitor features */
2881 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002882
2883 /* Disable the keep-alive feature */
2884 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02002885 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002886 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02002887
2888 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03002889 if (was_assoc) {
2890 wl1271_unjoin(wl);
2891 wl1271_dummy_join(wl);
2892 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002893 }
2894 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002895
Arik Nemtsove78a2872010-10-16 19:07:21 +02002896 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
2897 if (ret < 0)
2898 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002899
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002900 if (changed & BSS_CHANGED_ARP_FILTER) {
2901 __be32 addr = bss_conf->arp_addr_list[0];
2902 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
2903
Eliad Pellerc5312772010-12-09 11:31:27 +02002904 if (bss_conf->arp_addr_cnt == 1 &&
2905 bss_conf->arp_filter_enabled) {
2906 /*
2907 * The template should have been configured only upon
2908 * association. however, it seems that the correct ip
2909 * isn't being set (when sending), so we have to
2910 * reconfigure the template upon every ip change.
2911 */
2912 ret = wl1271_cmd_build_arp_rsp(wl, addr);
2913 if (ret < 0) {
2914 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002915 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02002916 }
2917
2918 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01002919 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02002920 addr);
2921 } else
2922 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002923
2924 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02002925 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03002926 }
2927
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002928 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002929 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002930 if (ret < 0) {
2931 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002932 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02002933 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02002934 }
2935
Arik Nemtsove78a2872010-10-16 19:07:21 +02002936out:
2937 return;
2938}
2939
2940static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
2941 struct ieee80211_vif *vif,
2942 struct ieee80211_bss_conf *bss_conf,
2943 u32 changed)
2944{
2945 struct wl1271 *wl = hw->priv;
2946 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2947 int ret;
2948
2949 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
2950 (int)changed);
2951
2952 mutex_lock(&wl->mutex);
2953
2954 if (unlikely(wl->state == WL1271_STATE_OFF))
2955 goto out;
2956
Ido Yariva6208652011-03-01 15:14:41 +02002957 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02002958 if (ret < 0)
2959 goto out;
2960
2961 if (is_ap)
2962 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
2963 else
2964 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
2965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002966 wl1271_ps_elp_sleep(wl);
2967
2968out:
2969 mutex_unlock(&wl->mutex);
2970}
2971
Kalle Valoc6999d82010-02-18 13:25:41 +02002972static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
2973 const struct ieee80211_tx_queue_params *params)
2974{
2975 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02002976 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02002977 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02002978
2979 mutex_lock(&wl->mutex);
2980
2981 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
2982
Kalle Valo4695dc92010-03-18 12:26:38 +02002983 if (params->uapsd)
2984 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
2985 else
2986 ps_scheme = CONF_PS_SCHEME_LEGACY;
2987
Arik Nemtsov488fc542010-10-16 20:33:45 +02002988 if (wl->state == WL1271_STATE_OFF) {
2989 /*
2990 * If the state is off, the parameters will be recorded and
2991 * configured on init. This happens in AP-mode.
2992 */
2993 struct conf_tx_ac_category *conf_ac =
2994 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
2995 struct conf_tx_tid *conf_tid =
2996 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
2997
2998 conf_ac->ac = wl1271_tx_get_queue(queue);
2999 conf_ac->cw_min = (u8)params->cw_min;
3000 conf_ac->cw_max = params->cw_max;
3001 conf_ac->aifsn = params->aifs;
3002 conf_ac->tx_op_limit = params->txop << 5;
3003
3004 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3005 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3006 conf_tid->tsid = wl1271_tx_get_queue(queue);
3007 conf_tid->ps_scheme = ps_scheme;
3008 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3009 conf_tid->apsd_conf[0] = 0;
3010 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003011 goto out;
3012 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003013
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003014 ret = wl1271_ps_elp_wakeup(wl);
3015 if (ret < 0)
3016 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003017
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003018 /*
3019 * the txop is confed in units of 32us by the mac80211,
3020 * we need us
3021 */
3022 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3023 params->cw_min, params->cw_max,
3024 params->aifs, params->txop << 5);
3025 if (ret < 0)
3026 goto out_sleep;
3027
3028 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3029 CONF_CHANNEL_TYPE_EDCF,
3030 wl1271_tx_get_queue(queue),
3031 ps_scheme, CONF_ACK_POLICY_LEGACY,
3032 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003033
3034out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003035 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003036
3037out:
3038 mutex_unlock(&wl->mutex);
3039
3040 return ret;
3041}
3042
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003043static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3044{
3045
3046 struct wl1271 *wl = hw->priv;
3047 u64 mactime = ULLONG_MAX;
3048 int ret;
3049
3050 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3051
3052 mutex_lock(&wl->mutex);
3053
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003054 if (unlikely(wl->state == WL1271_STATE_OFF))
3055 goto out;
3056
Ido Yariva6208652011-03-01 15:14:41 +02003057 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003058 if (ret < 0)
3059 goto out;
3060
3061 ret = wl1271_acx_tsf_info(wl, &mactime);
3062 if (ret < 0)
3063 goto out_sleep;
3064
3065out_sleep:
3066 wl1271_ps_elp_sleep(wl);
3067
3068out:
3069 mutex_unlock(&wl->mutex);
3070 return mactime;
3071}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072
John W. Linvilleece550d2010-07-28 16:41:06 -04003073static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3074 struct survey_info *survey)
3075{
3076 struct wl1271 *wl = hw->priv;
3077 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003078
John W. Linvilleece550d2010-07-28 16:41:06 -04003079 if (idx != 0)
3080 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003081
John W. Linvilleece550d2010-07-28 16:41:06 -04003082 survey->channel = conf->channel;
3083 survey->filled = SURVEY_INFO_NOISE_DBM;
3084 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003085
John W. Linvilleece550d2010-07-28 16:41:06 -04003086 return 0;
3087}
3088
Arik Nemtsov409622e2011-02-23 00:22:29 +02003089static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003090 struct ieee80211_sta *sta,
3091 u8 *hlid)
3092{
3093 struct wl1271_station *wl_sta;
3094 int id;
3095
3096 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3097 if (id >= AP_MAX_STATIONS) {
3098 wl1271_warning("could not allocate HLID - too much stations");
3099 return -EBUSY;
3100 }
3101
3102 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003103 __set_bit(id, wl->ap_hlid_map);
3104 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3105 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003106 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003107 return 0;
3108}
3109
Arik Nemtsov409622e2011-02-23 00:22:29 +02003110static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003111{
3112 int id = hlid - WL1271_AP_STA_HLID_START;
3113
Arik Nemtsov409622e2011-02-23 00:22:29 +02003114 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3115 return;
3116
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003117 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003118 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003119 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003120 __clear_bit(hlid, &wl->ap_ps_map);
3121 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003122}
3123
3124static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3125 struct ieee80211_vif *vif,
3126 struct ieee80211_sta *sta)
3127{
3128 struct wl1271 *wl = hw->priv;
3129 int ret = 0;
3130 u8 hlid;
3131
3132 mutex_lock(&wl->mutex);
3133
3134 if (unlikely(wl->state == WL1271_STATE_OFF))
3135 goto out;
3136
3137 if (wl->bss_type != BSS_TYPE_AP_BSS)
3138 goto out;
3139
3140 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3141
Arik Nemtsov409622e2011-02-23 00:22:29 +02003142 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003143 if (ret < 0)
3144 goto out;
3145
Ido Yariva6208652011-03-01 15:14:41 +02003146 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003147 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003148 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003149
3150 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3151 if (ret < 0)
3152 goto out_sleep;
3153
3154out_sleep:
3155 wl1271_ps_elp_sleep(wl);
3156
Arik Nemtsov409622e2011-02-23 00:22:29 +02003157out_free_sta:
3158 if (ret < 0)
3159 wl1271_free_sta(wl, hlid);
3160
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003161out:
3162 mutex_unlock(&wl->mutex);
3163 return ret;
3164}
3165
3166static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3167 struct ieee80211_vif *vif,
3168 struct ieee80211_sta *sta)
3169{
3170 struct wl1271 *wl = hw->priv;
3171 struct wl1271_station *wl_sta;
3172 int ret = 0, id;
3173
3174 mutex_lock(&wl->mutex);
3175
3176 if (unlikely(wl->state == WL1271_STATE_OFF))
3177 goto out;
3178
3179 if (wl->bss_type != BSS_TYPE_AP_BSS)
3180 goto out;
3181
3182 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3183
3184 wl_sta = (struct wl1271_station *)sta->drv_priv;
3185 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3186 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3187 goto out;
3188
Ido Yariva6208652011-03-01 15:14:41 +02003189 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003190 if (ret < 0)
3191 goto out;
3192
3193 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3194 if (ret < 0)
3195 goto out_sleep;
3196
Arik Nemtsov409622e2011-02-23 00:22:29 +02003197 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003198
3199out_sleep:
3200 wl1271_ps_elp_sleep(wl);
3201
3202out:
3203 mutex_unlock(&wl->mutex);
3204 return ret;
3205}
3206
Luciano Coelho4623ec72011-03-21 19:26:41 +02003207static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3208 struct ieee80211_vif *vif,
3209 enum ieee80211_ampdu_mlme_action action,
3210 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3211 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003212{
3213 struct wl1271 *wl = hw->priv;
3214 int ret;
3215
3216 mutex_lock(&wl->mutex);
3217
3218 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3219 ret = -EAGAIN;
3220 goto out;
3221 }
3222
Ido Yariva6208652011-03-01 15:14:41 +02003223 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003224 if (ret < 0)
3225 goto out;
3226
3227 switch (action) {
3228 case IEEE80211_AMPDU_RX_START:
3229 if (wl->ba_support) {
3230 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3231 true);
3232 if (!ret)
3233 wl->ba_rx_bitmap |= BIT(tid);
3234 } else {
3235 ret = -ENOTSUPP;
3236 }
3237 break;
3238
3239 case IEEE80211_AMPDU_RX_STOP:
3240 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3241 if (!ret)
3242 wl->ba_rx_bitmap &= ~BIT(tid);
3243 break;
3244
3245 /*
3246 * The BA initiator session management in FW independently.
3247 * Falling break here on purpose for all TX APDU commands.
3248 */
3249 case IEEE80211_AMPDU_TX_START:
3250 case IEEE80211_AMPDU_TX_STOP:
3251 case IEEE80211_AMPDU_TX_OPERATIONAL:
3252 ret = -EINVAL;
3253 break;
3254
3255 default:
3256 wl1271_error("Incorrect ampdu action id=%x\n", action);
3257 ret = -EINVAL;
3258 }
3259
3260 wl1271_ps_elp_sleep(wl);
3261
3262out:
3263 mutex_unlock(&wl->mutex);
3264
3265 return ret;
3266}
3267
Arik Nemtsov33437892011-04-26 23:35:39 +03003268static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3269{
3270 struct wl1271 *wl = hw->priv;
3271 bool ret = false;
3272
3273 mutex_lock(&wl->mutex);
3274
3275 if (unlikely(wl->state == WL1271_STATE_OFF))
3276 goto out;
3277
3278 /* packets are considered pending if in the TX queue or the FW */
3279 ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
3280
3281 /* the above is appropriate for STA mode for PS purposes */
3282 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3283
3284out:
3285 mutex_unlock(&wl->mutex);
3286
3287 return ret;
3288}
3289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003290/* can't be const, mac80211 writes to this */
3291static struct ieee80211_rate wl1271_rates[] = {
3292 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003293 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3294 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003295 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003296 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3297 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003298 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3299 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003300 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3301 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3303 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003304 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3305 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3307 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003308 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3309 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003310 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003311 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3312 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003313 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003314 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3315 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003317 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3318 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003319 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003320 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3321 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003322 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003323 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3324 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003325 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003326 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3327 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003329 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3330 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003331};
3332
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003333/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003334static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003335 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003336 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003337 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3338 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3339 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003340 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003341 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3342 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3343 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003344 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003345 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3346 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3347 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003348 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003349};
3350
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003351/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003352static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003353 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003354 7, /* CONF_HW_RXTX_RATE_MCS7 */
3355 6, /* CONF_HW_RXTX_RATE_MCS6 */
3356 5, /* CONF_HW_RXTX_RATE_MCS5 */
3357 4, /* CONF_HW_RXTX_RATE_MCS4 */
3358 3, /* CONF_HW_RXTX_RATE_MCS3 */
3359 2, /* CONF_HW_RXTX_RATE_MCS2 */
3360 1, /* CONF_HW_RXTX_RATE_MCS1 */
3361 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003362
3363 11, /* CONF_HW_RXTX_RATE_54 */
3364 10, /* CONF_HW_RXTX_RATE_48 */
3365 9, /* CONF_HW_RXTX_RATE_36 */
3366 8, /* CONF_HW_RXTX_RATE_24 */
3367
3368 /* TI-specific rate */
3369 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3370
3371 7, /* CONF_HW_RXTX_RATE_18 */
3372 6, /* CONF_HW_RXTX_RATE_12 */
3373 3, /* CONF_HW_RXTX_RATE_11 */
3374 5, /* CONF_HW_RXTX_RATE_9 */
3375 4, /* CONF_HW_RXTX_RATE_6 */
3376 2, /* CONF_HW_RXTX_RATE_5_5 */
3377 1, /* CONF_HW_RXTX_RATE_2 */
3378 0 /* CONF_HW_RXTX_RATE_1 */
3379};
3380
Shahar Levie8b03a22010-10-13 16:09:39 +02003381/* 11n STA capabilities */
3382#define HW_RX_HIGHEST_RATE 72
3383
Shahar Levi00d20102010-11-08 11:20:10 +00003384#ifdef CONFIG_WL12XX_HT
3385#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003386 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3387 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003388 .ht_supported = true, \
3389 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3390 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3391 .mcs = { \
3392 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3393 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3394 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3395 }, \
3396}
Shahar Levi18357852010-10-13 16:09:41 +02003397#else
Shahar Levi00d20102010-11-08 11:20:10 +00003398#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003399 .ht_supported = false, \
3400}
3401#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003402
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003403/* can't be const, mac80211 writes to this */
3404static struct ieee80211_supported_band wl1271_band_2ghz = {
3405 .channels = wl1271_channels,
3406 .n_channels = ARRAY_SIZE(wl1271_channels),
3407 .bitrates = wl1271_rates,
3408 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003409 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003410};
3411
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003412/* 5 GHz data rates for WL1273 */
3413static struct ieee80211_rate wl1271_rates_5ghz[] = {
3414 { .bitrate = 60,
3415 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3416 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3417 { .bitrate = 90,
3418 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3419 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3420 { .bitrate = 120,
3421 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3422 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3423 { .bitrate = 180,
3424 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3425 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3426 { .bitrate = 240,
3427 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3428 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3429 { .bitrate = 360,
3430 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3431 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3432 { .bitrate = 480,
3433 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3434 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3435 { .bitrate = 540,
3436 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3437 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3438};
3439
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003440/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003441static struct ieee80211_channel wl1271_channels_5ghz[] = {
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003442 { .hw_value = 7, .center_freq = 5035},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003443 { .hw_value = 8, .center_freq = 5040},
3444 { .hw_value = 9, .center_freq = 5045},
3445 { .hw_value = 11, .center_freq = 5055},
3446 { .hw_value = 12, .center_freq = 5060},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003447 { .hw_value = 16, .center_freq = 5080},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003448 { .hw_value = 34, .center_freq = 5170},
3449 { .hw_value = 36, .center_freq = 5180},
3450 { .hw_value = 38, .center_freq = 5190},
3451 { .hw_value = 40, .center_freq = 5200},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003452 { .hw_value = 42, .center_freq = 5210},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003453 { .hw_value = 44, .center_freq = 5220},
3454 { .hw_value = 46, .center_freq = 5230},
3455 { .hw_value = 48, .center_freq = 5240},
3456 { .hw_value = 52, .center_freq = 5260},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003457 { .hw_value = 56, .center_freq = 5280},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003458 { .hw_value = 60, .center_freq = 5300},
3459 { .hw_value = 64, .center_freq = 5320},
3460 { .hw_value = 100, .center_freq = 5500},
3461 { .hw_value = 104, .center_freq = 5520},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003462 { .hw_value = 108, .center_freq = 5540},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003463 { .hw_value = 112, .center_freq = 5560},
3464 { .hw_value = 116, .center_freq = 5580},
3465 { .hw_value = 120, .center_freq = 5600},
3466 { .hw_value = 124, .center_freq = 5620},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003467 { .hw_value = 128, .center_freq = 5640},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003468 { .hw_value = 132, .center_freq = 5660},
3469 { .hw_value = 136, .center_freq = 5680},
3470 { .hw_value = 140, .center_freq = 5700},
3471 { .hw_value = 149, .center_freq = 5745},
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003472 { .hw_value = 153, .center_freq = 5765},
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003473 { .hw_value = 157, .center_freq = 5785},
3474 { .hw_value = 161, .center_freq = 5805},
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003475 { .hw_value = 165, .center_freq = 5825},
3476};
3477
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003478/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003479static const u8 wl1271_rate_to_idx_5ghz[] = {
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 7, /* CONF_HW_RXTX_RATE_54 */
3491 6, /* CONF_HW_RXTX_RATE_48 */
3492 5, /* CONF_HW_RXTX_RATE_36 */
3493 4, /* CONF_HW_RXTX_RATE_24 */
3494
3495 /* TI-specific rate */
3496 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3497
3498 3, /* CONF_HW_RXTX_RATE_18 */
3499 2, /* CONF_HW_RXTX_RATE_12 */
3500 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3501 1, /* CONF_HW_RXTX_RATE_9 */
3502 0, /* CONF_HW_RXTX_RATE_6 */
3503 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3504 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3505 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3506};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003507
3508static struct ieee80211_supported_band wl1271_band_5ghz = {
3509 .channels = wl1271_channels_5ghz,
3510 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3511 .bitrates = wl1271_rates_5ghz,
3512 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003513 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003514};
3515
Tobias Klausera0ea9492010-05-20 10:38:11 +02003516static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003517 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3518 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3519};
3520
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003521static const struct ieee80211_ops wl1271_ops = {
3522 .start = wl1271_op_start,
3523 .stop = wl1271_op_stop,
3524 .add_interface = wl1271_op_add_interface,
3525 .remove_interface = wl1271_op_remove_interface,
Eliad Peller402e48612011-05-13 11:57:09 +03003526 .suspend = wl1271_op_suspend,
3527 .resume = wl1271_op_resume,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003529 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003530 .configure_filter = wl1271_op_configure_filter,
3531 .tx = wl1271_op_tx,
3532 .set_key = wl1271_op_set_key,
3533 .hw_scan = wl1271_op_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003534 .sched_scan_start = wl1271_op_sched_scan_start,
3535 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003536 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003537 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003538 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003539 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003540 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003541 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003542 .sta_add = wl1271_op_sta_add,
3543 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003544 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003545 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003546 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003547};
3548
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003549
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003550u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003551{
3552 u8 idx;
3553
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003554 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003555
3556 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3557 wl1271_error("Illegal RX rate from HW: %d", rate);
3558 return 0;
3559 }
3560
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003561 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003562 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3563 wl1271_error("Unsupported RX rate from HW: %d", rate);
3564 return 0;
3565 }
3566
3567 return idx;
3568}
3569
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003570static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3571 struct device_attribute *attr,
3572 char *buf)
3573{
3574 struct wl1271 *wl = dev_get_drvdata(dev);
3575 ssize_t len;
3576
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003577 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003578
3579 mutex_lock(&wl->mutex);
3580 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3581 wl->sg_enabled);
3582 mutex_unlock(&wl->mutex);
3583
3584 return len;
3585
3586}
3587
3588static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3589 struct device_attribute *attr,
3590 const char *buf, size_t count)
3591{
3592 struct wl1271 *wl = dev_get_drvdata(dev);
3593 unsigned long res;
3594 int ret;
3595
Luciano Coelho6277ed62011-04-01 17:49:54 +03003596 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003597 if (ret < 0) {
3598 wl1271_warning("incorrect value written to bt_coex_mode");
3599 return count;
3600 }
3601
3602 mutex_lock(&wl->mutex);
3603
3604 res = !!res;
3605
3606 if (res == wl->sg_enabled)
3607 goto out;
3608
3609 wl->sg_enabled = res;
3610
3611 if (wl->state == WL1271_STATE_OFF)
3612 goto out;
3613
Ido Yariva6208652011-03-01 15:14:41 +02003614 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003615 if (ret < 0)
3616 goto out;
3617
3618 wl1271_acx_sg_enable(wl, wl->sg_enabled);
3619 wl1271_ps_elp_sleep(wl);
3620
3621 out:
3622 mutex_unlock(&wl->mutex);
3623 return count;
3624}
3625
3626static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
3627 wl1271_sysfs_show_bt_coex_state,
3628 wl1271_sysfs_store_bt_coex_state);
3629
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003630static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
3631 struct device_attribute *attr,
3632 char *buf)
3633{
3634 struct wl1271 *wl = dev_get_drvdata(dev);
3635 ssize_t len;
3636
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003637 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003638
3639 mutex_lock(&wl->mutex);
3640 if (wl->hw_pg_ver >= 0)
3641 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
3642 else
3643 len = snprintf(buf, len, "n/a\n");
3644 mutex_unlock(&wl->mutex);
3645
3646 return len;
3647}
3648
3649static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
3650 wl1271_sysfs_show_hw_pg_ver, NULL);
3651
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003652int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653{
3654 int ret;
3655
3656 if (wl->mac80211_registered)
3657 return 0;
3658
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003659 ret = wl1271_fetch_nvs(wl);
3660 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02003661 /* NOTE: The wl->nvs->nvs element must be first, in
3662 * order to simplify the casting, we assume it is at
3663 * the beginning of the wl->nvs structure.
3664 */
3665 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02003666
3667 wl->mac_addr[0] = nvs_ptr[11];
3668 wl->mac_addr[1] = nvs_ptr[10];
3669 wl->mac_addr[2] = nvs_ptr[6];
3670 wl->mac_addr[3] = nvs_ptr[5];
3671 wl->mac_addr[4] = nvs_ptr[4];
3672 wl->mac_addr[5] = nvs_ptr[3];
3673 }
3674
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003675 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
3676
3677 ret = ieee80211_register_hw(wl->hw);
3678 if (ret < 0) {
3679 wl1271_error("unable to register mac80211 hw: %d", ret);
3680 return ret;
3681 }
3682
3683 wl->mac80211_registered = true;
3684
Eliad Pellerd60080a2010-11-24 12:53:16 +02003685 wl1271_debugfs_init(wl);
3686
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003687 register_netdevice_notifier(&wl1271_dev_notifier);
3688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003689 wl1271_notice("loaded");
3690
3691 return 0;
3692}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003693EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003694
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003695void wl1271_unregister_hw(struct wl1271 *wl)
3696{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01003697 if (wl->state == WL1271_STATE_PLT)
3698 __wl1271_plt_stop(wl);
3699
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003700 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003701 ieee80211_unregister_hw(wl->hw);
3702 wl->mac80211_registered = false;
3703
3704}
3705EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
3706
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003707int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003708{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003709 static const u32 cipher_suites[] = {
3710 WLAN_CIPHER_SUITE_WEP40,
3711 WLAN_CIPHER_SUITE_WEP104,
3712 WLAN_CIPHER_SUITE_TKIP,
3713 WLAN_CIPHER_SUITE_CCMP,
3714 WL1271_CIPHER_SUITE_GEM,
3715 };
3716
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03003717 /* The tx descriptor buffer and the TKIP space. */
3718 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
3719 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003720
3721 /* unit us */
3722 /* FIXME: find a proper value */
3723 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03003724 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003725
3726 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02003727 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02003728 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02003729 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02003730 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003731 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02003732 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03003733 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03003734 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02003735 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003736
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003737 wl->hw->wiphy->cipher_suites = cipher_suites;
3738 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
3739
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003740 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02003741 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003742 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02003743 /*
3744 * Maximum length of elements in scanning probe request templates
3745 * should be the maximum length possible for a template, without
3746 * the IEEE80211 header of the template
3747 */
3748 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
3749 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003750
Luciano Coelho4a31c112011-03-21 23:16:14 +02003751 /* make sure all our channels fit in the scanned_ch bitmask */
3752 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
3753 ARRAY_SIZE(wl1271_channels_5ghz) >
3754 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01003755 /*
3756 * We keep local copies of the band structs because we need to
3757 * modify them on a per-device basis.
3758 */
3759 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
3760 sizeof(wl1271_band_2ghz));
3761 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
3762 sizeof(wl1271_band_5ghz));
3763
3764 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
3765 &wl->bands[IEEE80211_BAND_2GHZ];
3766 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
3767 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003768
Kalle Valo12bd8942010-03-18 12:26:33 +02003769 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02003770 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02003771
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01003772 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
3773
Teemu Paasikivi8197b712010-02-22 08:38:23 +02003774 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003775
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003776 wl->hw->sta_data_size = sizeof(struct wl1271_station);
3777
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01003778 wl->hw->max_rx_aggregation_subframes = 8;
3779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003780 return 0;
3781}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003782EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003783
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003784#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003785
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02003786struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003787{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003788 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003789 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003790 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003791 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003792 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003793
3794 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
3795 if (!hw) {
3796 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003797 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003798 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003799 }
3800
Julia Lawall929ebd32010-05-15 23:16:39 +02003801 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003802 if (!plat_dev) {
3803 wl1271_error("could not allocate platform_device");
3804 ret = -ENOMEM;
3805 goto err_plat_alloc;
3806 }
3807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003808 wl = hw->priv;
3809 memset(wl, 0, sizeof(*wl));
3810
Juuso Oikarinen01c09162009-10-13 12:47:55 +03003811 INIT_LIST_HEAD(&wl->list);
3812
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003813 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003814 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003815
Juuso Oikarinen6742f552010-12-13 09:52:37 +02003816 for (i = 0; i < NUM_TX_QUEUES; i++)
3817 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003818
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003819 for (i = 0; i < NUM_TX_QUEUES; i++)
3820 for (j = 0; j < AP_MAX_LINKS; j++)
3821 skb_queue_head_init(&wl->links[j].tx_queue[i]);
3822
Ido Yariva6208652011-03-01 15:14:41 +02003823 skb_queue_head_init(&wl->deferred_rx_queue);
3824 skb_queue_head_init(&wl->deferred_tx_queue);
3825
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03003826 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003827 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02003828 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02003829 INIT_WORK(&wl->tx_work, wl1271_tx_work);
3830 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
3831 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003832 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02003833 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003834 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003835 wl->rx_counter = 0;
Arik Nemtsovae113b52010-10-16 18:45:07 +02003836 wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG;
3837 wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02003838 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003839 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02003840 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003841 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003842 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003843 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03003844 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02003845 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003846 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003847 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02003848 wl->bss_type = MAX_BSS_TYPE;
3849 wl->set_bss_type = MAX_BSS_TYPE;
3850 wl->fw_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003851 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003852 wl->ap_ps_map = 0;
3853 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02003854 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02003855 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03003856 wl->sched_scanning = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003857
Ido Yariv25eeb9e2010-10-12 16:20:06 +02003858 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03003859 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003860 wl->tx_frames[i] = NULL;
3861
3862 spin_lock_init(&wl->wl_lock);
3863
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003864 wl->state = WL1271_STATE_OFF;
3865 mutex_init(&wl->mutex);
3866
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003867 /* Apply default driver configuration. */
3868 wl1271_conf_init(wl);
3869
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003870 order = get_order(WL1271_AGGR_BUFFER_SIZE);
3871 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
3872 if (!wl->aggr_buf) {
3873 ret = -ENOMEM;
3874 goto err_hw;
3875 }
3876
Ido Yariv990f5de2011-03-31 10:06:59 +02003877 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
3878 if (!wl->dummy_packet) {
3879 ret = -ENOMEM;
3880 goto err_aggr;
3881 }
3882
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003883 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003884 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003885 if (ret) {
3886 wl1271_error("couldn't register platform device");
Ido Yariv990f5de2011-03-31 10:06:59 +02003887 goto err_dummy_packet;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003888 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003889 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003890
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003891 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003892 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003893 if (ret < 0) {
3894 wl1271_error("failed to create sysfs file bt_coex_state");
3895 goto err_platform;
3896 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003897
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003898 /* Create sysfs file to get HW PG version */
3899 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
3900 if (ret < 0) {
3901 wl1271_error("failed to create sysfs file hw_pg_ver");
3902 goto err_bt_coex_state;
3903 }
3904
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003905 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003906
Juuso Oikarinend717fd62010-05-07 11:38:58 +03003907err_bt_coex_state:
3908 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
3909
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003910err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003911 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003912
Ido Yariv990f5de2011-03-31 10:06:59 +02003913err_dummy_packet:
3914 dev_kfree_skb(wl->dummy_packet);
3915
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003916err_aggr:
3917 free_pages((unsigned long)wl->aggr_buf, order);
3918
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003919err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003920 wl1271_debugfs_exit(wl);
3921 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003922
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003923err_plat_alloc:
3924 ieee80211_free_hw(hw);
3925
3926err_hw_alloc:
3927
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02003928 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003929}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003930EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003931
3932int wl1271_free_hw(struct wl1271 *wl)
3933{
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003934 platform_device_unregister(wl->plat_dev);
Ido Yariv990f5de2011-03-31 10:06:59 +02003935 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02003936 free_pages((unsigned long)wl->aggr_buf,
3937 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02003938 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003939
3940 wl1271_debugfs_exit(wl);
3941
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02003942 vfree(wl->fw);
3943 wl->fw = NULL;
3944 kfree(wl->nvs);
3945 wl->nvs = NULL;
3946
3947 kfree(wl->fw_status);
3948 kfree(wl->tx_res_if);
3949
3950 ieee80211_free_hw(wl->hw);
3951
3952 return 0;
3953}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003954EXPORT_SYMBOL_GPL(wl1271_free_hw);
3955
Guy Eilam491bbd62011-01-12 10:33:29 +01003956u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02003957EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01003958module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02003959MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
3960
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003961MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02003962MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02003963MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");