blob: 57b10e98730eb44ca5cd29ab48a455e20edcfc59 [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>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030055 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020056 [CONF_SG_BT_PER_THRESHOLD] = 7500,
57 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
58 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020059 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030060 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020061 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
62 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
63 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
64 [CONF_SG_BEACON_MISS_PERCENT] = 60,
65 [CONF_SG_RATE_ADAPT_THRESH] = 12,
66 [CONF_SG_RATE_ADAPT_SNR] = 0,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
68 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
69 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
71 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
72 /* Note: with UPSD, this should be 4 */
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
75 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
76 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
77 /* Note: with UPDS, this should be 15 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
79 /* Note: with UPDS, this should be 50 */
80 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
81 /* Note: with UPDS, this should be 10 */
82 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
83 [CONF_SG_RXT] = 1200,
84 [CONF_SG_TXT] = 1000,
85 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
86 [CONF_SG_PS_POLL_TIMEOUT] = 10,
87 [CONF_SG_UPSD_TIMEOUT] = 10,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
95 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
96 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
98 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
99 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
100 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
101 [CONF_SG_HV3_MAX_SERVED] = 6,
102 [CONF_SG_DHCP_TIME] = 5000,
103 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
104 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300105 .ap_params = {
106 [CONF_SG_BT_PER_THRESHOLD] = 7500,
107 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
108 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
109 [CONF_SG_BT_LOAD_RATIO] = 50,
110 [CONF_SG_AUTO_PS_MODE] = 1,
111 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
112 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
113 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
114 [CONF_SG_BEACON_MISS_PERCENT] = 60,
115 [CONF_SG_RATE_ADAPT_THRESH] = 64,
116 [CONF_SG_RATE_ADAPT_SNR] = 1,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
118 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
119 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
121 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
122 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
124 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
125 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
127 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
128 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
129 [CONF_SG_RXT] = 1200,
130 [CONF_SG_TXT] = 1000,
131 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
132 [CONF_SG_PS_POLL_TIMEOUT] = 10,
133 [CONF_SG_UPSD_TIMEOUT] = 10,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
135 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
138 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
139 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
141 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
142 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
144 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
145 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
146 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
147 [CONF_SG_HV3_MAX_SERVED] = 6,
148 [CONF_SG_DHCP_TIME] = 5000,
149 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
150 [CONF_SG_TEMP_PARAM_1] = 0,
151 [CONF_SG_TEMP_PARAM_2] = 0,
152 [CONF_SG_TEMP_PARAM_3] = 0,
153 [CONF_SG_TEMP_PARAM_4] = 0,
154 [CONF_SG_TEMP_PARAM_5] = 0,
155 [CONF_SG_AP_BEACON_MISS_TX] = 3,
156 [CONF_SG_RX_WINDOW_LENGTH] = 6,
157 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
158 [CONF_SG_TEMP_PARAM_6] = 1,
159 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200160 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 },
162 .rx = {
163 .rx_msdu_life_time = 512000,
164 .packet_detection_threshold = 0,
165 .ps_poll_timeout = 15,
166 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300167 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200168 .rx_cca_threshold = 0,
169 .irq_blk_threshold = 0xFFFF,
170 .irq_pkt_threshold = 0,
171 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300172 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
173 },
174 .tx = {
175 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200176 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300177 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .short_retry_limit = 10,
179 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200180 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300181 },
182 .ac_conf_count = 4,
183 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300185 .ac = CONF_TX_AC_BE,
186 .cw_min = 15,
187 .cw_max = 63,
188 .aifsn = 3,
189 .tx_op_limit = 0,
190 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200191 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ac = CONF_TX_AC_BK,
193 .cw_min = 15,
194 .cw_max = 63,
195 .aifsn = 7,
196 .tx_op_limit = 0,
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300199 .ac = CONF_TX_AC_VI,
200 .cw_min = 15,
201 .cw_max = 63,
202 .aifsn = CONF_TX_AIFS_PIFS,
203 .tx_op_limit = 3008,
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 .ac = CONF_TX_AC_VO,
207 .cw_min = 15,
208 .cw_max = 63,
209 .aifsn = CONF_TX_AIFS_PIFS,
210 .tx_op_limit = 1504,
211 },
212 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300213 .max_tx_retries = 100,
214 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200217 [CONF_TX_AC_BE] = {
218 .queue_id = CONF_TX_AC_BE,
219 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .tsid = CONF_TX_AC_BE,
221 .ps_scheme = CONF_PS_SCHEME_LEGACY,
222 .ack_policy = CONF_ACK_POLICY_LEGACY,
223 .apsd_conf = {0, 0},
224 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200225 [CONF_TX_AC_BK] = {
226 .queue_id = CONF_TX_AC_BK,
227 .channel_type = CONF_CHANNEL_TYPE_EDCF,
228 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 .ps_scheme = CONF_PS_SCHEME_LEGACY,
230 .ack_policy = CONF_ACK_POLICY_LEGACY,
231 .apsd_conf = {0, 0},
232 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200233 [CONF_TX_AC_VI] = {
234 .queue_id = CONF_TX_AC_VI,
235 .channel_type = CONF_CHANNEL_TYPE_EDCF,
236 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 .ps_scheme = CONF_PS_SCHEME_LEGACY,
238 .ack_policy = CONF_ACK_POLICY_LEGACY,
239 .apsd_conf = {0, 0},
240 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200241 [CONF_TX_AC_VO] = {
242 .queue_id = CONF_TX_AC_VO,
243 .channel_type = CONF_CHANNEL_TYPE_EDCF,
244 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 .ps_scheme = CONF_PS_SCHEME_LEGACY,
246 .ack_policy = CONF_ACK_POLICY_LEGACY,
247 .apsd_conf = {0, 0},
248 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300249 },
250 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200251 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300252 .tx_compl_threshold = 4,
253 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
254 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200255 .tmpl_short_retry_limit = 10,
256 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300257 },
258 .conn = {
259 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300260 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300262 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 .bcn_filt_ie = {
264 [0] = {
265 .ie = WLAN_EID_CHANNEL_SWITCH,
266 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300267 },
268 [1] = {
269 .ie = WLAN_EID_HT_INFORMATION,
270 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
271 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200273 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300274 .bss_lose_timeout = 100,
275 .beacon_rx_timeout = 10000,
276 .broadcast_timeout = 20000,
277 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300278 .ps_poll_threshold = 10,
279 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300280 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200281 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300283 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200284 .psm_entry_nullfunc_retries = 3,
285 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300286 .keep_alive_interval = 55000,
287 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300288 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200289 .itrim = {
290 .enable = false,
291 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200292 },
293 .pm_config = {
294 .host_clk_settling_time = 5000,
295 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 },
297 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300298 .trigger_pacing = 1,
299 .avg_weight_rssi_beacon = 20,
300 .avg_weight_rssi_data = 10,
301 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100302 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200303 },
304 .scan = {
305 .min_dwell_time_active = 7500,
306 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100307 .min_dwell_time_passive = 100000,
308 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200309 .num_probe_reqs = 2,
310 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300311 .sched_scan = {
312 /* sched_scan requires dwell times in TU instead of TU/1000 */
313 .min_dwell_time_active = 8,
314 .max_dwell_time_active = 30,
315 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300316 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300317 .num_probe_reqs = 2,
318 .rssi_threshold = -90,
319 .snr_threshold = 0,
320 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200321 .rf = {
322 .tx_per_channel_power_compensation_2 = {
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 },
325 .tx_per_channel_power_compensation_5 = {
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 },
330 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100331 .ht = {
332 .tx_ba_win_size = 64,
333 .inactivity_timeout = 10000,
334 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200335 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200336 .num_stations = 1,
337 .ssid_profiles = 1,
338 .rx_block_num = 70,
339 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300340 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200341 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200342 .min_req_rx_blocks = 22,
343 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200344 },
345 .mem_wl128x = {
346 .num_stations = 1,
347 .ssid_profiles = 1,
348 .rx_block_num = 40,
349 .tx_min_block_num = 40,
350 .dynamic_memory = 1,
351 .min_req_tx_blocks = 45,
352 .min_req_rx_blocks = 22,
353 .tx_min = 27,
354 },
Shahar Leviff868432011-04-11 15:41:46 +0300355 .fm_coex = {
356 .enable = true,
357 .swallow_period = 5,
358 .n_divider_fref_set_1 = 0xff, /* default */
359 .n_divider_fref_set_2 = 12,
360 .m_divider_fref_set_1 = 148,
361 .m_divider_fref_set_2 = 0xffff, /* default */
362 .coex_pll_stabilization_time = 0xffffffff, /* default */
363 .ldo_stabilization_time = 0xffff, /* default */
364 .fm_disturbed_band_margin = 0xff, /* default */
365 .swallow_clk_diff = 0xff, /* default */
366 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300367 .rx_streaming = {
368 .duration = 150,
369 .queues = 0x1,
370 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300371 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300372 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300373 .fwlog = {
374 .mode = WL12XX_FWLOG_ON_DEMAND,
375 .mem_blocks = 2,
376 .severity = 0,
377 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
378 .output = WL12XX_FWLOG_OUTPUT_HOST,
379 .threshold = 0,
380 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300381 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300382 .rate = {
383 .rate_retry_score = 32000,
384 .per_add = 8192,
385 .per_th1 = 2048,
386 .per_th2 = 4096,
387 .max_per = 8100,
388 .inverse_curiosity_factor = 5,
389 .tx_fail_low_th = 4,
390 .tx_fail_high_th = 10,
391 .per_alpha_shift = 4,
392 .per_add_shift = 13,
393 .per_beta1_shift = 10,
394 .per_beta2_shift = 8,
395 .rate_check_up = 2,
396 .rate_check_down = 12,
397 .rate_retry_policy = {
398 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00,
401 },
402 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300403};
404
Ido Yariv95dac04f2011-06-06 14:57:06 +0300405static char *fwlog_param;
406
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300407static void __wl1271_op_remove_interface(struct wl1271 *wl,
408 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200409static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200410
411
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200412static void wl1271_device_release(struct device *dev)
413{
414
415}
416
417static struct platform_device wl1271_device = {
418 .name = "wl1271",
419 .id = -1,
420
421 /* device model insists to have a release function */
422 .dev = {
423 .release = wl1271_device_release,
424 },
425};
426
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200427static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300428static LIST_HEAD(wl_list);
429
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300430static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
431{
432 int ret;
433 if (operstate != IF_OPER_UP)
434 return 0;
435
436 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
437 return 0;
438
Eliad Pellerc690ec82011-08-14 13:17:07 +0300439 ret = wl12xx_cmd_set_peer_state(wl);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300440 if (ret < 0)
441 return ret;
442
Eliad Peller251c1772011-08-14 13:17:17 +0300443 wl12xx_croc(wl, wl->role_id);
444
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300445 wl1271_info("Association completed.");
446 return 0;
447}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300448static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
449 void *arg)
450{
451 struct net_device *dev = arg;
452 struct wireless_dev *wdev;
453 struct wiphy *wiphy;
454 struct ieee80211_hw *hw;
455 struct wl1271 *wl;
456 struct wl1271 *wl_temp;
457 int ret = 0;
458
459 /* Check that this notification is for us. */
460 if (what != NETDEV_CHANGE)
461 return NOTIFY_DONE;
462
463 wdev = dev->ieee80211_ptr;
464 if (wdev == NULL)
465 return NOTIFY_DONE;
466
467 wiphy = wdev->wiphy;
468 if (wiphy == NULL)
469 return NOTIFY_DONE;
470
471 hw = wiphy_priv(wiphy);
472 if (hw == NULL)
473 return NOTIFY_DONE;
474
475 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200476 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477 list_for_each_entry(wl, &wl_list, list) {
478 if (wl == wl_temp)
479 break;
480 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200481 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300482 if (wl != wl_temp)
483 return NOTIFY_DONE;
484
485 mutex_lock(&wl->mutex);
486
487 if (wl->state == WL1271_STATE_OFF)
488 goto out;
489
490 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
491 goto out;
492
Ido Yariva6208652011-03-01 15:14:41 +0200493 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300494 if (ret < 0)
495 goto out;
496
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300497 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300498
499 wl1271_ps_elp_sleep(wl);
500
501out:
502 mutex_unlock(&wl->mutex);
503
504 return NOTIFY_OK;
505}
506
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100507static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200508 struct regulatory_request *request)
509{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100510 struct ieee80211_supported_band *band;
511 struct ieee80211_channel *ch;
512 int i;
513
514 band = wiphy->bands[IEEE80211_BAND_5GHZ];
515 for (i = 0; i < band->n_channels; i++) {
516 ch = &band->channels[i];
517 if (ch->flags & IEEE80211_CHAN_DISABLED)
518 continue;
519
520 if (ch->flags & IEEE80211_CHAN_RADAR)
521 ch->flags |= IEEE80211_CHAN_NO_IBSS |
522 IEEE80211_CHAN_PASSIVE_SCAN;
523
524 }
525
526 return 0;
527}
528
Eliad Peller77ddaa12011-05-15 11:10:29 +0300529static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
530{
531 int ret = 0;
532
533 /* we should hold wl->mutex */
534 ret = wl1271_acx_ps_rx_streaming(wl, enable);
535 if (ret < 0)
536 goto out;
537
538 if (enable)
539 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
540 else
541 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
542out:
543 return ret;
544}
545
546/*
547 * this function is being called when the rx_streaming interval
548 * has beed changed or rx_streaming should be disabled
549 */
550int wl1271_recalc_rx_streaming(struct wl1271 *wl)
551{
552 int ret = 0;
553 int period = wl->conf.rx_streaming.interval;
554
555 /* don't reconfigure if rx_streaming is disabled */
556 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
557 goto out;
558
559 /* reconfigure/disable according to new streaming_period */
560 if (period &&
561 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
562 (wl->conf.rx_streaming.always ||
563 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
564 ret = wl1271_set_rx_streaming(wl, true);
565 else {
566 ret = wl1271_set_rx_streaming(wl, false);
567 /* don't cancel_work_sync since we might deadlock */
568 del_timer_sync(&wl->rx_streaming_timer);
569 }
570out:
571 return ret;
572}
573
574static void wl1271_rx_streaming_enable_work(struct work_struct *work)
575{
576 int ret;
577 struct wl1271 *wl =
578 container_of(work, struct wl1271, rx_streaming_enable_work);
579
580 mutex_lock(&wl->mutex);
581
582 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
583 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
584 (!wl->conf.rx_streaming.always &&
585 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
586 goto out;
587
588 if (!wl->conf.rx_streaming.interval)
589 goto out;
590
591 ret = wl1271_ps_elp_wakeup(wl);
592 if (ret < 0)
593 goto out;
594
595 ret = wl1271_set_rx_streaming(wl, true);
596 if (ret < 0)
597 goto out_sleep;
598
599 /* stop it after some time of inactivity */
600 mod_timer(&wl->rx_streaming_timer,
601 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
602
603out_sleep:
604 wl1271_ps_elp_sleep(wl);
605out:
606 mutex_unlock(&wl->mutex);
607}
608
609static void wl1271_rx_streaming_disable_work(struct work_struct *work)
610{
611 int ret;
612 struct wl1271 *wl =
613 container_of(work, struct wl1271, rx_streaming_disable_work);
614
615 mutex_lock(&wl->mutex);
616
617 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
618 goto out;
619
620 ret = wl1271_ps_elp_wakeup(wl);
621 if (ret < 0)
622 goto out;
623
624 ret = wl1271_set_rx_streaming(wl, false);
625 if (ret)
626 goto out_sleep;
627
628out_sleep:
629 wl1271_ps_elp_sleep(wl);
630out:
631 mutex_unlock(&wl->mutex);
632}
633
634static void wl1271_rx_streaming_timer(unsigned long data)
635{
636 struct wl1271 *wl = (struct wl1271 *)data;
637 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
638}
639
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300640static void wl1271_conf_init(struct wl1271 *wl)
641{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300642
643 /*
644 * This function applies the default configuration to the driver. This
645 * function is invoked upon driver load (spi probe.)
646 *
647 * The configuration is stored in a run-time structure in order to
648 * facilitate for run-time adjustment of any of the parameters. Making
649 * changes to the configuration structure will apply the new values on
650 * the next interface up (wl1271_op_start.)
651 */
652
653 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300654 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300655
Ido Yariv95dac04f2011-06-06 14:57:06 +0300656 /* Adjust settings according to optional module parameters */
657 if (fwlog_param) {
658 if (!strcmp(fwlog_param, "continuous")) {
659 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
660 } else if (!strcmp(fwlog_param, "ondemand")) {
661 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
662 } else if (!strcmp(fwlog_param, "dbgpins")) {
663 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
664 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
665 } else if (!strcmp(fwlog_param, "disable")) {
666 wl->conf.fwlog.mem_blocks = 0;
667 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
668 } else {
669 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
670 }
671 }
672}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300673
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300674static int wl1271_plt_init(struct wl1271 *wl)
675{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200676 struct conf_tx_ac_category *conf_ac;
677 struct conf_tx_tid *conf_tid;
678 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300679
Shahar Levi49d750ca2011-03-06 16:32:09 +0200680 if (wl->chip.id == CHIP_ID_1283_PG20)
681 ret = wl128x_cmd_general_parms(wl);
682 else
683 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200684 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200685 return ret;
686
Shahar Levi49d750ca2011-03-06 16:32:09 +0200687 if (wl->chip.id == CHIP_ID_1283_PG20)
688 ret = wl128x_cmd_radio_parms(wl);
689 else
690 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200691 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200692 return ret;
693
Shahar Levi49d750ca2011-03-06 16:32:09 +0200694 if (wl->chip.id != CHIP_ID_1283_PG20) {
695 ret = wl1271_cmd_ext_radio_parms(wl);
696 if (ret < 0)
697 return ret;
698 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200699 if (ret < 0)
700 return ret;
701
Shahar Levi48a61472011-03-06 16:32:08 +0200702 /* Chip-specific initializations */
703 ret = wl1271_chip_specific_init(wl);
704 if (ret < 0)
705 return ret;
706
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200707 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200708 if (ret < 0)
709 return ret;
710
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711 ret = wl1271_acx_init_mem_config(wl);
712 if (ret < 0)
713 return ret;
714
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715 /* PHY layer config */
716 ret = wl1271_init_phy_config(wl);
717 if (ret < 0)
718 goto out_free_memmap;
719
720 ret = wl1271_acx_dco_itrim_params(wl);
721 if (ret < 0)
722 goto out_free_memmap;
723
724 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200725 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200726 if (ret < 0)
727 goto out_free_memmap;
728
729 /* Bluetooth WLAN coexistence */
730 ret = wl1271_init_pta(wl);
731 if (ret < 0)
732 goto out_free_memmap;
733
Shahar Leviff868432011-04-11 15:41:46 +0300734 /* FM WLAN coexistence */
735 ret = wl1271_acx_fm_coex(wl);
736 if (ret < 0)
737 goto out_free_memmap;
738
Luciano Coelho12419cc2010-02-18 13:25:44 +0200739 /* Energy detection */
740 ret = wl1271_init_energy_detection(wl);
741 if (ret < 0)
742 goto out_free_memmap;
743
Eliad Peller7f0979882011-08-14 13:17:06 +0300744 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600745 if (ret < 0)
746 goto out_free_memmap;
747
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100749 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200750 if (ret < 0)
751 goto out_free_memmap;
752
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200753 /* Default TID/AC configuration */
754 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200755 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200756 conf_ac = &wl->conf.tx.ac_conf[i];
757 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
758 conf_ac->cw_max, conf_ac->aifsn,
759 conf_ac->tx_op_limit);
760 if (ret < 0)
761 goto out_free_memmap;
762
Luciano Coelho12419cc2010-02-18 13:25:44 +0200763 conf_tid = &wl->conf.tx.tid_conf[i];
764 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
765 conf_tid->channel_type,
766 conf_tid->tsid,
767 conf_tid->ps_scheme,
768 conf_tid->ack_policy,
769 conf_tid->apsd_conf[0],
770 conf_tid->apsd_conf[1]);
771 if (ret < 0)
772 goto out_free_memmap;
773 }
774
Luciano Coelho12419cc2010-02-18 13:25:44 +0200775 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200776 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300777 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200778 goto out_free_memmap;
779
780 /* Configure for CAM power saving (ie. always active) */
781 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
782 if (ret < 0)
783 goto out_free_memmap;
784
785 /* configure PM */
786 ret = wl1271_acx_pm_config(wl);
787 if (ret < 0)
788 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789
790 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200791
792 out_free_memmap:
793 kfree(wl->target_mem_map);
794 wl->target_mem_map = NULL;
795
796 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300797}
798
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300799#if 0
Arik Nemtsovb622d992011-02-23 00:22:31 +0200800static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
801{
802 bool fw_ps;
803
804 /* only regulate station links */
805 if (hlid < WL1271_AP_STA_HLID_START)
806 return;
807
808 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
809
810 /*
811 * Wake up from high level PS if the STA is asleep with too little
812 * blocks in FW or if the STA is awake.
813 */
814 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
815 wl1271_ps_link_end(wl, hlid);
816
817 /* Start high-level PS if the STA is asleep with enough blocks in FW */
818 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
819 wl1271_ps_link_start(wl, hlid, true);
820}
821
822static void wl1271_irq_update_links_status(struct wl1271 *wl,
823 struct wl1271_fw_ap_status *status)
824{
825 u32 cur_fw_ps_map;
826 u8 hlid;
827
828 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
829 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
830 wl1271_debug(DEBUG_PSM,
831 "link ps prev 0x%x cur 0x%x changed 0x%x",
832 wl->ap_fw_ps_map, cur_fw_ps_map,
833 wl->ap_fw_ps_map ^ cur_fw_ps_map);
834
835 wl->ap_fw_ps_map = cur_fw_ps_map;
836 }
837
838 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
839 u8 cnt = status->tx_lnk_free_blks[hlid] -
840 wl->links[hlid].prev_freed_blks;
841
842 wl->links[hlid].prev_freed_blks =
843 status->tx_lnk_free_blks[hlid];
844 wl->links[hlid].allocated_blks -= cnt;
845
846 wl1271_irq_ps_regulate_link(wl, hlid,
847 wl->links[hlid].allocated_blks);
848 }
849}
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300850#endif
Arik Nemtsovb622d992011-02-23 00:22:31 +0200851
Eliad Peller4d56ad92011-08-14 13:17:05 +0300852static void wl12xx_fw_status(struct wl1271 *wl,
853 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300854{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200855 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200856 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300857 int avail, freed_blocks;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300858
Eliad Peller4d56ad92011-08-14 13:17:05 +0300859 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200860
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300861 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
862 "drv_rx_counter = %d, tx_results_counter = %d)",
863 status->intr,
864 status->fw_rx_counter,
865 status->drv_rx_counter,
866 status->tx_results_counter);
867
Eliad Peller4d56ad92011-08-14 13:17:05 +0300868 freed_blocks = le32_to_cpu(status->total_released_blks) -
869 wl->tx_blocks_freed;
870 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200871
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300872 wl->tx_allocated_blocks -= freed_blocks;
873
Eliad Peller4d56ad92011-08-14 13:17:05 +0300874 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200875
Eliad Peller4d56ad92011-08-14 13:17:05 +0300876 /*
877 * The FW might change the total number of TX memblocks before
878 * we get a notification about blocks being released. Thus, the
879 * available blocks calculation might yield a temporary result
880 * which is lower than the actual available blocks. Keeping in
881 * mind that only blocks that were allocated can be moved from
882 * TX to RX, tx_blocks_available should never decrease here.
883 */
884 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
885 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886
Ido Yariva5225502010-10-12 14:49:10 +0200887 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200888 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200889 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300890
Eliad Peller4d56ad92011-08-14 13:17:05 +0300891 /* for AP update num of allocated TX blocks per link and ps status */
892 if (wl->bss_type == BSS_TYPE_AP_BSS) {
893#if 0
894 wl1271_irq_update_links_status(wl, status);
895#endif
896 }
897
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200899 getnstimeofday(&ts);
900 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
901 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902}
903
Ido Yariva6208652011-03-01 15:14:41 +0200904static void wl1271_flush_deferred_work(struct wl1271 *wl)
905{
906 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200907
Ido Yariva6208652011-03-01 15:14:41 +0200908 /* Pass all received frames to the network stack */
909 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
910 ieee80211_rx_ni(wl->hw, skb);
911
912 /* Return sent skbs to the network stack */
913 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300914 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200915}
916
917static void wl1271_netstack_work(struct work_struct *work)
918{
919 struct wl1271 *wl =
920 container_of(work, struct wl1271, netstack_work);
921
922 do {
923 wl1271_flush_deferred_work(wl);
924 } while (skb_queue_len(&wl->deferred_rx_queue));
925}
926
927#define WL1271_IRQ_MAX_LOOPS 256
928
929irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300930{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300931 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300932 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200933 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200934 struct wl1271 *wl = (struct wl1271 *)cookie;
935 bool done = false;
936 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 unsigned long flags;
938
939 /* TX might be handled here, avoid redundant work */
940 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
941 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300942
Ido Yariv341b7cd2011-03-31 10:07:01 +0200943 /*
944 * In case edge triggered interrupt must be used, we cannot iterate
945 * more than once without introducing race conditions with the hardirq.
946 */
947 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
948 loopcount = 1;
949
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300950 mutex_lock(&wl->mutex);
951
952 wl1271_debug(DEBUG_IRQ, "IRQ work");
953
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200954 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300955 goto out;
956
Ido Yariva6208652011-03-01 15:14:41 +0200957 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300958 if (ret < 0)
959 goto out;
960
Ido Yariva6208652011-03-01 15:14:41 +0200961 while (!done && loopcount--) {
962 /*
963 * In order to avoid a race with the hardirq, clear the flag
964 * before acknowledging the chip. Since the mutex is held,
965 * wl1271_ps_elp_wakeup cannot be called concurrently.
966 */
967 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
968 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200969
Eliad Peller4d56ad92011-08-14 13:17:05 +0300970 wl12xx_fw_status(wl, wl->fw_status);
971 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200972 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200973 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200974 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200975 continue;
976 }
977
Eliad Pellerccc83b02010-10-27 14:09:57 +0200978 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
979 wl1271_error("watchdog interrupt received! "
980 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300981 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200982
983 /* restarting the chip. ignore any other interrupt. */
984 goto out;
985 }
986
Ido Yariva6208652011-03-01 15:14:41 +0200987 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200988 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
989
Eliad Peller4d56ad92011-08-14 13:17:05 +0300990 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200991
Ido Yariva5225502010-10-12 14:49:10 +0200992 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200993 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200994 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300995 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200996 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200997 /*
998 * In order to avoid starvation of the TX path,
999 * call the work function directly.
1000 */
1001 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001002 } else {
1003 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001004 }
1005
Ido Yariv8aad2462011-03-01 15:14:38 +02001006 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001007 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001008 (wl->tx_results_count & 0xff))
1009 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001010
1011 /* Make sure the deferred queues don't get too long */
1012 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1013 skb_queue_len(&wl->deferred_rx_queue);
1014 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1015 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001016 }
1017
1018 if (intr & WL1271_ACX_INTR_EVENT_A) {
1019 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1020 wl1271_event_handle(wl, 0);
1021 }
1022
1023 if (intr & WL1271_ACX_INTR_EVENT_B) {
1024 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1025 wl1271_event_handle(wl, 1);
1026 }
1027
1028 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1029 wl1271_debug(DEBUG_IRQ,
1030 "WL1271_ACX_INTR_INIT_COMPLETE");
1031
1032 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1033 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 }
1035
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001036 wl1271_ps_elp_sleep(wl);
1037
1038out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001039 spin_lock_irqsave(&wl->wl_lock, flags);
1040 /* In case TX was not handled here, queue TX work */
1041 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1042 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001043 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001044 ieee80211_queue_work(wl->hw, &wl->tx_work);
1045 spin_unlock_irqrestore(&wl->wl_lock, flags);
1046
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001048
1049 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050}
Ido Yariva6208652011-03-01 15:14:41 +02001051EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001053static int wl1271_fetch_firmware(struct wl1271 *wl)
1054{
1055 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001056 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057 int ret;
1058
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001059 if (wl->chip.id == CHIP_ID_1283_PG20)
1060 fw_name = WL128X_FW_NAME;
1061 else
1062 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001063
1064 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1065
1066 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067
1068 if (ret < 0) {
1069 wl1271_error("could not get firmware: %d", ret);
1070 return ret;
1071 }
1072
1073 if (fw->size % 4) {
1074 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1075 fw->size);
1076 ret = -EILSEQ;
1077 goto out;
1078 }
1079
Arik Nemtsov166d5042010-10-16 21:44:57 +02001080 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001082 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001083
1084 if (!wl->fw) {
1085 wl1271_error("could not allocate memory for the firmware");
1086 ret = -ENOMEM;
1087 goto out;
1088 }
1089
1090 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091 ret = 0;
1092
1093out:
1094 release_firmware(fw);
1095
1096 return ret;
1097}
1098
1099static int wl1271_fetch_nvs(struct wl1271 *wl)
1100{
1101 const struct firmware *fw;
1102 int ret;
1103
Shahar Levi5aa42342011-03-06 16:32:07 +02001104 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001105
1106 if (ret < 0) {
1107 wl1271_error("could not get nvs file: %d", ret);
1108 return ret;
1109 }
1110
Shahar Levibc765bf2011-03-06 16:32:10 +02001111 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112
1113 if (!wl->nvs) {
1114 wl1271_error("could not allocate memory for the nvs file");
1115 ret = -ENOMEM;
1116 goto out;
1117 }
1118
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001119 wl->nvs_len = fw->size;
1120
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001121out:
1122 release_firmware(fw);
1123
1124 return ret;
1125}
1126
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001127void wl12xx_queue_recovery_work(struct wl1271 *wl)
1128{
1129 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1130 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1131}
1132
Ido Yariv95dac04f2011-06-06 14:57:06 +03001133size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1134{
1135 size_t len = 0;
1136
1137 /* The FW log is a length-value list, find where the log end */
1138 while (len < maxlen) {
1139 if (memblock[len] == 0)
1140 break;
1141 if (len + memblock[len] + 1 > maxlen)
1142 break;
1143 len += memblock[len] + 1;
1144 }
1145
1146 /* Make sure we have enough room */
1147 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1148
1149 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1150 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1151 wl->fwlog_size += len;
1152
1153 return len;
1154}
1155
1156static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1157{
1158 u32 addr;
1159 u32 first_addr;
1160 u8 *block;
1161
1162 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1163 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1164 (wl->conf.fwlog.mem_blocks == 0))
1165 return;
1166
1167 wl1271_info("Reading FW panic log");
1168
1169 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1170 if (!block)
1171 return;
1172
1173 /*
1174 * Make sure the chip is awake and the logger isn't active.
1175 * This might fail if the firmware hanged.
1176 */
1177 if (!wl1271_ps_elp_wakeup(wl))
1178 wl12xx_cmd_stop_fwlog(wl);
1179
1180 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001181 wl12xx_fw_status(wl, wl->fw_status);
1182 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001183 if (!first_addr)
1184 goto out;
1185
1186 /* Traverse the memory blocks linked list */
1187 addr = first_addr;
1188 do {
1189 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1190 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1191 false);
1192
1193 /*
1194 * Memory blocks are linked to one another. The first 4 bytes
1195 * of each memory block hold the hardware address of the next
1196 * one. The last memory block points to the first one.
1197 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001198 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001199 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1200 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1201 break;
1202 } while (addr && (addr != first_addr));
1203
1204 wake_up_interruptible(&wl->fwlog_waitq);
1205
1206out:
1207 kfree(block);
1208}
1209
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001210static void wl1271_recovery_work(struct work_struct *work)
1211{
1212 struct wl1271 *wl =
1213 container_of(work, struct wl1271, recovery_work);
1214
1215 mutex_lock(&wl->mutex);
1216
1217 if (wl->state != WL1271_STATE_ON)
1218 goto out;
1219
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001220 /* Avoid a recursive recovery */
1221 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1222
Ido Yariv95dac04f2011-06-06 14:57:06 +03001223 wl12xx_read_fwlog_panic(wl);
1224
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001225 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1226 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001227
Oz Krakowskib992c682011-06-26 10:36:02 +03001228 /*
1229 * Advance security sequence number to overcome potential progress
1230 * in the firmware during recovery. This doens't hurt if the network is
1231 * not encrypted.
1232 */
1233 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1234 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1235 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1236
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001237 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1238 ieee80211_connection_loss(wl->vif);
1239
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001240 /* Prevent spurious TX during FW restart */
1241 ieee80211_stop_queues(wl->hw);
1242
Luciano Coelho33c2c062011-05-10 14:46:02 +03001243 if (wl->sched_scanning) {
1244 ieee80211_sched_scan_stopped(wl->hw);
1245 wl->sched_scanning = false;
1246 }
1247
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001248 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001249 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001250
1251 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1252
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001253 ieee80211_restart_hw(wl->hw);
1254
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001255 /*
1256 * Its safe to enable TX now - the queues are stopped after a request
1257 * to restart the HW.
1258 */
1259 ieee80211_wake_queues(wl->hw);
1260
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001261out:
1262 mutex_unlock(&wl->mutex);
1263}
1264
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001265static void wl1271_fw_wakeup(struct wl1271 *wl)
1266{
1267 u32 elp_reg;
1268
1269 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001270 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271}
1272
1273static int wl1271_setup(struct wl1271 *wl)
1274{
1275 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1276 if (!wl->fw_status)
1277 return -ENOMEM;
1278
1279 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1280 if (!wl->tx_res_if) {
1281 kfree(wl->fw_status);
1282 return -ENOMEM;
1283 }
1284
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001285 return 0;
1286}
1287
1288static int wl1271_chip_wakeup(struct wl1271 *wl)
1289{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001290 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 int ret = 0;
1292
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001293 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001294 ret = wl1271_power_on(wl);
1295 if (ret < 0)
1296 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001297 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001298 wl1271_io_reset(wl);
1299 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300
1301 /* We don't need a real memory partition here, because we only want
1302 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001303 memset(&partition, 0, sizeof(partition));
1304 partition.reg.start = REGISTERS_BASE;
1305 partition.reg.size = REGISTERS_DOWN_SIZE;
1306 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307
1308 /* ELP module wake up */
1309 wl1271_fw_wakeup(wl);
1310
1311 /* whal_FwCtrl_BootSm() */
1312
1313 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001314 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315
1316 /* 1. check if chip id is valid */
1317
1318 switch (wl->chip.id) {
1319 case CHIP_ID_1271_PG10:
1320 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1321 wl->chip.id);
1322
1323 ret = wl1271_setup(wl);
1324 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326 break;
1327 case CHIP_ID_1271_PG20:
1328 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1329 wl->chip.id);
1330
Shahar Levi0c005042011-06-12 10:34:43 +03001331 /*
1332 * 'end-of-transaction flag' and 'LPD mode flag'
1333 * should be set in wl127x AP mode only
1334 */
Shahar Levi564f5952011-04-04 10:20:39 +03001335 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001336 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1337 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001338
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 ret = wl1271_setup(wl);
1340 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001342 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001343 case CHIP_ID_1283_PG20:
1344 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1345 wl->chip.id);
1346
1347 ret = wl1271_setup(wl);
1348 if (ret < 0)
1349 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001350
Ido Yariv0da13da2011-03-31 10:06:58 +02001351 if (wl1271_set_block_size(wl))
1352 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001353 break;
1354 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001359 }
1360
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001361 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001362 ret = wl1271_fetch_firmware(wl);
1363 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001364 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001365 }
1366
1367 /* No NVS from netlink, try to get it from the filesystem */
1368 if (wl->nvs == NULL) {
1369 ret = wl1271_fetch_nvs(wl);
1370 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 }
1373
1374out:
1375 return ret;
1376}
1377
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001378int wl1271_plt_start(struct wl1271 *wl)
1379{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001380 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001381 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001382 int ret;
1383
1384 mutex_lock(&wl->mutex);
1385
1386 wl1271_notice("power up");
1387
1388 if (wl->state != WL1271_STATE_OFF) {
1389 wl1271_error("cannot go into PLT state because not "
1390 "in off state: %d", wl->state);
1391 ret = -EBUSY;
1392 goto out;
1393 }
1394
Arik Nemtsov166d5042010-10-16 21:44:57 +02001395 wl->bss_type = BSS_TYPE_STA_BSS;
1396
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001397 while (retries) {
1398 retries--;
1399 ret = wl1271_chip_wakeup(wl);
1400 if (ret < 0)
1401 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001403 ret = wl1271_boot(wl);
1404 if (ret < 0)
1405 goto power_off;
1406
1407 ret = wl1271_plt_init(wl);
1408 if (ret < 0)
1409 goto irq_disable;
1410
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001411 wl->state = WL1271_STATE_PLT;
1412 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001413 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001414
Gery Kahn6f07b722011-07-18 14:21:49 +03001415 /* update hw/fw version info in wiphy struct */
1416 wiphy->hw_version = wl->chip.id;
1417 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1418 sizeof(wiphy->fw_version));
1419
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001420 goto out;
1421
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001423 mutex_unlock(&wl->mutex);
1424 /* Unlocking the mutex in the middle of handling is
1425 inherently unsafe. In this case we deem it safe to do,
1426 because we need to let any possibly pending IRQ out of
1427 the system (and while we are WL1271_STATE_OFF the IRQ
1428 work function will not do anything.) Also, any other
1429 possible concurrent operations will fail due to the
1430 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001431 wl1271_disable_interrupts(wl);
1432 wl1271_flush_deferred_work(wl);
1433 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001434 mutex_lock(&wl->mutex);
1435power_off:
1436 wl1271_power_off(wl);
1437 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001438
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001439 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1440 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001441out:
1442 mutex_unlock(&wl->mutex);
1443
1444 return ret;
1445}
1446
Luciano Coelho4623ec72011-03-21 19:26:41 +02001447static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448{
1449 int ret = 0;
1450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 wl1271_notice("power down");
1452
1453 if (wl->state != WL1271_STATE_PLT) {
1454 wl1271_error("cannot power down because not in PLT "
1455 "state: %d", wl->state);
1456 ret = -EBUSY;
1457 goto out;
1458 }
1459
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001460 wl1271_power_off(wl);
1461
1462 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001463 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001464
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001465 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001466 wl1271_disable_interrupts(wl);
1467 wl1271_flush_deferred_work(wl);
1468 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001469 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001470 mutex_lock(&wl->mutex);
1471out:
1472 return ret;
1473}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001474
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001475int wl1271_plt_stop(struct wl1271 *wl)
1476{
1477 int ret;
1478
1479 mutex_lock(&wl->mutex);
1480 ret = __wl1271_plt_stop(wl);
1481 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482 return ret;
1483}
1484
Johannes Berg7bb45682011-02-24 14:42:06 +01001485static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486{
1487 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001488 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001489 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001490 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001492 mapping = skb_get_queue_mapping(skb);
1493 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001494
1495 if (wl->bss_type == BSS_TYPE_AP_BSS)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001496 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001497
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001498 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001500 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001501
1502 /*
1503 * The workqueue is slow to process the tx_queue and we need stop
1504 * the queue here, otherwise the queue will get too long.
1505 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001506 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001507 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1508 ieee80211_stop_queue(wl->hw, mapping);
1509 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001510 }
1511
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001512 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001513 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001514 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1515 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1516 } else {
1517 skb_queue_tail(&wl->tx_queue[q], skb);
1518 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001519
1520 /*
1521 * The chip specific setup must run before the first TX packet -
1522 * before that, the tx_work will not be initialized!
1523 */
1524
Ido Yarivb07d4032011-03-01 15:14:43 +02001525 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1526 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001527 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001528
1529 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001530}
1531
Shahar Leviae47c452011-03-06 16:32:14 +02001532int wl1271_tx_dummy_packet(struct wl1271 *wl)
1533{
Ido Yariv990f5de2011-03-31 10:06:59 +02001534 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001535 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001536
Ido Yariv990f5de2011-03-31 10:06:59 +02001537 spin_lock_irqsave(&wl->wl_lock, flags);
1538 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001539 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001540 spin_unlock_irqrestore(&wl->wl_lock, flags);
1541
1542 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1543 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1544 wl1271_tx_work_locked(wl);
1545
1546 /*
1547 * If the FW TX is busy, TX work will be scheduled by the threaded
1548 * interrupt handler function
1549 */
1550 return 0;
1551}
1552
1553/*
1554 * The size of the dummy packet should be at least 1400 bytes. However, in
1555 * order to minimize the number of bus transactions, aligning it to 512 bytes
1556 * boundaries could be beneficial, performance wise
1557 */
1558#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1559
Luciano Coelhocf27d862011-04-01 21:08:23 +03001560static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001561{
1562 struct sk_buff *skb;
1563 struct ieee80211_hdr_3addr *hdr;
1564 unsigned int dummy_packet_size;
1565
1566 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1567 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1568
1569 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001570 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001571 wl1271_warning("Failed to allocate a dummy packet skb");
1572 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001573 }
1574
1575 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1576
1577 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1578 memset(hdr, 0, sizeof(*hdr));
1579 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001580 IEEE80211_STYPE_NULLFUNC |
1581 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001582
Ido Yariv990f5de2011-03-31 10:06:59 +02001583 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001584
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001585 /* Dummy packets require the TID to be management */
1586 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001587
1588 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001589 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001590 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001591
Ido Yariv990f5de2011-03-31 10:06:59 +02001592 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001593}
1594
Ido Yariv990f5de2011-03-31 10:06:59 +02001595
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001596static struct notifier_block wl1271_dev_notifier = {
1597 .notifier_call = wl1271_dev_notify,
1598};
1599
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001600#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001601static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001602{
Eliad Pellere85d1622011-06-27 13:06:43 +03001603 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001604
Eliad Peller94390642011-05-13 11:57:13 +03001605 mutex_lock(&wl->mutex);
1606
Eliad Pellere85d1622011-06-27 13:06:43 +03001607 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1608 goto out_unlock;
1609
Eliad Peller94390642011-05-13 11:57:13 +03001610 ret = wl1271_ps_elp_wakeup(wl);
1611 if (ret < 0)
1612 goto out_unlock;
1613
1614 /* enter psm if needed*/
1615 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1616 DECLARE_COMPLETION_ONSTACK(compl);
1617
1618 wl->ps_compl = &compl;
1619 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1620 wl->basic_rate, true);
1621 if (ret < 0)
1622 goto out_sleep;
1623
1624 /* we must unlock here so we will be able to get events */
1625 wl1271_ps_elp_sleep(wl);
1626 mutex_unlock(&wl->mutex);
1627
1628 ret = wait_for_completion_timeout(
1629 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1630 if (ret <= 0) {
1631 wl1271_warning("couldn't enter ps mode!");
1632 ret = -EBUSY;
1633 goto out;
1634 }
1635
1636 /* take mutex again, and wakeup */
1637 mutex_lock(&wl->mutex);
1638
1639 ret = wl1271_ps_elp_wakeup(wl);
1640 if (ret < 0)
1641 goto out_unlock;
1642 }
1643out_sleep:
1644 wl1271_ps_elp_sleep(wl);
1645out_unlock:
1646 mutex_unlock(&wl->mutex);
1647out:
1648 return ret;
1649
1650}
1651
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001652static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001653{
Eliad Pellere85d1622011-06-27 13:06:43 +03001654 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001655
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001656 mutex_lock(&wl->mutex);
1657
Eliad Pellere85d1622011-06-27 13:06:43 +03001658 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1659 goto out_unlock;
1660
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001661 ret = wl1271_ps_elp_wakeup(wl);
1662 if (ret < 0)
1663 goto out_unlock;
1664
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001665 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001666
1667 wl1271_ps_elp_sleep(wl);
1668out_unlock:
1669 mutex_unlock(&wl->mutex);
1670 return ret;
1671
1672}
1673
1674static int wl1271_configure_suspend(struct wl1271 *wl)
1675{
1676 if (wl->bss_type == BSS_TYPE_STA_BSS)
1677 return wl1271_configure_suspend_sta(wl);
1678 if (wl->bss_type == BSS_TYPE_AP_BSS)
1679 return wl1271_configure_suspend_ap(wl);
1680 return 0;
1681}
1682
1683static void wl1271_configure_resume(struct wl1271 *wl)
1684{
1685 int ret;
1686 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1687 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1688
1689 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001690 return;
1691
1692 mutex_lock(&wl->mutex);
1693 ret = wl1271_ps_elp_wakeup(wl);
1694 if (ret < 0)
1695 goto out;
1696
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001697 if (is_sta) {
1698 /* exit psm if it wasn't configured */
1699 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1700 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1701 wl->basic_rate, true);
1702 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001703 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001704 }
Eliad Peller94390642011-05-13 11:57:13 +03001705
1706 wl1271_ps_elp_sleep(wl);
1707out:
1708 mutex_unlock(&wl->mutex);
1709}
1710
Eliad Peller402e48612011-05-13 11:57:09 +03001711static int wl1271_op_suspend(struct ieee80211_hw *hw,
1712 struct cfg80211_wowlan *wow)
1713{
1714 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001715 int ret;
1716
Eliad Peller402e48612011-05-13 11:57:09 +03001717 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001718 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001719
Eliad Peller4a859df2011-06-06 12:21:52 +03001720 wl->wow_enabled = true;
1721 ret = wl1271_configure_suspend(wl);
1722 if (ret < 0) {
1723 wl1271_warning("couldn't prepare device to suspend");
1724 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001725 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 /* flush any remaining work */
1727 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001728
1729 /*
1730 * disable and re-enable interrupts in order to flush
1731 * the threaded_irq
1732 */
1733 wl1271_disable_interrupts(wl);
1734
1735 /*
1736 * set suspended flag to avoid triggering a new threaded_irq
1737 * work. no need for spinlock as interrupts are disabled.
1738 */
1739 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1740
1741 wl1271_enable_interrupts(wl);
1742 flush_work(&wl->tx_work);
1743 flush_delayed_work(&wl->pspoll_work);
1744 flush_delayed_work(&wl->elp_work);
1745
Eliad Peller402e48612011-05-13 11:57:09 +03001746 return 0;
1747}
1748
1749static int wl1271_op_resume(struct ieee80211_hw *hw)
1750{
1751 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001752 unsigned long flags;
1753 bool run_irq_work = false;
1754
Eliad Peller402e48612011-05-13 11:57:09 +03001755 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1756 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001757 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001758
1759 /*
1760 * re-enable irq_work enqueuing, and call irq_work directly if
1761 * there is a pending work.
1762 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001763 spin_lock_irqsave(&wl->wl_lock, flags);
1764 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1765 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1766 run_irq_work = true;
1767 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001768
Eliad Peller4a859df2011-06-06 12:21:52 +03001769 if (run_irq_work) {
1770 wl1271_debug(DEBUG_MAC80211,
1771 "run postponed irq_work directly");
1772 wl1271_irq(0, wl);
1773 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001774 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001775 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001776 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001777
Eliad Peller402e48612011-05-13 11:57:09 +03001778 return 0;
1779}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001780#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001781
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001782static int wl1271_op_start(struct ieee80211_hw *hw)
1783{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001784 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1785
1786 /*
1787 * We have to delay the booting of the hardware because
1788 * we need to know the local MAC address before downloading and
1789 * initializing the firmware. The MAC address cannot be changed
1790 * after boot, and without the proper MAC address, the firmware
1791 * will not function properly.
1792 *
1793 * The MAC address is first known when the corresponding interface
1794 * is added. That is where we will initialize the hardware.
1795 */
1796
1797 return 0;
1798}
1799
1800static void wl1271_op_stop(struct ieee80211_hw *hw)
1801{
1802 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1803}
1804
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001805static u8 wl12xx_get_role_type(struct wl1271 *wl)
1806{
1807 switch (wl->bss_type) {
1808 case BSS_TYPE_AP_BSS:
1809 return WL1271_ROLE_AP;
1810
1811 case BSS_TYPE_STA_BSS:
1812 return WL1271_ROLE_STA;
1813
1814 default:
1815 wl1271_error("invalid bss_type: %d", wl->bss_type);
1816 }
1817 return WL12XX_INVALID_ROLE_TYPE;
1818}
1819
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001820static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1821 struct ieee80211_vif *vif)
1822{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001823 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001824 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001825 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001826 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001827 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001828 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001829
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001830 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1831 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001832
1833 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001834 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001835 wl1271_debug(DEBUG_MAC80211,
1836 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001837 ret = -EBUSY;
1838 goto out;
1839 }
1840
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001841 /*
1842 * in some very corner case HW recovery scenarios its possible to
1843 * get here before __wl1271_op_remove_interface is complete, so
1844 * opt out if that is the case.
1845 */
1846 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1847 ret = -EBUSY;
1848 goto out;
1849 }
1850
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001851 switch (vif->type) {
1852 case NL80211_IFTYPE_STATION:
1853 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001854 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001855 break;
1856 case NL80211_IFTYPE_ADHOC:
1857 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001858 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001859 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001860 case NL80211_IFTYPE_AP:
1861 wl->bss_type = BSS_TYPE_AP_BSS;
1862 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001863 default:
1864 ret = -EOPNOTSUPP;
1865 goto out;
1866 }
1867
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001868 role_type = wl12xx_get_role_type(wl);
1869 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1870 ret = -EINVAL;
1871 goto out;
1872 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001873 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001874
1875 if (wl->state != WL1271_STATE_OFF) {
1876 wl1271_error("cannot start because not in off state: %d",
1877 wl->state);
1878 ret = -EBUSY;
1879 goto out;
1880 }
1881
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001882 while (retries) {
1883 retries--;
1884 ret = wl1271_chip_wakeup(wl);
1885 if (ret < 0)
1886 goto power_off;
1887
1888 ret = wl1271_boot(wl);
1889 if (ret < 0)
1890 goto power_off;
1891
Eliad Peller04e80792011-08-14 13:17:09 +03001892 if (wl->bss_type == BSS_TYPE_STA_BSS) {
1893 /*
1894 * The device role is a special role used for
1895 * rx and tx frames prior to association (as
1896 * the STA role can get packets only from
1897 * its associated bssid)
1898 */
1899 ret = wl12xx_cmd_role_enable(wl,
1900 WL1271_ROLE_DEVICE,
1901 &wl->dev_role_id);
1902 if (ret < 0)
1903 goto irq_disable;
1904 }
1905
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1907 if (ret < 0)
1908 goto irq_disable;
1909
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001910 ret = wl1271_hw_init(wl);
1911 if (ret < 0)
1912 goto irq_disable;
1913
Eliad Peller71125ab2010-10-28 21:46:43 +02001914 booted = true;
1915 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001916
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001917irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001918 mutex_unlock(&wl->mutex);
1919 /* Unlocking the mutex in the middle of handling is
1920 inherently unsafe. In this case we deem it safe to do,
1921 because we need to let any possibly pending IRQ out of
1922 the system (and while we are WL1271_STATE_OFF the IRQ
1923 work function will not do anything.) Also, any other
1924 possible concurrent operations will fail due to the
1925 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001926 wl1271_disable_interrupts(wl);
1927 wl1271_flush_deferred_work(wl);
1928 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001929 mutex_lock(&wl->mutex);
1930power_off:
1931 wl1271_power_off(wl);
1932 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001933
Eliad Peller71125ab2010-10-28 21:46:43 +02001934 if (!booted) {
1935 wl1271_error("firmware boot failed despite %d retries",
1936 WL1271_BOOT_RETRIES);
1937 goto out;
1938 }
1939
1940 wl->vif = vif;
1941 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001942 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001943 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001944
1945 /* update hw/fw version info in wiphy struct */
1946 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001947 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001948 sizeof(wiphy->fw_version));
1949
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001950 /*
1951 * Now we know if 11a is supported (info from the NVS), so disable
1952 * 11a channels if not supported
1953 */
1954 if (!wl->enable_11a)
1955 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1956
1957 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1958 wl->enable_11a ? "" : "not ");
1959
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001960out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001961 mutex_unlock(&wl->mutex);
1962
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001963 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001964 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001965 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001966 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001967
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001968 return ret;
1969}
1970
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001971static void __wl1271_op_remove_interface(struct wl1271 *wl,
1972 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973{
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001974 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001976 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001977
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001978 /* because of hardware recovery, we may get here twice */
1979 if (wl->state != WL1271_STATE_ON)
1980 return;
1981
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001982 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001983
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001984 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001985 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001986 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001987
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001988 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001989 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001990 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001991
Luciano Coelho08688d62010-07-08 17:50:07 +03001992 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001993 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001994 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001995 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001996 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001997 }
1998
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001999 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2000 /* disable active roles */
2001 ret = wl1271_ps_elp_wakeup(wl);
2002 if (ret < 0)
2003 goto deinit;
2004
Eliad Peller04e80792011-08-14 13:17:09 +03002005 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2006 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2007 if (ret < 0)
2008 goto deinit;
2009 }
2010
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002011 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2012 if (ret < 0)
2013 goto deinit;
2014
2015 wl1271_ps_elp_sleep(wl);
2016 }
2017deinit:
2018 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002019 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002020
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002021 /*
2022 * this must be before the cancel_work calls below, so that the work
2023 * functions don't perform further work.
2024 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 wl->state = WL1271_STATE_OFF;
2026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002027 mutex_unlock(&wl->mutex);
2028
Ido Yariva6208652011-03-01 15:14:41 +02002029 wl1271_disable_interrupts(wl);
2030 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002031 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002032 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002033 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002034 del_timer_sync(&wl->rx_streaming_timer);
2035 cancel_work_sync(&wl->rx_streaming_enable_work);
2036 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002037 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002038 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002039
2040 mutex_lock(&wl->mutex);
2041
2042 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002043 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002044 wl1271_power_off(wl);
2045
2046 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002047 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002048 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002049 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002050 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002051 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002052
2053 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002054 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002055 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2056 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002057 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002058 wl->tx_results_count = 0;
2059 wl->tx_packets_count = 0;
2060 wl->time_offset = 0;
2061 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002062 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002063 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002064 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002065 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002066 wl->ap_fw_ps_map = 0;
2067 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002068 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002069 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002070 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002071 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2072 memset(wl->links_map, 0, sizeof(wl->links_map));
Eliad Peller251c1772011-08-14 13:17:17 +03002073 memset(wl->roc_map, 0, sizeof(wl->roc_map));
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002074
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002075 /* The system link is always allocated */
2076 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2077
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002078 /*
2079 * this is performed after the cancel_work calls and the associated
2080 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2081 * get executed before all these vars have been reset.
2082 */
2083 wl->flags = 0;
2084
Eliad Peller4d56ad92011-08-14 13:17:05 +03002085 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002086
2087 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002088
2089 kfree(wl->fw_status);
2090 wl->fw_status = NULL;
2091 kfree(wl->tx_res_if);
2092 wl->tx_res_if = NULL;
2093 kfree(wl->target_mem_map);
2094 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002095}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002096
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002097static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2098 struct ieee80211_vif *vif)
2099{
2100 struct wl1271 *wl = hw->priv;
2101
2102 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002103 /*
2104 * wl->vif can be null here if someone shuts down the interface
2105 * just when hardware recovery has been started.
2106 */
2107 if (wl->vif) {
2108 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002109 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002110 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002111
Juuso Oikarinen67353292010-11-18 15:19:02 +02002112 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002113 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002114}
2115
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002116static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002117{
2118 int ret;
2119
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002120 /*
2121 * One of the side effects of the JOIN command is that is clears
2122 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2123 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002124 * Currently the only valid scenario for JOIN during association
2125 * is on roaming, in which case we will also be given new keys.
2126 * Keep the below message for now, unless it starts bothering
2127 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002128 */
2129 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2130 wl1271_info("JOIN while associated.");
2131
2132 if (set_assoc)
2133 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2134
Eliad Pellerc690ec82011-08-14 13:17:07 +03002135 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002136 if (ret < 0)
2137 goto out;
2138
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002139 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2140 goto out;
2141
2142 /*
2143 * The join command disable the keep-alive mode, shut down its process,
2144 * and also clear the template config, so we need to reset it all after
2145 * the join. The acx_aid starts the keep-alive process, and the order
2146 * of the commands below is relevant.
2147 */
2148 ret = wl1271_acx_keep_alive_mode(wl, true);
2149 if (ret < 0)
2150 goto out;
2151
2152 ret = wl1271_acx_aid(wl, wl->aid);
2153 if (ret < 0)
2154 goto out;
2155
2156 ret = wl1271_cmd_build_klv_null_data(wl);
2157 if (ret < 0)
2158 goto out;
2159
2160 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2161 ACX_KEEP_ALIVE_TPL_VALID);
2162 if (ret < 0)
2163 goto out;
2164
2165out:
2166 return ret;
2167}
2168
2169static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002170{
2171 int ret;
2172
2173 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002174 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002175 if (ret < 0)
2176 goto out;
2177
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002178 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002179
Oz Krakowskib992c682011-06-26 10:36:02 +03002180 /* reset TX security counters on a clean disconnect */
2181 wl->tx_security_last_seq_lsb = 0;
2182 wl->tx_security_seq = 0;
2183
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002184out:
2185 return ret;
2186}
2187
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002188static void wl1271_set_band_rate(struct wl1271 *wl)
2189{
2190 if (wl->band == IEEE80211_BAND_2GHZ)
2191 wl->basic_rate_set = wl->conf.tx.basic_rate;
2192 else
2193 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2194}
2195
Eliad Peller251c1772011-08-14 13:17:17 +03002196static bool wl12xx_is_roc(struct wl1271 *wl)
2197{
2198 u8 role_id;
2199
2200 role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES);
2201 if (role_id >= WL12XX_MAX_ROLES)
2202 return false;
2203
2204 return true;
2205}
2206
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002207static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002208{
2209 int ret;
2210
2211 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002212 /* no need to croc if we weren't busy (e.g. during boot) */
2213 if (wl12xx_is_roc(wl)) {
2214 ret = wl12xx_croc(wl, wl->dev_role_id);
2215 if (ret < 0)
2216 goto out;
2217
2218 ret = wl12xx_cmd_role_stop_dev(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002219 if (ret < 0)
2220 goto out;
2221 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002222 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002223 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002224 if (ret < 0)
2225 goto out;
2226 ret = wl1271_acx_keep_alive_config(
2227 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2228 ACX_KEEP_ALIVE_TPL_INVALID);
2229 if (ret < 0)
2230 goto out;
2231 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2232 } else {
2233 /* increment the session counter */
2234 wl->session_counter++;
2235 if (wl->session_counter >= SESSION_COUNTER_MAX)
2236 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002237
2238 /* The current firmware only supports sched_scan in idle */
2239 if (wl->sched_scanning) {
2240 wl1271_scan_sched_scan_stop(wl);
2241 ieee80211_sched_scan_stopped(wl->hw);
2242 }
2243
Eliad Peller251c1772011-08-14 13:17:17 +03002244 ret = wl12xx_cmd_role_start_dev(wl);
2245 if (ret < 0)
2246 goto out;
2247
2248 ret = wl12xx_roc(wl, wl->dev_role_id);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002249 if (ret < 0)
2250 goto out;
2251 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2252 }
2253
2254out:
2255 return ret;
2256}
2257
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2259{
2260 struct wl1271 *wl = hw->priv;
2261 struct ieee80211_conf *conf = &hw->conf;
2262 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002263 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002264
2265 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2266
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002267 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2268 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002269 channel,
2270 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002271 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002272 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2273 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002274
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002275 /*
2276 * mac80211 will go to idle nearly immediately after transmitting some
2277 * frames, such as the deauth. To make sure those frames reach the air,
2278 * wait here until the TX queue is fully flushed.
2279 */
2280 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2281 (conf->flags & IEEE80211_CONF_IDLE))
2282 wl1271_tx_flush(wl);
2283
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002284 mutex_lock(&wl->mutex);
2285
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002286 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002287 /* we support configuring the channel and band while off */
2288 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2289 wl->band = conf->channel->band;
2290 wl->channel = channel;
2291 }
2292
Arik Nemtsov097f8822011-06-27 22:06:34 +03002293 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2294 wl->power_level = conf->power_level;
2295
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002296 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002297 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002298
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002299 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2300
Ido Yariva6208652011-03-01 15:14:41 +02002301 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002302 if (ret < 0)
2303 goto out;
2304
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002305 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002306 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2307 ((wl->band != conf->channel->band) ||
2308 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002309 wl->band = conf->channel->band;
2310 wl->channel = channel;
2311
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002312 if (!is_ap) {
2313 /*
2314 * FIXME: the mac80211 should really provide a fixed
2315 * rate to use here. for now, just use the smallest
2316 * possible rate for the band as a fixed rate for
2317 * association frames and other control messages.
2318 */
2319 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2320 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002321
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002322 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2323 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002324 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002325 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002326 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002327
Eliad Peller251c1772011-08-14 13:17:17 +03002328 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2329 if (wl12xx_is_roc(wl)) {
2330 /* roaming */
2331 ret = wl12xx_croc(wl, wl->dev_role_id);
2332 if (ret < 0)
2333 goto out_sleep;
2334 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002335 ret = wl1271_join(wl, false);
2336 if (ret < 0)
2337 wl1271_warning("cmd join on channel "
2338 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002339 } else {
2340 /*
2341 * change the ROC channel. do it only if we are
2342 * not idle. otherwise, CROC will be called
2343 * anyway.
2344 */
2345 if (wl12xx_is_roc(wl) &&
2346 !(conf->flags & IEEE80211_CONF_IDLE)) {
2347 ret = wl12xx_croc(wl, wl->dev_role_id);
2348 if (ret < 0)
2349 goto out_sleep;
2350
2351 ret = wl12xx_roc(wl, wl->dev_role_id);
2352 if (ret < 0)
2353 wl1271_warning("roc failed %d",
2354 ret);
2355 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002356 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002357 }
2358 }
2359
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002360 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2361 ret = wl1271_sta_handle_idle(wl,
2362 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002363 if (ret < 0)
2364 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002365 }
2366
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002367 /*
2368 * if mac80211 changes the PSM mode, make sure the mode is not
2369 * incorrectly changed after the pspoll failure active window.
2370 */
2371 if (changed & IEEE80211_CONF_CHANGE_PS)
2372 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2373
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002374 if (conf->flags & IEEE80211_CONF_PS &&
2375 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2376 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002377
2378 /*
2379 * We enter PSM only if we're already associated.
2380 * If we're not, we'll enter it when joining an SSID,
2381 * through the bss_info_changed() hook.
2382 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002383 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002384 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002385 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002386 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002387 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002388 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002389 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002390 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002391
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002392 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002393
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002394 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002395 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002396 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002397 }
2398
2399 if (conf->power_level != wl->power_level) {
2400 ret = wl1271_acx_tx_power(wl, conf->power_level);
2401 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002402 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002403
2404 wl->power_level = conf->power_level;
2405 }
2406
2407out_sleep:
2408 wl1271_ps_elp_sleep(wl);
2409
2410out:
2411 mutex_unlock(&wl->mutex);
2412
2413 return ret;
2414}
2415
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002416struct wl1271_filter_params {
2417 bool enabled;
2418 int mc_list_length;
2419 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2420};
2421
Jiri Pirko22bedad32010-04-01 21:22:57 +00002422static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2423 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002424{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002425 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002426 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002427 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002428
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002429 if (unlikely(wl->state == WL1271_STATE_OFF))
2430 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002431
Juuso Oikarinen74441132009-10-13 12:47:53 +03002432 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002433 if (!fp) {
2434 wl1271_error("Out of memory setting filters.");
2435 return 0;
2436 }
2437
2438 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002439 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002440 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2441 fp->enabled = false;
2442 } else {
2443 fp->enabled = true;
2444 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002445 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002446 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002447 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002448 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002449 }
2450
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002451 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002452}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002453
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002454#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2455 FIF_ALLMULTI | \
2456 FIF_FCSFAIL | \
2457 FIF_BCN_PRBRESP_PROMISC | \
2458 FIF_CONTROL | \
2459 FIF_OTHER_BSS)
2460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002461static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2462 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002463 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002464{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002465 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002466 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002467 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468
Arik Nemtsov7d057862010-10-16 19:25:35 +02002469 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2470 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002471
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002472 mutex_lock(&wl->mutex);
2473
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002474 *total &= WL1271_SUPPORTED_FILTERS;
2475 changed &= WL1271_SUPPORTED_FILTERS;
2476
2477 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002478 goto out;
2479
Ido Yariva6208652011-03-01 15:14:41 +02002480 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002481 if (ret < 0)
2482 goto out;
2483
Arik Nemtsov7d057862010-10-16 19:25:35 +02002484 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2485 if (*total & FIF_ALLMULTI)
2486 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2487 else if (fp)
2488 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2489 fp->mc_list,
2490 fp->mc_list_length);
2491 if (ret < 0)
2492 goto out_sleep;
2493 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002494
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002495 /*
2496 * the fw doesn't provide an api to configure the filters. instead,
2497 * the filters configuration is based on the active roles / ROC
2498 * state.
2499 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002500
2501out_sleep:
2502 wl1271_ps_elp_sleep(wl);
2503
2504out:
2505 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002506 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002507}
2508
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002509static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2510 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2511 u16 tx_seq_16)
2512{
2513 struct wl1271_ap_key *ap_key;
2514 int i;
2515
2516 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2517
2518 if (key_size > MAX_KEY_SIZE)
2519 return -EINVAL;
2520
2521 /*
2522 * Find next free entry in ap_keys. Also check we are not replacing
2523 * an existing key.
2524 */
2525 for (i = 0; i < MAX_NUM_KEYS; i++) {
2526 if (wl->recorded_ap_keys[i] == NULL)
2527 break;
2528
2529 if (wl->recorded_ap_keys[i]->id == id) {
2530 wl1271_warning("trying to record key replacement");
2531 return -EINVAL;
2532 }
2533 }
2534
2535 if (i == MAX_NUM_KEYS)
2536 return -EBUSY;
2537
2538 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2539 if (!ap_key)
2540 return -ENOMEM;
2541
2542 ap_key->id = id;
2543 ap_key->key_type = key_type;
2544 ap_key->key_size = key_size;
2545 memcpy(ap_key->key, key, key_size);
2546 ap_key->hlid = hlid;
2547 ap_key->tx_seq_32 = tx_seq_32;
2548 ap_key->tx_seq_16 = tx_seq_16;
2549
2550 wl->recorded_ap_keys[i] = ap_key;
2551 return 0;
2552}
2553
2554static void wl1271_free_ap_keys(struct wl1271 *wl)
2555{
2556 int i;
2557
2558 for (i = 0; i < MAX_NUM_KEYS; i++) {
2559 kfree(wl->recorded_ap_keys[i]);
2560 wl->recorded_ap_keys[i] = NULL;
2561 }
2562}
2563
2564static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2565{
2566 int i, ret = 0;
2567 struct wl1271_ap_key *key;
2568 bool wep_key_added = false;
2569
2570 for (i = 0; i < MAX_NUM_KEYS; i++) {
2571 if (wl->recorded_ap_keys[i] == NULL)
2572 break;
2573
2574 key = wl->recorded_ap_keys[i];
2575 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2576 key->id, key->key_type,
2577 key->key_size, key->key,
2578 key->hlid, key->tx_seq_32,
2579 key->tx_seq_16);
2580 if (ret < 0)
2581 goto out;
2582
2583 if (key->key_type == KEY_WEP)
2584 wep_key_added = true;
2585 }
2586
2587 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002588 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
2589 WL1271_AP_BROADCAST_HLID);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002590 if (ret < 0)
2591 goto out;
2592 }
2593
2594out:
2595 wl1271_free_ap_keys(wl);
2596 return ret;
2597}
2598
2599static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2600 u8 key_size, const u8 *key, u32 tx_seq_32,
2601 u16 tx_seq_16, struct ieee80211_sta *sta)
2602{
2603 int ret;
2604 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2605
2606 if (is_ap) {
2607 struct wl1271_station *wl_sta;
2608 u8 hlid;
2609
2610 if (sta) {
2611 wl_sta = (struct wl1271_station *)sta->drv_priv;
2612 hlid = wl_sta->hlid;
2613 } else {
2614 hlid = WL1271_AP_BROADCAST_HLID;
2615 }
2616
2617 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2618 /*
2619 * We do not support removing keys after AP shutdown.
2620 * Pretend we do to make mac80211 happy.
2621 */
2622 if (action != KEY_ADD_OR_REPLACE)
2623 return 0;
2624
2625 ret = wl1271_record_ap_key(wl, id,
2626 key_type, key_size,
2627 key, hlid, tx_seq_32,
2628 tx_seq_16);
2629 } else {
2630 ret = wl1271_cmd_set_ap_key(wl, action,
2631 id, key_type, key_size,
2632 key, hlid, tx_seq_32,
2633 tx_seq_16);
2634 }
2635
2636 if (ret < 0)
2637 return ret;
2638 } else {
2639 const u8 *addr;
2640 static const u8 bcast_addr[ETH_ALEN] = {
2641 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2642 };
2643
2644 addr = sta ? sta->addr : bcast_addr;
2645
2646 if (is_zero_ether_addr(addr)) {
2647 /* We dont support TX only encryption */
2648 return -EOPNOTSUPP;
2649 }
2650
2651 /* The wl1271 does not allow to remove unicast keys - they
2652 will be cleared automatically on next CMD_JOIN. Ignore the
2653 request silently, as we dont want the mac80211 to emit
2654 an error message. */
2655 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2656 return 0;
2657
2658 ret = wl1271_cmd_set_sta_key(wl, action,
2659 id, key_type, key_size,
2660 key, addr, tx_seq_32,
2661 tx_seq_16);
2662 if (ret < 0)
2663 return ret;
2664
2665 /* the default WEP key needs to be configured at least once */
2666 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002667 ret = wl12xx_cmd_set_default_wep_key(wl,
2668 wl->default_key,
2669 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002670 if (ret < 0)
2671 return ret;
2672 }
2673 }
2674
2675 return 0;
2676}
2677
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2679 struct ieee80211_vif *vif,
2680 struct ieee80211_sta *sta,
2681 struct ieee80211_key_conf *key_conf)
2682{
2683 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002685 u32 tx_seq_32 = 0;
2686 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 u8 key_type;
2688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2690
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002691 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002693 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 key_conf->keylen, key_conf->flags);
2695 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2696
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697 mutex_lock(&wl->mutex);
2698
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002699 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2700 ret = -EAGAIN;
2701 goto out_unlock;
2702 }
2703
Ido Yariva6208652011-03-01 15:14:41 +02002704 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002705 if (ret < 0)
2706 goto out_unlock;
2707
Johannes Berg97359d12010-08-10 09:46:38 +02002708 switch (key_conf->cipher) {
2709 case WLAN_CIPHER_SUITE_WEP40:
2710 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002711 key_type = KEY_WEP;
2712
2713 key_conf->hw_key_idx = key_conf->keyidx;
2714 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002715 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716 key_type = KEY_TKIP;
2717
2718 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002719 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2720 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002722 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002723 key_type = KEY_AES;
2724
2725 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002726 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2727 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002728 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002729 case WL1271_CIPHER_SUITE_GEM:
2730 key_type = KEY_GEM;
2731 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2732 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2733 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002735 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002736
2737 ret = -EOPNOTSUPP;
2738 goto out_sleep;
2739 }
2740
2741 switch (cmd) {
2742 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002743 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2744 key_conf->keyidx, key_type,
2745 key_conf->keylen, key_conf->key,
2746 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002747 if (ret < 0) {
2748 wl1271_error("Could not add or replace key");
2749 goto out_sleep;
2750 }
2751 break;
2752
2753 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002754 ret = wl1271_set_key(wl, KEY_REMOVE,
2755 key_conf->keyidx, key_type,
2756 key_conf->keylen, key_conf->key,
2757 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002758 if (ret < 0) {
2759 wl1271_error("Could not remove key");
2760 goto out_sleep;
2761 }
2762 break;
2763
2764 default:
2765 wl1271_error("Unsupported key cmd 0x%x", cmd);
2766 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002767 break;
2768 }
2769
2770out_sleep:
2771 wl1271_ps_elp_sleep(wl);
2772
2773out_unlock:
2774 mutex_unlock(&wl->mutex);
2775
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002776 return ret;
2777}
2778
2779static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002780 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002781 struct cfg80211_scan_request *req)
2782{
2783 struct wl1271 *wl = hw->priv;
2784 int ret;
2785 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002786 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002787
2788 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2789
2790 if (req->n_ssids) {
2791 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002792 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002793 }
2794
2795 mutex_lock(&wl->mutex);
2796
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002797 if (wl->state == WL1271_STATE_OFF) {
2798 /*
2799 * We cannot return -EBUSY here because cfg80211 will expect
2800 * a call to ieee80211_scan_completed if we do - in this case
2801 * there won't be any call.
2802 */
2803 ret = -EAGAIN;
2804 goto out;
2805 }
2806
Ido Yariva6208652011-03-01 15:14:41 +02002807 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002808 if (ret < 0)
2809 goto out;
2810
Eliad Peller251c1772011-08-14 13:17:17 +03002811 /* cancel ROC before scanning */
2812 if (wl12xx_is_roc(wl)) {
2813 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
2814 /* don't allow scanning right now */
2815 ret = -EBUSY;
2816 goto out_sleep;
2817 }
2818 wl12xx_croc(wl, wl->dev_role_id);
2819 wl12xx_cmd_role_stop_dev(wl);
2820 }
2821
Luciano Coelho5924f892010-08-04 03:46:22 +03002822 ret = wl1271_scan(hw->priv, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03002823out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002824 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002825out:
2826 mutex_unlock(&wl->mutex);
2827
2828 return ret;
2829}
2830
Eliad Peller73ecce32011-06-27 13:06:45 +03002831static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2832 struct ieee80211_vif *vif)
2833{
2834 struct wl1271 *wl = hw->priv;
2835 int ret;
2836
2837 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2838
2839 mutex_lock(&wl->mutex);
2840
2841 if (wl->state == WL1271_STATE_OFF)
2842 goto out;
2843
2844 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2845 goto out;
2846
2847 ret = wl1271_ps_elp_wakeup(wl);
2848 if (ret < 0)
2849 goto out;
2850
2851 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2852 ret = wl1271_scan_stop(wl);
2853 if (ret < 0)
2854 goto out_sleep;
2855 }
2856 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2857 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2858 wl->scan.req = NULL;
2859 ieee80211_scan_completed(wl->hw, true);
2860
2861out_sleep:
2862 wl1271_ps_elp_sleep(wl);
2863out:
2864 mutex_unlock(&wl->mutex);
2865
2866 cancel_delayed_work_sync(&wl->scan_complete_work);
2867}
2868
Luciano Coelho33c2c062011-05-10 14:46:02 +03002869static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2870 struct ieee80211_vif *vif,
2871 struct cfg80211_sched_scan_request *req,
2872 struct ieee80211_sched_scan_ies *ies)
2873{
2874 struct wl1271 *wl = hw->priv;
2875 int ret;
2876
2877 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2878
2879 mutex_lock(&wl->mutex);
2880
2881 ret = wl1271_ps_elp_wakeup(wl);
2882 if (ret < 0)
2883 goto out;
2884
2885 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2886 if (ret < 0)
2887 goto out_sleep;
2888
2889 ret = wl1271_scan_sched_scan_start(wl);
2890 if (ret < 0)
2891 goto out_sleep;
2892
2893 wl->sched_scanning = true;
2894
2895out_sleep:
2896 wl1271_ps_elp_sleep(wl);
2897out:
2898 mutex_unlock(&wl->mutex);
2899 return ret;
2900}
2901
2902static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2903 struct ieee80211_vif *vif)
2904{
2905 struct wl1271 *wl = hw->priv;
2906 int ret;
2907
2908 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2909
2910 mutex_lock(&wl->mutex);
2911
2912 ret = wl1271_ps_elp_wakeup(wl);
2913 if (ret < 0)
2914 goto out;
2915
2916 wl1271_scan_sched_scan_stop(wl);
2917
2918 wl1271_ps_elp_sleep(wl);
2919out:
2920 mutex_unlock(&wl->mutex);
2921}
2922
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002923static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2924{
2925 struct wl1271 *wl = hw->priv;
2926 int ret = 0;
2927
2928 mutex_lock(&wl->mutex);
2929
2930 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2931 ret = -EAGAIN;
2932 goto out;
2933 }
2934
Ido Yariva6208652011-03-01 15:14:41 +02002935 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002936 if (ret < 0)
2937 goto out;
2938
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002939 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002940 if (ret < 0)
2941 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2942
2943 wl1271_ps_elp_sleep(wl);
2944
2945out:
2946 mutex_unlock(&wl->mutex);
2947
2948 return ret;
2949}
2950
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002951static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2952{
2953 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002954 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002955
2956 mutex_lock(&wl->mutex);
2957
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002958 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2959 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002960 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002961 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002962
Ido Yariva6208652011-03-01 15:14:41 +02002963 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 if (ret < 0)
2965 goto out;
2966
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002967 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002968 if (ret < 0)
2969 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2970
2971 wl1271_ps_elp_sleep(wl);
2972
2973out:
2974 mutex_unlock(&wl->mutex);
2975
2976 return ret;
2977}
2978
Arik Nemtsove78a2872010-10-16 19:07:21 +02002979static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002980 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002981{
Eliad Peller889cb362011-05-01 09:56:45 +03002982 u8 ssid_len;
2983 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2984 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002985
Eliad Peller889cb362011-05-01 09:56:45 +03002986 if (!ptr) {
2987 wl1271_error("No SSID in IEs!");
2988 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002989 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002990
Eliad Peller889cb362011-05-01 09:56:45 +03002991 ssid_len = ptr[1];
2992 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2993 wl1271_error("SSID is too long!");
2994 return -EINVAL;
2995 }
2996
2997 wl->ssid_len = ssid_len;
2998 memcpy(wl->ssid, ptr+2, ssid_len);
2999 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003000}
3001
Arik Nemtsove78a2872010-10-16 19:07:21 +02003002static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
3003 struct ieee80211_bss_conf *bss_conf,
3004 u32 changed)
3005{
3006 int ret = 0;
3007
3008 if (changed & BSS_CHANGED_ERP_SLOT) {
3009 if (bss_conf->use_short_slot)
3010 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
3011 else
3012 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
3013 if (ret < 0) {
3014 wl1271_warning("Set slot time failed %d", ret);
3015 goto out;
3016 }
3017 }
3018
3019 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3020 if (bss_conf->use_short_preamble)
3021 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
3022 else
3023 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
3024 }
3025
3026 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3027 if (bss_conf->use_cts_prot)
3028 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
3029 else
3030 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
3031 if (ret < 0) {
3032 wl1271_warning("Set ctsprotect failed %d", ret);
3033 goto out;
3034 }
3035 }
3036
3037out:
3038 return ret;
3039}
3040
3041static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3042 struct ieee80211_vif *vif,
3043 struct ieee80211_bss_conf *bss_conf,
3044 u32 changed)
3045{
3046 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3047 int ret = 0;
3048
3049 if ((changed & BSS_CHANGED_BEACON_INT)) {
3050 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3051 bss_conf->beacon_int);
3052
3053 wl->beacon_int = bss_conf->beacon_int;
3054 }
3055
3056 if ((changed & BSS_CHANGED_BEACON)) {
3057 struct ieee80211_hdr *hdr;
3058 int ieoffset = offsetof(struct ieee80211_mgmt,
3059 u.beacon.variable);
3060 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3061 u16 tmpl_id;
3062
3063 if (!beacon)
3064 goto out;
3065
3066 wl1271_debug(DEBUG_MASTER, "beacon updated");
3067
3068 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3069 if (ret < 0) {
3070 dev_kfree_skb(beacon);
3071 goto out;
3072 }
3073 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3074 CMD_TEMPL_BEACON;
3075 ret = wl1271_cmd_template_set(wl, tmpl_id,
3076 beacon->data,
3077 beacon->len, 0,
3078 wl1271_tx_min_rate_get(wl));
3079 if (ret < 0) {
3080 dev_kfree_skb(beacon);
3081 goto out;
3082 }
3083
3084 hdr = (struct ieee80211_hdr *) beacon->data;
3085 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3086 IEEE80211_STYPE_PROBE_RESP);
3087
3088 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3089 CMD_TEMPL_PROBE_RESPONSE;
3090 ret = wl1271_cmd_template_set(wl,
3091 tmpl_id,
3092 beacon->data,
3093 beacon->len, 0,
3094 wl1271_tx_min_rate_get(wl));
3095 dev_kfree_skb(beacon);
3096 if (ret < 0)
3097 goto out;
3098 }
3099
3100out:
3101 return ret;
3102}
3103
3104/* AP mode changes */
3105static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003106 struct ieee80211_vif *vif,
3107 struct ieee80211_bss_conf *bss_conf,
3108 u32 changed)
3109{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003110 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003111
Arik Nemtsove78a2872010-10-16 19:07:21 +02003112 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3113 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114
Arik Nemtsove78a2872010-10-16 19:07:21 +02003115 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3116 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003117
Arik Nemtsov70f47422011-04-18 14:15:25 +03003118 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003119 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003120 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003121 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003122 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003123
3124 ret = wl1271_ap_init_templates(wl);
3125 if (ret < 0)
3126 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003127 }
3128
Arik Nemtsove78a2872010-10-16 19:07:21 +02003129 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3130 if (ret < 0)
3131 goto out;
3132
3133 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3134 if (bss_conf->enable_beacon) {
3135 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003136 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003137 if (ret < 0)
3138 goto out;
3139
3140 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3141 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003142
3143 ret = wl1271_ap_init_hwenc(wl);
3144 if (ret < 0)
3145 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003146 }
3147 } else {
3148 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003149 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003150 if (ret < 0)
3151 goto out;
3152
3153 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3154 wl1271_debug(DEBUG_AP, "stopped AP");
3155 }
3156 }
3157 }
3158
3159 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3160 if (ret < 0)
3161 goto out;
3162out:
3163 return;
3164}
3165
3166/* STA/IBSS mode changes */
3167static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3168 struct ieee80211_vif *vif,
3169 struct ieee80211_bss_conf *bss_conf,
3170 u32 changed)
3171{
3172 bool do_join = false, set_assoc = false;
3173 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003174 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003175 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003176 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003177 bool sta_exists = false;
3178 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003179
3180 if (is_ibss) {
3181 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3182 changed);
3183 if (ret < 0)
3184 goto out;
3185 }
3186
3187 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
3188 do_join = true;
3189
3190 /* Need to update the SSID (for filtering etc) */
3191 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
3192 do_join = true;
3193
3194 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003195 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3196 bss_conf->enable_beacon ? "enabled" : "disabled");
3197
3198 if (bss_conf->enable_beacon)
3199 wl->set_bss_type = BSS_TYPE_IBSS;
3200 else
3201 wl->set_bss_type = BSS_TYPE_STA_BSS;
3202 do_join = true;
3203 }
3204
Arik Nemtsove78a2872010-10-16 19:07:21 +02003205 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003206 bool enable = false;
3207 if (bss_conf->cqm_rssi_thold)
3208 enable = true;
3209 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3210 bss_conf->cqm_rssi_thold,
3211 bss_conf->cqm_rssi_hyst);
3212 if (ret < 0)
3213 goto out;
3214 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3215 }
3216
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003217 if ((changed & BSS_CHANGED_BSSID) &&
3218 /*
3219 * Now we know the correct bssid, so we send a new join command
3220 * and enable the BSSID filter
3221 */
3222 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003223 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003224
Eliad Pellerfa287b82010-12-26 09:27:50 +01003225 if (!is_zero_ether_addr(wl->bssid)) {
3226 ret = wl1271_cmd_build_null_data(wl);
3227 if (ret < 0)
3228 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003229
Eliad Pellerfa287b82010-12-26 09:27:50 +01003230 ret = wl1271_build_qos_null_data(wl);
3231 if (ret < 0)
3232 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003233
Eliad Pellerfa287b82010-12-26 09:27:50 +01003234 /* Need to update the BSSID (for filtering etc) */
3235 do_join = true;
3236 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003237 }
3238
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003239 rcu_read_lock();
3240 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3241 if (sta) {
3242 /* save the supp_rates of the ap */
3243 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3244 if (sta->ht_cap.ht_supported)
3245 sta_rate_set |=
3246 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003247 sta_ht_cap = sta->ht_cap;
3248 sta_exists = true;
3249 }
3250 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003251
Arik Nemtsova1008852011-02-12 23:24:20 +02003252 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003253 /* handle new association with HT and HT information change */
3254 if ((changed & BSS_CHANGED_HT) &&
3255 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003256 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003257 true);
3258 if (ret < 0) {
3259 wl1271_warning("Set ht cap true failed %d",
3260 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003261 goto out;
3262 }
3263 ret = wl1271_acx_set_ht_information(wl,
3264 bss_conf->ht_operation_mode);
3265 if (ret < 0) {
3266 wl1271_warning("Set ht information failed %d",
3267 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003268 goto out;
3269 }
3270 }
3271 /* handle new association without HT and disassociation */
3272 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003273 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003274 false);
3275 if (ret < 0) {
3276 wl1271_warning("Set ht cap false failed %d",
3277 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003278 goto out;
3279 }
3280 }
3281 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003282
Arik Nemtsove78a2872010-10-16 19:07:21 +02003283 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003284 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003285 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003286 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003287 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003288 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003289
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003290 wl->ps_poll_failures = 0;
3291
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003292 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003293 * use basic rates from AP, and determine lowest rate
3294 * to use with control frames.
3295 */
3296 rates = bss_conf->basic_rates;
3297 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3298 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003299 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003300 if (sta_rate_set)
3301 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3302 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003303 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003304 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003305 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003306
3307 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003308 * with wl1271, we don't need to update the
3309 * beacon_int and dtim_period, because the firmware
3310 * updates it by itself when the first beacon is
3311 * received after a join.
3312 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003313 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3314 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003315 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003316
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003317 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003318 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003319 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003320 dev_kfree_skb(wl->probereq);
3321 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3322 ieoffset = offsetof(struct ieee80211_mgmt,
3323 u.probe_req.variable);
3324 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003325
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003326 /* enable the connection monitoring feature */
3327 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003328 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003330
3331 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003332 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3333 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003334 enum wl1271_cmd_ps_mode mode;
3335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003336 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003337 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003338 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003339 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003340 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003341 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003342 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003343 } else {
3344 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003345 bool was_assoc =
3346 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3347 &wl->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003348 bool was_ifup =
3349 !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT,
3350 &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003351 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003352
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003353 /* free probe-request template */
3354 dev_kfree_skb(wl->probereq);
3355 wl->probereq = NULL;
3356
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003357 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003358 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003359
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003360 /* revert back to minimum rates for the current band */
3361 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003362 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003363 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003364 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003366
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003367 /* disable connection monitor features */
3368 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003369
3370 /* Disable the keep-alive feature */
3371 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003372 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003373 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003374
3375 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003376 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003377 u32 conf_flags = wl->hw->conf.flags;
3378 /*
3379 * we might have to disable roc, if there was
3380 * no IF_OPER_UP notification.
3381 */
3382 if (!was_ifup) {
3383 ret = wl12xx_croc(wl, wl->role_id);
3384 if (ret < 0)
3385 goto out;
3386 }
3387 /*
3388 * (we also need to disable roc in case of
3389 * roaming on the same channel. until we will
3390 * have a better flow...)
3391 */
3392 if (test_bit(wl->dev_role_id, wl->roc_map)) {
3393 ret = wl12xx_croc(wl, wl->dev_role_id);
3394 if (ret < 0)
3395 goto out;
3396 }
3397
Eliad Peller30df14d2011-04-05 19:13:28 +03003398 wl1271_unjoin(wl);
Eliad Peller251c1772011-08-14 13:17:17 +03003399 if (!(conf_flags & IEEE80211_CONF_IDLE)) {
3400 wl12xx_cmd_role_start_dev(wl);
3401 wl12xx_roc(wl, wl->dev_role_id);
3402 }
Eliad Peller30df14d2011-04-05 19:13:28 +03003403 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003404 }
3405 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003406
Eliad Pellerd192d262011-05-24 14:33:08 +03003407 if (changed & BSS_CHANGED_IBSS) {
3408 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3409 bss_conf->ibss_joined);
3410
3411 if (bss_conf->ibss_joined) {
3412 u32 rates = bss_conf->basic_rates;
3413 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3414 rates);
3415 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3416
3417 /* by default, use 11b rates */
3418 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3419 ret = wl1271_acx_sta_rate_policies(wl);
3420 if (ret < 0)
3421 goto out;
3422 }
3423 }
3424
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3426 if (ret < 0)
3427 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003428
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003429 if (changed & BSS_CHANGED_ARP_FILTER) {
3430 __be32 addr = bss_conf->arp_addr_list[0];
3431 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3432
Eliad Pellerc5312772010-12-09 11:31:27 +02003433 if (bss_conf->arp_addr_cnt == 1 &&
3434 bss_conf->arp_filter_enabled) {
3435 /*
3436 * The template should have been configured only upon
3437 * association. however, it seems that the correct ip
3438 * isn't being set (when sending), so we have to
3439 * reconfigure the template upon every ip change.
3440 */
3441 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3442 if (ret < 0) {
3443 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003444 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003445 }
3446
3447 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003448 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003449 addr);
3450 } else
3451 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003452
3453 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003455 }
3456
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003457 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003458 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003459 if (ret < 0) {
3460 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003461 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003462 }
Eliad Peller251c1772011-08-14 13:17:17 +03003463
3464 /* ROC until connected (after EAPOL exchange) */
3465 if (!is_ibss) {
3466 ret = wl12xx_roc(wl, wl->role_id);
3467 if (ret < 0)
3468 goto out;
3469
3470 wl1271_check_operstate(wl,
3471 ieee80211_get_operstate(vif));
3472 }
3473 /*
3474 * stop device role if started (we might already be in
3475 * STA role). TODO: make it better.
3476 */
3477 if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) {
3478 ret = wl12xx_croc(wl, wl->dev_role_id);
3479 if (ret < 0)
3480 goto out;
3481
3482 ret = wl12xx_cmd_role_stop_dev(wl);
3483 if (ret < 0)
3484 goto out;
3485 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003486 }
3487
Arik Nemtsove78a2872010-10-16 19:07:21 +02003488out:
3489 return;
3490}
3491
3492static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3493 struct ieee80211_vif *vif,
3494 struct ieee80211_bss_conf *bss_conf,
3495 u32 changed)
3496{
3497 struct wl1271 *wl = hw->priv;
3498 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3499 int ret;
3500
3501 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3502 (int)changed);
3503
3504 mutex_lock(&wl->mutex);
3505
3506 if (unlikely(wl->state == WL1271_STATE_OFF))
3507 goto out;
3508
Ido Yariva6208652011-03-01 15:14:41 +02003509 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 if (ret < 0)
3511 goto out;
3512
3513 if (is_ap)
3514 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3515 else
3516 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3517
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003518 wl1271_ps_elp_sleep(wl);
3519
3520out:
3521 mutex_unlock(&wl->mutex);
3522}
3523
Kalle Valoc6999d82010-02-18 13:25:41 +02003524static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3525 const struct ieee80211_tx_queue_params *params)
3526{
3527 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003528 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003529 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003530
3531 mutex_lock(&wl->mutex);
3532
3533 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3534
Kalle Valo4695dc92010-03-18 12:26:38 +02003535 if (params->uapsd)
3536 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3537 else
3538 ps_scheme = CONF_PS_SCHEME_LEGACY;
3539
Arik Nemtsov488fc542010-10-16 20:33:45 +02003540 if (wl->state == WL1271_STATE_OFF) {
3541 /*
3542 * If the state is off, the parameters will be recorded and
3543 * configured on init. This happens in AP-mode.
3544 */
3545 struct conf_tx_ac_category *conf_ac =
3546 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3547 struct conf_tx_tid *conf_tid =
3548 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3549
3550 conf_ac->ac = wl1271_tx_get_queue(queue);
3551 conf_ac->cw_min = (u8)params->cw_min;
3552 conf_ac->cw_max = params->cw_max;
3553 conf_ac->aifsn = params->aifs;
3554 conf_ac->tx_op_limit = params->txop << 5;
3555
3556 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3557 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3558 conf_tid->tsid = wl1271_tx_get_queue(queue);
3559 conf_tid->ps_scheme = ps_scheme;
3560 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3561 conf_tid->apsd_conf[0] = 0;
3562 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003563 goto out;
3564 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003565
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003566 ret = wl1271_ps_elp_wakeup(wl);
3567 if (ret < 0)
3568 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003569
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003570 /*
3571 * the txop is confed in units of 32us by the mac80211,
3572 * we need us
3573 */
3574 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3575 params->cw_min, params->cw_max,
3576 params->aifs, params->txop << 5);
3577 if (ret < 0)
3578 goto out_sleep;
3579
3580 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3581 CONF_CHANNEL_TYPE_EDCF,
3582 wl1271_tx_get_queue(queue),
3583 ps_scheme, CONF_ACK_POLICY_LEGACY,
3584 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003585
3586out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003587 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003588
3589out:
3590 mutex_unlock(&wl->mutex);
3591
3592 return ret;
3593}
3594
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003595static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3596{
3597
3598 struct wl1271 *wl = hw->priv;
3599 u64 mactime = ULLONG_MAX;
3600 int ret;
3601
3602 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3603
3604 mutex_lock(&wl->mutex);
3605
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003606 if (unlikely(wl->state == WL1271_STATE_OFF))
3607 goto out;
3608
Ido Yariva6208652011-03-01 15:14:41 +02003609 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003610 if (ret < 0)
3611 goto out;
3612
3613 ret = wl1271_acx_tsf_info(wl, &mactime);
3614 if (ret < 0)
3615 goto out_sleep;
3616
3617out_sleep:
3618 wl1271_ps_elp_sleep(wl);
3619
3620out:
3621 mutex_unlock(&wl->mutex);
3622 return mactime;
3623}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003624
John W. Linvilleece550d2010-07-28 16:41:06 -04003625static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3626 struct survey_info *survey)
3627{
3628 struct wl1271 *wl = hw->priv;
3629 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003630
John W. Linvilleece550d2010-07-28 16:41:06 -04003631 if (idx != 0)
3632 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003633
John W. Linvilleece550d2010-07-28 16:41:06 -04003634 survey->channel = conf->channel;
3635 survey->filled = SURVEY_INFO_NOISE_DBM;
3636 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003637
John W. Linvilleece550d2010-07-28 16:41:06 -04003638 return 0;
3639}
3640
Arik Nemtsov409622e2011-02-23 00:22:29 +02003641static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003642 struct ieee80211_sta *sta,
3643 u8 *hlid)
3644{
3645 struct wl1271_station *wl_sta;
3646 int id;
3647
3648 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3649 if (id >= AP_MAX_STATIONS) {
3650 wl1271_warning("could not allocate HLID - too much stations");
3651 return -EBUSY;
3652 }
3653
3654 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003655 __set_bit(id, wl->ap_hlid_map);
3656 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3657 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003658 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003659 return 0;
3660}
3661
Arik Nemtsov409622e2011-02-23 00:22:29 +02003662static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003663{
3664 int id = hlid - WL1271_AP_STA_HLID_START;
3665
Arik Nemtsov409622e2011-02-23 00:22:29 +02003666 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3667 return;
3668
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003669 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003670 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003671 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003672 __clear_bit(hlid, &wl->ap_ps_map);
3673 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003674}
3675
Arik Nemtsov3618f302011-06-26 10:36:03 +03003676bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3677{
3678 int id = hlid - WL1271_AP_STA_HLID_START;
3679 return test_bit(id, wl->ap_hlid_map);
3680}
3681
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003682static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3683 struct ieee80211_vif *vif,
3684 struct ieee80211_sta *sta)
3685{
3686 struct wl1271 *wl = hw->priv;
3687 int ret = 0;
3688 u8 hlid;
3689
3690 mutex_lock(&wl->mutex);
3691
3692 if (unlikely(wl->state == WL1271_STATE_OFF))
3693 goto out;
3694
3695 if (wl->bss_type != BSS_TYPE_AP_BSS)
3696 goto out;
3697
3698 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3699
Arik Nemtsov409622e2011-02-23 00:22:29 +02003700 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003701 if (ret < 0)
3702 goto out;
3703
Ido Yariva6208652011-03-01 15:14:41 +02003704 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003705 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003706 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003707
Eliad Pellerc690ec82011-08-14 13:17:07 +03003708 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003709 if (ret < 0)
3710 goto out_sleep;
3711
3712out_sleep:
3713 wl1271_ps_elp_sleep(wl);
3714
Arik Nemtsov409622e2011-02-23 00:22:29 +02003715out_free_sta:
3716 if (ret < 0)
3717 wl1271_free_sta(wl, hlid);
3718
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003719out:
3720 mutex_unlock(&wl->mutex);
3721 return ret;
3722}
3723
3724static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3725 struct ieee80211_vif *vif,
3726 struct ieee80211_sta *sta)
3727{
3728 struct wl1271 *wl = hw->priv;
3729 struct wl1271_station *wl_sta;
3730 int ret = 0, id;
3731
3732 mutex_lock(&wl->mutex);
3733
3734 if (unlikely(wl->state == WL1271_STATE_OFF))
3735 goto out;
3736
3737 if (wl->bss_type != BSS_TYPE_AP_BSS)
3738 goto out;
3739
3740 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3741
3742 wl_sta = (struct wl1271_station *)sta->drv_priv;
3743 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3744 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3745 goto out;
3746
Ido Yariva6208652011-03-01 15:14:41 +02003747 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003748 if (ret < 0)
3749 goto out;
3750
Eliad Pellerc690ec82011-08-14 13:17:07 +03003751 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003752 if (ret < 0)
3753 goto out_sleep;
3754
Arik Nemtsov409622e2011-02-23 00:22:29 +02003755 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003756
3757out_sleep:
3758 wl1271_ps_elp_sleep(wl);
3759
3760out:
3761 mutex_unlock(&wl->mutex);
3762 return ret;
3763}
3764
Luciano Coelho4623ec72011-03-21 19:26:41 +02003765static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3766 struct ieee80211_vif *vif,
3767 enum ieee80211_ampdu_mlme_action action,
3768 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3769 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003770{
3771 struct wl1271 *wl = hw->priv;
3772 int ret;
3773
3774 mutex_lock(&wl->mutex);
3775
3776 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3777 ret = -EAGAIN;
3778 goto out;
3779 }
3780
Ido Yariva6208652011-03-01 15:14:41 +02003781 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003782 if (ret < 0)
3783 goto out;
3784
Shahar Levi70559a02011-05-22 16:10:22 +03003785 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3786 tid, action);
3787
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003788 switch (action) {
3789 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003790 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003791 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3792 true);
3793 if (!ret)
3794 wl->ba_rx_bitmap |= BIT(tid);
3795 } else {
3796 ret = -ENOTSUPP;
3797 }
3798 break;
3799
3800 case IEEE80211_AMPDU_RX_STOP:
3801 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3802 if (!ret)
3803 wl->ba_rx_bitmap &= ~BIT(tid);
3804 break;
3805
3806 /*
3807 * The BA initiator session management in FW independently.
3808 * Falling break here on purpose for all TX APDU commands.
3809 */
3810 case IEEE80211_AMPDU_TX_START:
3811 case IEEE80211_AMPDU_TX_STOP:
3812 case IEEE80211_AMPDU_TX_OPERATIONAL:
3813 ret = -EINVAL;
3814 break;
3815
3816 default:
3817 wl1271_error("Incorrect ampdu action id=%x\n", action);
3818 ret = -EINVAL;
3819 }
3820
3821 wl1271_ps_elp_sleep(wl);
3822
3823out:
3824 mutex_unlock(&wl->mutex);
3825
3826 return ret;
3827}
3828
Arik Nemtsov33437892011-04-26 23:35:39 +03003829static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3830{
3831 struct wl1271 *wl = hw->priv;
3832 bool ret = false;
3833
3834 mutex_lock(&wl->mutex);
3835
3836 if (unlikely(wl->state == WL1271_STATE_OFF))
3837 goto out;
3838
3839 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003840 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003841
3842 /* the above is appropriate for STA mode for PS purposes */
3843 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3844
3845out:
3846 mutex_unlock(&wl->mutex);
3847
3848 return ret;
3849}
3850
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003851/* can't be const, mac80211 writes to this */
3852static struct ieee80211_rate wl1271_rates[] = {
3853 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003854 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3855 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003856 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003857 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3858 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003859 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3860 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003861 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3862 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003863 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3864 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003865 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3866 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003867 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3868 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003869 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3870 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003871 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003872 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3873 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003874 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003875 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3876 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003877 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003878 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3879 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003880 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003881 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3882 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003883 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003884 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3885 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003886 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003887 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3888 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003889 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003890 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3891 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003892};
3893
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003894/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003895static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003896 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003897 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003898 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3899 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3900 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003901 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003902 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3903 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3904 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003905 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003906 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3907 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3908 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003909 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003910};
3911
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003912/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003913static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003914 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003915 7, /* CONF_HW_RXTX_RATE_MCS7 */
3916 6, /* CONF_HW_RXTX_RATE_MCS6 */
3917 5, /* CONF_HW_RXTX_RATE_MCS5 */
3918 4, /* CONF_HW_RXTX_RATE_MCS4 */
3919 3, /* CONF_HW_RXTX_RATE_MCS3 */
3920 2, /* CONF_HW_RXTX_RATE_MCS2 */
3921 1, /* CONF_HW_RXTX_RATE_MCS1 */
3922 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003923
3924 11, /* CONF_HW_RXTX_RATE_54 */
3925 10, /* CONF_HW_RXTX_RATE_48 */
3926 9, /* CONF_HW_RXTX_RATE_36 */
3927 8, /* CONF_HW_RXTX_RATE_24 */
3928
3929 /* TI-specific rate */
3930 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3931
3932 7, /* CONF_HW_RXTX_RATE_18 */
3933 6, /* CONF_HW_RXTX_RATE_12 */
3934 3, /* CONF_HW_RXTX_RATE_11 */
3935 5, /* CONF_HW_RXTX_RATE_9 */
3936 4, /* CONF_HW_RXTX_RATE_6 */
3937 2, /* CONF_HW_RXTX_RATE_5_5 */
3938 1, /* CONF_HW_RXTX_RATE_2 */
3939 0 /* CONF_HW_RXTX_RATE_1 */
3940};
3941
Shahar Levie8b03a22010-10-13 16:09:39 +02003942/* 11n STA capabilities */
3943#define HW_RX_HIGHEST_RATE 72
3944
Shahar Levi00d20102010-11-08 11:20:10 +00003945#ifdef CONFIG_WL12XX_HT
3946#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003947 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3948 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003949 .ht_supported = true, \
3950 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3951 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3952 .mcs = { \
3953 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3954 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3955 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3956 }, \
3957}
Shahar Levi18357852010-10-13 16:09:41 +02003958#else
Shahar Levi00d20102010-11-08 11:20:10 +00003959#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003960 .ht_supported = false, \
3961}
3962#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003963
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003964/* can't be const, mac80211 writes to this */
3965static struct ieee80211_supported_band wl1271_band_2ghz = {
3966 .channels = wl1271_channels,
3967 .n_channels = ARRAY_SIZE(wl1271_channels),
3968 .bitrates = wl1271_rates,
3969 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003970 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003971};
3972
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003973/* 5 GHz data rates for WL1273 */
3974static struct ieee80211_rate wl1271_rates_5ghz[] = {
3975 { .bitrate = 60,
3976 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3977 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3978 { .bitrate = 90,
3979 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3980 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3981 { .bitrate = 120,
3982 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3983 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3984 { .bitrate = 180,
3985 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3986 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3987 { .bitrate = 240,
3988 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3989 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3990 { .bitrate = 360,
3991 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3992 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3993 { .bitrate = 480,
3994 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3995 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3996 { .bitrate = 540,
3997 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3998 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3999};
4000
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004001/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004002static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004003 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4004 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4005 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4006 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4007 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4008 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4009 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4010 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4011 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4012 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4013 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4014 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4015 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4016 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4017 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4018 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4019 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4020 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4021 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4022 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4023 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4024 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4025 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4026 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4027 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4028 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4029 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4030 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4031 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4032 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4033 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4034 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4035 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4036 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004037};
4038
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004039/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004040static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004041 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004042 7, /* CONF_HW_RXTX_RATE_MCS7 */
4043 6, /* CONF_HW_RXTX_RATE_MCS6 */
4044 5, /* CONF_HW_RXTX_RATE_MCS5 */
4045 4, /* CONF_HW_RXTX_RATE_MCS4 */
4046 3, /* CONF_HW_RXTX_RATE_MCS3 */
4047 2, /* CONF_HW_RXTX_RATE_MCS2 */
4048 1, /* CONF_HW_RXTX_RATE_MCS1 */
4049 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004050
4051 7, /* CONF_HW_RXTX_RATE_54 */
4052 6, /* CONF_HW_RXTX_RATE_48 */
4053 5, /* CONF_HW_RXTX_RATE_36 */
4054 4, /* CONF_HW_RXTX_RATE_24 */
4055
4056 /* TI-specific rate */
4057 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4058
4059 3, /* CONF_HW_RXTX_RATE_18 */
4060 2, /* CONF_HW_RXTX_RATE_12 */
4061 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4062 1, /* CONF_HW_RXTX_RATE_9 */
4063 0, /* CONF_HW_RXTX_RATE_6 */
4064 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4065 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4066 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4067};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004068
4069static struct ieee80211_supported_band wl1271_band_5ghz = {
4070 .channels = wl1271_channels_5ghz,
4071 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4072 .bitrates = wl1271_rates_5ghz,
4073 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004074 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004075};
4076
Tobias Klausera0ea9492010-05-20 10:38:11 +02004077static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004078 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4079 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4080};
4081
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004082static const struct ieee80211_ops wl1271_ops = {
4083 .start = wl1271_op_start,
4084 .stop = wl1271_op_stop,
4085 .add_interface = wl1271_op_add_interface,
4086 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004087#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004088 .suspend = wl1271_op_suspend,
4089 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004090#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004091 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004092 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004093 .configure_filter = wl1271_op_configure_filter,
4094 .tx = wl1271_op_tx,
4095 .set_key = wl1271_op_set_key,
4096 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004097 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004098 .sched_scan_start = wl1271_op_sched_scan_start,
4099 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004100 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004101 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004102 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004103 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004104 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004105 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106 .sta_add = wl1271_op_sta_add,
4107 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004108 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004109 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004110 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004111};
4112
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004113
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004114u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004115{
4116 u8 idx;
4117
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004118 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004119
4120 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4121 wl1271_error("Illegal RX rate from HW: %d", rate);
4122 return 0;
4123 }
4124
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004125 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004126 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4127 wl1271_error("Unsupported RX rate from HW: %d", rate);
4128 return 0;
4129 }
4130
4131 return idx;
4132}
4133
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004134static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4135 struct device_attribute *attr,
4136 char *buf)
4137{
4138 struct wl1271 *wl = dev_get_drvdata(dev);
4139 ssize_t len;
4140
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004141 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004142
4143 mutex_lock(&wl->mutex);
4144 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4145 wl->sg_enabled);
4146 mutex_unlock(&wl->mutex);
4147
4148 return len;
4149
4150}
4151
4152static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4153 struct device_attribute *attr,
4154 const char *buf, size_t count)
4155{
4156 struct wl1271 *wl = dev_get_drvdata(dev);
4157 unsigned long res;
4158 int ret;
4159
Luciano Coelho6277ed62011-04-01 17:49:54 +03004160 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004161 if (ret < 0) {
4162 wl1271_warning("incorrect value written to bt_coex_mode");
4163 return count;
4164 }
4165
4166 mutex_lock(&wl->mutex);
4167
4168 res = !!res;
4169
4170 if (res == wl->sg_enabled)
4171 goto out;
4172
4173 wl->sg_enabled = res;
4174
4175 if (wl->state == WL1271_STATE_OFF)
4176 goto out;
4177
Ido Yariva6208652011-03-01 15:14:41 +02004178 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004179 if (ret < 0)
4180 goto out;
4181
4182 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4183 wl1271_ps_elp_sleep(wl);
4184
4185 out:
4186 mutex_unlock(&wl->mutex);
4187 return count;
4188}
4189
4190static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4191 wl1271_sysfs_show_bt_coex_state,
4192 wl1271_sysfs_store_bt_coex_state);
4193
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004194static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4195 struct device_attribute *attr,
4196 char *buf)
4197{
4198 struct wl1271 *wl = dev_get_drvdata(dev);
4199 ssize_t len;
4200
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004201 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004202
4203 mutex_lock(&wl->mutex);
4204 if (wl->hw_pg_ver >= 0)
4205 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4206 else
4207 len = snprintf(buf, len, "n/a\n");
4208 mutex_unlock(&wl->mutex);
4209
4210 return len;
4211}
4212
Gery Kahn6f07b722011-07-18 14:21:49 +03004213static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004214 wl1271_sysfs_show_hw_pg_ver, NULL);
4215
Ido Yariv95dac04f2011-06-06 14:57:06 +03004216static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4217 struct bin_attribute *bin_attr,
4218 char *buffer, loff_t pos, size_t count)
4219{
4220 struct device *dev = container_of(kobj, struct device, kobj);
4221 struct wl1271 *wl = dev_get_drvdata(dev);
4222 ssize_t len;
4223 int ret;
4224
4225 ret = mutex_lock_interruptible(&wl->mutex);
4226 if (ret < 0)
4227 return -ERESTARTSYS;
4228
4229 /* Let only one thread read the log at a time, blocking others */
4230 while (wl->fwlog_size == 0) {
4231 DEFINE_WAIT(wait);
4232
4233 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4234 &wait,
4235 TASK_INTERRUPTIBLE);
4236
4237 if (wl->fwlog_size != 0) {
4238 finish_wait(&wl->fwlog_waitq, &wait);
4239 break;
4240 }
4241
4242 mutex_unlock(&wl->mutex);
4243
4244 schedule();
4245 finish_wait(&wl->fwlog_waitq, &wait);
4246
4247 if (signal_pending(current))
4248 return -ERESTARTSYS;
4249
4250 ret = mutex_lock_interruptible(&wl->mutex);
4251 if (ret < 0)
4252 return -ERESTARTSYS;
4253 }
4254
4255 /* Check if the fwlog is still valid */
4256 if (wl->fwlog_size < 0) {
4257 mutex_unlock(&wl->mutex);
4258 return 0;
4259 }
4260
4261 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4262 len = min(count, (size_t)wl->fwlog_size);
4263 wl->fwlog_size -= len;
4264 memcpy(buffer, wl->fwlog, len);
4265
4266 /* Make room for new messages */
4267 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4268
4269 mutex_unlock(&wl->mutex);
4270
4271 return len;
4272}
4273
4274static struct bin_attribute fwlog_attr = {
4275 .attr = {.name = "fwlog", .mode = S_IRUSR},
4276 .read = wl1271_sysfs_read_fwlog,
4277};
4278
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004279int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004280{
4281 int ret;
4282
4283 if (wl->mac80211_registered)
4284 return 0;
4285
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004286 ret = wl1271_fetch_nvs(wl);
4287 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004288 /* NOTE: The wl->nvs->nvs element must be first, in
4289 * order to simplify the casting, we assume it is at
4290 * the beginning of the wl->nvs structure.
4291 */
4292 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004293
4294 wl->mac_addr[0] = nvs_ptr[11];
4295 wl->mac_addr[1] = nvs_ptr[10];
4296 wl->mac_addr[2] = nvs_ptr[6];
4297 wl->mac_addr[3] = nvs_ptr[5];
4298 wl->mac_addr[4] = nvs_ptr[4];
4299 wl->mac_addr[5] = nvs_ptr[3];
4300 }
4301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004302 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4303
4304 ret = ieee80211_register_hw(wl->hw);
4305 if (ret < 0) {
4306 wl1271_error("unable to register mac80211 hw: %d", ret);
4307 return ret;
4308 }
4309
4310 wl->mac80211_registered = true;
4311
Eliad Pellerd60080a2010-11-24 12:53:16 +02004312 wl1271_debugfs_init(wl);
4313
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004314 register_netdevice_notifier(&wl1271_dev_notifier);
4315
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004316 wl1271_notice("loaded");
4317
4318 return 0;
4319}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004320EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004321
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004322void wl1271_unregister_hw(struct wl1271 *wl)
4323{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004324 if (wl->state == WL1271_STATE_PLT)
4325 __wl1271_plt_stop(wl);
4326
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004327 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004328 ieee80211_unregister_hw(wl->hw);
4329 wl->mac80211_registered = false;
4330
4331}
4332EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4333
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004334int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004335{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004336 static const u32 cipher_suites[] = {
4337 WLAN_CIPHER_SUITE_WEP40,
4338 WLAN_CIPHER_SUITE_WEP104,
4339 WLAN_CIPHER_SUITE_TKIP,
4340 WLAN_CIPHER_SUITE_CCMP,
4341 WL1271_CIPHER_SUITE_GEM,
4342 };
4343
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004344 /* The tx descriptor buffer and the TKIP space. */
4345 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4346 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004347
4348 /* unit us */
4349 /* FIXME: find a proper value */
4350 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004351 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004352
4353 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004354 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004355 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004356 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004357 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004358 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004359 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004360 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004361 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004362 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004363
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004364 wl->hw->wiphy->cipher_suites = cipher_suites;
4365 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4366
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004367 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004368 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004369 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004370 /*
4371 * Maximum length of elements in scanning probe request templates
4372 * should be the maximum length possible for a template, without
4373 * the IEEE80211 header of the template
4374 */
Eliad Peller154037d2011-08-14 13:17:12 +03004375 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004376 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004377
Luciano Coelho4a31c112011-03-21 23:16:14 +02004378 /* make sure all our channels fit in the scanned_ch bitmask */
4379 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4380 ARRAY_SIZE(wl1271_channels_5ghz) >
4381 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004382 /*
4383 * We keep local copies of the band structs because we need to
4384 * modify them on a per-device basis.
4385 */
4386 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4387 sizeof(wl1271_band_2ghz));
4388 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4389 sizeof(wl1271_band_5ghz));
4390
4391 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4392 &wl->bands[IEEE80211_BAND_2GHZ];
4393 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4394 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004395
Kalle Valo12bd8942010-03-18 12:26:33 +02004396 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004397 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004398
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004399 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4400
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004401 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004402
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004403 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4404
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004405 wl->hw->max_rx_aggregation_subframes = 8;
4406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004407 return 0;
4408}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004409EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004410
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004412
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004413struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004415 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004416 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004418 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004419 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004420
4421 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4422 if (!hw) {
4423 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004424 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004425 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 }
4427
Julia Lawall929ebd32010-05-15 23:16:39 +02004428 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004429 if (!plat_dev) {
4430 wl1271_error("could not allocate platform_device");
4431 ret = -ENOMEM;
4432 goto err_plat_alloc;
4433 }
4434
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 wl = hw->priv;
4436 memset(wl, 0, sizeof(*wl));
4437
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004438 INIT_LIST_HEAD(&wl->list);
4439
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004441 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004442
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004443 for (i = 0; i < NUM_TX_QUEUES; i++)
4444 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004445
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004446 for (i = 0; i < NUM_TX_QUEUES; i++)
4447 for (j = 0; j < AP_MAX_LINKS; j++)
4448 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4449
Ido Yariva6208652011-03-01 15:14:41 +02004450 skb_queue_head_init(&wl->deferred_rx_queue);
4451 skb_queue_head_init(&wl->deferred_tx_queue);
4452
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004453 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004454 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004455 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004456 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4457 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4458 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004459 INIT_WORK(&wl->rx_streaming_enable_work,
4460 wl1271_rx_streaming_enable_work);
4461 INIT_WORK(&wl->rx_streaming_disable_work,
4462 wl1271_rx_streaming_disable_work);
4463
Eliad Peller92ef8962011-06-07 12:50:46 +03004464 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4465 if (!wl->freezable_wq) {
4466 ret = -ENOMEM;
4467 goto err_hw;
4468 }
4469
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004471 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004472 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004474 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004475 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004476 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004477 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004478 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004479 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004480 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004481 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004482 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004483 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004484 wl->bss_type = MAX_BSS_TYPE;
4485 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004486 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004487 wl->ap_ps_map = 0;
4488 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004489 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004490 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004491 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004492 wl->tx_security_seq = 0;
4493 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004494 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004495 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004496 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004497 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4498 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004499 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4500 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004501 wl->fwlog_size = 0;
4502 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004503
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004504 /* The system link is always allocated */
4505 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4506
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004507 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004508 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004509 wl->tx_frames[i] = NULL;
4510
4511 spin_lock_init(&wl->wl_lock);
4512
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004513 wl->state = WL1271_STATE_OFF;
4514 mutex_init(&wl->mutex);
4515
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004516 /* Apply default driver configuration. */
4517 wl1271_conf_init(wl);
4518
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004519 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4520 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4521 if (!wl->aggr_buf) {
4522 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004523 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004524 }
4525
Ido Yariv990f5de2011-03-31 10:06:59 +02004526 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4527 if (!wl->dummy_packet) {
4528 ret = -ENOMEM;
4529 goto err_aggr;
4530 }
4531
Ido Yariv95dac04f2011-06-06 14:57:06 +03004532 /* Allocate one page for the FW log */
4533 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4534 if (!wl->fwlog) {
4535 ret = -ENOMEM;
4536 goto err_dummy_packet;
4537 }
4538
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004539 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004540 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004541 if (ret) {
4542 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004543 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004544 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004545 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004546
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004547 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004548 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004549 if (ret < 0) {
4550 wl1271_error("failed to create sysfs file bt_coex_state");
4551 goto err_platform;
4552 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004553
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004554 /* Create sysfs file to get HW PG version */
4555 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4556 if (ret < 0) {
4557 wl1271_error("failed to create sysfs file hw_pg_ver");
4558 goto err_bt_coex_state;
4559 }
4560
Ido Yariv95dac04f2011-06-06 14:57:06 +03004561 /* Create sysfs file for the FW log */
4562 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4563 if (ret < 0) {
4564 wl1271_error("failed to create sysfs file fwlog");
4565 goto err_hw_pg_ver;
4566 }
4567
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004568 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004569
Ido Yariv95dac04f2011-06-06 14:57:06 +03004570err_hw_pg_ver:
4571 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4572
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004573err_bt_coex_state:
4574 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4575
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004576err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004577 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004578
Ido Yariv95dac04f2011-06-06 14:57:06 +03004579err_fwlog:
4580 free_page((unsigned long)wl->fwlog);
4581
Ido Yariv990f5de2011-03-31 10:06:59 +02004582err_dummy_packet:
4583 dev_kfree_skb(wl->dummy_packet);
4584
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004585err_aggr:
4586 free_pages((unsigned long)wl->aggr_buf, order);
4587
Eliad Peller92ef8962011-06-07 12:50:46 +03004588err_wq:
4589 destroy_workqueue(wl->freezable_wq);
4590
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004591err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004592 wl1271_debugfs_exit(wl);
4593 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004594
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004595err_plat_alloc:
4596 ieee80211_free_hw(hw);
4597
4598err_hw_alloc:
4599
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004600 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004601}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004602EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004603
4604int wl1271_free_hw(struct wl1271 *wl)
4605{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004606 /* Unblock any fwlog readers */
4607 mutex_lock(&wl->mutex);
4608 wl->fwlog_size = -1;
4609 wake_up_interruptible_all(&wl->fwlog_waitq);
4610 mutex_unlock(&wl->mutex);
4611
4612 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004613
4614 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4615
4616 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004617 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004618 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004619 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004620 free_pages((unsigned long)wl->aggr_buf,
4621 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004622 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004623
4624 wl1271_debugfs_exit(wl);
4625
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004626 vfree(wl->fw);
4627 wl->fw = NULL;
4628 kfree(wl->nvs);
4629 wl->nvs = NULL;
4630
4631 kfree(wl->fw_status);
4632 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004633 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004634
4635 ieee80211_free_hw(wl->hw);
4636
4637 return 0;
4638}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004639EXPORT_SYMBOL_GPL(wl1271_free_hw);
4640
Guy Eilam491bbd62011-01-12 10:33:29 +01004641u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004642EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004643module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004644MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4645
Ido Yariv95dac04f2011-06-06 14:57:06 +03004646module_param_named(fwlog, fwlog_param, charp, 0);
4647MODULE_PARM_DESC(keymap,
4648 "FW logger options: continuous, ondemand, dbgpins or disable");
4649
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004650MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004651MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004652MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");