blob: 7fcdfa3ee1db07ac52e64a7d90771180ae3602ef [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,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300382};
383
Ido Yariv95dac04f2011-06-06 14:57:06 +0300384static char *fwlog_param;
385
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300386static void __wl1271_op_remove_interface(struct wl1271 *wl,
387 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200388static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200389
390
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200391static void wl1271_device_release(struct device *dev)
392{
393
394}
395
396static struct platform_device wl1271_device = {
397 .name = "wl1271",
398 .id = -1,
399
400 /* device model insists to have a release function */
401 .dev = {
402 .release = wl1271_device_release,
403 },
404};
405
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200406static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300407static LIST_HEAD(wl_list);
408
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300409static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
410{
411 int ret;
412 if (operstate != IF_OPER_UP)
413 return 0;
414
415 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
416 return 0;
417
418 ret = wl1271_cmd_set_sta_state(wl);
419 if (ret < 0)
420 return ret;
421
422 wl1271_info("Association completed.");
423 return 0;
424}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300425static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
426 void *arg)
427{
428 struct net_device *dev = arg;
429 struct wireless_dev *wdev;
430 struct wiphy *wiphy;
431 struct ieee80211_hw *hw;
432 struct wl1271 *wl;
433 struct wl1271 *wl_temp;
434 int ret = 0;
435
436 /* Check that this notification is for us. */
437 if (what != NETDEV_CHANGE)
438 return NOTIFY_DONE;
439
440 wdev = dev->ieee80211_ptr;
441 if (wdev == NULL)
442 return NOTIFY_DONE;
443
444 wiphy = wdev->wiphy;
445 if (wiphy == NULL)
446 return NOTIFY_DONE;
447
448 hw = wiphy_priv(wiphy);
449 if (hw == NULL)
450 return NOTIFY_DONE;
451
452 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200453 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300454 list_for_each_entry(wl, &wl_list, list) {
455 if (wl == wl_temp)
456 break;
457 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200458 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300459 if (wl != wl_temp)
460 return NOTIFY_DONE;
461
462 mutex_lock(&wl->mutex);
463
464 if (wl->state == WL1271_STATE_OFF)
465 goto out;
466
467 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
468 goto out;
469
Ido Yariva6208652011-03-01 15:14:41 +0200470 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300471 if (ret < 0)
472 goto out;
473
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300474 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475
476 wl1271_ps_elp_sleep(wl);
477
478out:
479 mutex_unlock(&wl->mutex);
480
481 return NOTIFY_OK;
482}
483
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200485 struct regulatory_request *request)
486{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100487 struct ieee80211_supported_band *band;
488 struct ieee80211_channel *ch;
489 int i;
490
491 band = wiphy->bands[IEEE80211_BAND_5GHZ];
492 for (i = 0; i < band->n_channels; i++) {
493 ch = &band->channels[i];
494 if (ch->flags & IEEE80211_CHAN_DISABLED)
495 continue;
496
497 if (ch->flags & IEEE80211_CHAN_RADAR)
498 ch->flags |= IEEE80211_CHAN_NO_IBSS |
499 IEEE80211_CHAN_PASSIVE_SCAN;
500
501 }
502
503 return 0;
504}
505
Eliad Peller77ddaa12011-05-15 11:10:29 +0300506static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
507{
508 int ret = 0;
509
510 /* we should hold wl->mutex */
511 ret = wl1271_acx_ps_rx_streaming(wl, enable);
512 if (ret < 0)
513 goto out;
514
515 if (enable)
516 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
517 else
518 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
519out:
520 return ret;
521}
522
523/*
524 * this function is being called when the rx_streaming interval
525 * has beed changed or rx_streaming should be disabled
526 */
527int wl1271_recalc_rx_streaming(struct wl1271 *wl)
528{
529 int ret = 0;
530 int period = wl->conf.rx_streaming.interval;
531
532 /* don't reconfigure if rx_streaming is disabled */
533 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
534 goto out;
535
536 /* reconfigure/disable according to new streaming_period */
537 if (period &&
538 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
539 (wl->conf.rx_streaming.always ||
540 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
541 ret = wl1271_set_rx_streaming(wl, true);
542 else {
543 ret = wl1271_set_rx_streaming(wl, false);
544 /* don't cancel_work_sync since we might deadlock */
545 del_timer_sync(&wl->rx_streaming_timer);
546 }
547out:
548 return ret;
549}
550
551static void wl1271_rx_streaming_enable_work(struct work_struct *work)
552{
553 int ret;
554 struct wl1271 *wl =
555 container_of(work, struct wl1271, rx_streaming_enable_work);
556
557 mutex_lock(&wl->mutex);
558
559 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
560 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
561 (!wl->conf.rx_streaming.always &&
562 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
563 goto out;
564
565 if (!wl->conf.rx_streaming.interval)
566 goto out;
567
568 ret = wl1271_ps_elp_wakeup(wl);
569 if (ret < 0)
570 goto out;
571
572 ret = wl1271_set_rx_streaming(wl, true);
573 if (ret < 0)
574 goto out_sleep;
575
576 /* stop it after some time of inactivity */
577 mod_timer(&wl->rx_streaming_timer,
578 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
579
580out_sleep:
581 wl1271_ps_elp_sleep(wl);
582out:
583 mutex_unlock(&wl->mutex);
584}
585
586static void wl1271_rx_streaming_disable_work(struct work_struct *work)
587{
588 int ret;
589 struct wl1271 *wl =
590 container_of(work, struct wl1271, rx_streaming_disable_work);
591
592 mutex_lock(&wl->mutex);
593
594 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
601 ret = wl1271_set_rx_streaming(wl, false);
602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
613 struct wl1271 *wl = (struct wl1271 *)data;
614 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
615}
616
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300617static void wl1271_conf_init(struct wl1271 *wl)
618{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300619
620 /*
621 * This function applies the default configuration to the driver. This
622 * function is invoked upon driver load (spi probe.)
623 *
624 * The configuration is stored in a run-time structure in order to
625 * facilitate for run-time adjustment of any of the parameters. Making
626 * changes to the configuration structure will apply the new values on
627 * the next interface up (wl1271_op_start.)
628 */
629
630 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300631 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300632
Ido Yariv95dac04f2011-06-06 14:57:06 +0300633 /* Adjust settings according to optional module parameters */
634 if (fwlog_param) {
635 if (!strcmp(fwlog_param, "continuous")) {
636 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
637 } else if (!strcmp(fwlog_param, "ondemand")) {
638 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
639 } else if (!strcmp(fwlog_param, "dbgpins")) {
640 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
641 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
642 } else if (!strcmp(fwlog_param, "disable")) {
643 wl->conf.fwlog.mem_blocks = 0;
644 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
645 } else {
646 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
647 }
648 }
649}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300651static int wl1271_plt_init(struct wl1271 *wl)
652{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200653 struct conf_tx_ac_category *conf_ac;
654 struct conf_tx_tid *conf_tid;
655 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300656
Shahar Levi49d750ca2011-03-06 16:32:09 +0200657 if (wl->chip.id == CHIP_ID_1283_PG20)
658 ret = wl128x_cmd_general_parms(wl);
659 else
660 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200661 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200662 return ret;
663
Shahar Levi49d750ca2011-03-06 16:32:09 +0200664 if (wl->chip.id == CHIP_ID_1283_PG20)
665 ret = wl128x_cmd_radio_parms(wl);
666 else
667 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200668 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200669 return ret;
670
Shahar Levi49d750ca2011-03-06 16:32:09 +0200671 if (wl->chip.id != CHIP_ID_1283_PG20) {
672 ret = wl1271_cmd_ext_radio_parms(wl);
673 if (ret < 0)
674 return ret;
675 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200676 if (ret < 0)
677 return ret;
678
Shahar Levi48a61472011-03-06 16:32:08 +0200679 /* Chip-specific initializations */
680 ret = wl1271_chip_specific_init(wl);
681 if (ret < 0)
682 return ret;
683
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200684 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200685 if (ret < 0)
686 return ret;
687
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300688 ret = wl1271_acx_init_mem_config(wl);
689 if (ret < 0)
690 return ret;
691
Luciano Coelho12419cc2010-02-18 13:25:44 +0200692 /* PHY layer config */
693 ret = wl1271_init_phy_config(wl);
694 if (ret < 0)
695 goto out_free_memmap;
696
697 ret = wl1271_acx_dco_itrim_params(wl);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200702 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200703 if (ret < 0)
704 goto out_free_memmap;
705
706 /* Bluetooth WLAN coexistence */
707 ret = wl1271_init_pta(wl);
708 if (ret < 0)
709 goto out_free_memmap;
710
Shahar Leviff868432011-04-11 15:41:46 +0300711 /* FM WLAN coexistence */
712 ret = wl1271_acx_fm_coex(wl);
713 if (ret < 0)
714 goto out_free_memmap;
715
Luciano Coelho12419cc2010-02-18 13:25:44 +0200716 /* Energy detection */
717 ret = wl1271_init_energy_detection(wl);
718 if (ret < 0)
719 goto out_free_memmap;
720
Gery Kahn1ec610e2011-02-01 03:03:08 -0600721 ret = wl1271_acx_sta_mem_cfg(wl);
722 if (ret < 0)
723 goto out_free_memmap;
724
Luciano Coelho12419cc2010-02-18 13:25:44 +0200725 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100726 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200727 if (ret < 0)
728 goto out_free_memmap;
729
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200730 /* Default TID/AC configuration */
731 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200732 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200733 conf_ac = &wl->conf.tx.ac_conf[i];
734 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
735 conf_ac->cw_max, conf_ac->aifsn,
736 conf_ac->tx_op_limit);
737 if (ret < 0)
738 goto out_free_memmap;
739
Luciano Coelho12419cc2010-02-18 13:25:44 +0200740 conf_tid = &wl->conf.tx.tid_conf[i];
741 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
742 conf_tid->channel_type,
743 conf_tid->tsid,
744 conf_tid->ps_scheme,
745 conf_tid->ack_policy,
746 conf_tid->apsd_conf[0],
747 conf_tid->apsd_conf[1]);
748 if (ret < 0)
749 goto out_free_memmap;
750 }
751
Luciano Coelho12419cc2010-02-18 13:25:44 +0200752 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200753 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300754 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200755 goto out_free_memmap;
756
757 /* Configure for CAM power saving (ie. always active) */
758 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
759 if (ret < 0)
760 goto out_free_memmap;
761
762 /* configure PM */
763 ret = wl1271_acx_pm_config(wl);
764 if (ret < 0)
765 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300766
767 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200768
769 out_free_memmap:
770 kfree(wl->target_mem_map);
771 wl->target_mem_map = NULL;
772
773 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774}
775
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300776#if 0
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
778{
779 bool fw_ps;
780
781 /* only regulate station links */
782 if (hlid < WL1271_AP_STA_HLID_START)
783 return;
784
785 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
786
787 /*
788 * Wake up from high level PS if the STA is asleep with too little
789 * blocks in FW or if the STA is awake.
790 */
791 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
792 wl1271_ps_link_end(wl, hlid);
793
794 /* Start high-level PS if the STA is asleep with enough blocks in FW */
795 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
796 wl1271_ps_link_start(wl, hlid, true);
797}
798
799static void wl1271_irq_update_links_status(struct wl1271 *wl,
800 struct wl1271_fw_ap_status *status)
801{
802 u32 cur_fw_ps_map;
803 u8 hlid;
804
805 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
806 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
807 wl1271_debug(DEBUG_PSM,
808 "link ps prev 0x%x cur 0x%x changed 0x%x",
809 wl->ap_fw_ps_map, cur_fw_ps_map,
810 wl->ap_fw_ps_map ^ cur_fw_ps_map);
811
812 wl->ap_fw_ps_map = cur_fw_ps_map;
813 }
814
815 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
816 u8 cnt = status->tx_lnk_free_blks[hlid] -
817 wl->links[hlid].prev_freed_blks;
818
819 wl->links[hlid].prev_freed_blks =
820 status->tx_lnk_free_blks[hlid];
821 wl->links[hlid].allocated_blks -= cnt;
822
823 wl1271_irq_ps_regulate_link(wl, hlid,
824 wl->links[hlid].allocated_blks);
825 }
826}
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300827#endif
Arik Nemtsovb622d992011-02-23 00:22:31 +0200828
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300829static void wl1271_fw_status(struct wl1271 *wl,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200830 struct wl1271_fw_full_status *full_status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831{
Eliad Pellerc8bde242011-02-02 09:59:35 +0200832 struct wl1271_fw_common_status *status = &full_status->common;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200833 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200834 u32 old_tx_blk_count = wl->tx_blocks_available;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300835 u32 freed_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836 int i;
837
Shahar Levi13b107d2011-03-06 16:32:12 +0200838 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200839 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
840 sizeof(struct wl1271_fw_ap_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200841 } else {
Eliad Pellerc8bde242011-02-02 09:59:35 +0200842 wl1271_raw_read(wl, FW_STATUS_ADDR, status,
843 sizeof(struct wl1271_fw_sta_status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200844 }
845
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
847 "drv_rx_counter = %d, tx_results_counter = %d)",
848 status->intr,
849 status->fw_rx_counter,
850 status->drv_rx_counter,
851 status->tx_results_counter);
852
853 /* update number of available TX blocks */
854 for (i = 0; i < NUM_TX_QUEUES; i++) {
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300855 freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
856 wl->tx_blocks_freed[i];
Luciano Coelhod0f63b22009-10-15 10:33:29 +0300857
858 wl->tx_blocks_freed[i] =
859 le32_to_cpu(status->tx_released_blks[i]);
Shahar Levi13b107d2011-03-06 16:32:12 +0200860 }
861
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300862 wl->tx_allocated_blocks -= freed_blocks;
863
Ido Yarivd2f4d472011-03-31 10:07:00 +0200864 if (wl->bss_type == BSS_TYPE_AP_BSS) {
865 /* Update num of allocated TX blocks per link and ps status */
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300866#if 0
Ido Yarivd2f4d472011-03-31 10:07:00 +0200867 wl1271_irq_update_links_status(wl, &full_status->ap);
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300868#endif
Ido Yarivd2f4d472011-03-31 10:07:00 +0200869 wl->tx_blocks_available += freed_blocks;
870 } else {
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300871 int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200872
873 /*
874 * The FW might change the total number of TX memblocks before
875 * we get a notification about blocks being released. Thus, the
876 * available blocks calculation might yield a temporary result
877 * which is lower than the actual available blocks. Keeping in
878 * mind that only blocks that were allocated can be moved from
879 * TX to RX, tx_blocks_available should never decrease here.
880 */
881 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
882 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300883 }
884
Ido Yariva5225502010-10-12 14:49:10 +0200885 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200886 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200887 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300888
889 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200890 getnstimeofday(&ts);
891 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
892 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893}
894
Ido Yariva6208652011-03-01 15:14:41 +0200895static void wl1271_flush_deferred_work(struct wl1271 *wl)
896{
897 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200898
Ido Yariva6208652011-03-01 15:14:41 +0200899 /* Pass all received frames to the network stack */
900 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
901 ieee80211_rx_ni(wl->hw, skb);
902
903 /* Return sent skbs to the network stack */
904 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300905 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200906}
907
908static void wl1271_netstack_work(struct work_struct *work)
909{
910 struct wl1271 *wl =
911 container_of(work, struct wl1271, netstack_work);
912
913 do {
914 wl1271_flush_deferred_work(wl);
915 } while (skb_queue_len(&wl->deferred_rx_queue));
916}
917
918#define WL1271_IRQ_MAX_LOOPS 256
919
920irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300921{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300922 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300923 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200925 struct wl1271 *wl = (struct wl1271 *)cookie;
926 bool done = false;
927 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200928 unsigned long flags;
929
930 /* TX might be handled here, avoid redundant work */
931 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
932 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300933
Ido Yariv341b7cd2011-03-31 10:07:01 +0200934 /*
935 * In case edge triggered interrupt must be used, we cannot iterate
936 * more than once without introducing race conditions with the hardirq.
937 */
938 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
939 loopcount = 1;
940
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300941 mutex_lock(&wl->mutex);
942
943 wl1271_debug(DEBUG_IRQ, "IRQ work");
944
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200945 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300946 goto out;
947
Ido Yariva6208652011-03-01 15:14:41 +0200948 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300949 if (ret < 0)
950 goto out;
951
Ido Yariva6208652011-03-01 15:14:41 +0200952 while (!done && loopcount--) {
953 /*
954 * In order to avoid a race with the hardirq, clear the flag
955 * before acknowledging the chip. Since the mutex is held,
956 * wl1271_ps_elp_wakeup cannot be called concurrently.
957 */
958 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
959 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960
961 wl1271_fw_status(wl, wl->fw_status);
Eliad Pellerc8bde242011-02-02 09:59:35 +0200962 intr = le32_to_cpu(wl->fw_status->common.intr);
Ido Yariva6208652011-03-01 15:14:41 +0200963 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200964 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200965 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200966 continue;
967 }
968
Eliad Pellerccc83b02010-10-27 14:09:57 +0200969 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
970 wl1271_error("watchdog interrupt received! "
971 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300972 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200973
974 /* restarting the chip. ignore any other interrupt. */
975 goto out;
976 }
977
Ido Yariva6208652011-03-01 15:14:41 +0200978 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200979 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
980
Ido Yariv8aad2462011-03-01 15:14:38 +0200981 wl1271_rx(wl, &wl->fw_status->common);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200982
Ido Yariva5225502010-10-12 14:49:10 +0200983 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200984 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200985 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300986 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200987 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200988 /*
989 * In order to avoid starvation of the TX path,
990 * call the work function directly.
991 */
992 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200993 } else {
994 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200995 }
996
Ido Yariv8aad2462011-03-01 15:14:38 +0200997 /* check for tx results */
998 if (wl->fw_status->common.tx_results_counter !=
999 (wl->tx_results_count & 0xff))
1000 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001001
1002 /* Make sure the deferred queues don't get too long */
1003 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1004 skb_queue_len(&wl->deferred_rx_queue);
1005 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1006 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001007 }
1008
1009 if (intr & WL1271_ACX_INTR_EVENT_A) {
1010 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1011 wl1271_event_handle(wl, 0);
1012 }
1013
1014 if (intr & WL1271_ACX_INTR_EVENT_B) {
1015 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1016 wl1271_event_handle(wl, 1);
1017 }
1018
1019 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1020 wl1271_debug(DEBUG_IRQ,
1021 "WL1271_ACX_INTR_INIT_COMPLETE");
1022
1023 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1024 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025 }
1026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001027 wl1271_ps_elp_sleep(wl);
1028
1029out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001030 spin_lock_irqsave(&wl->wl_lock, flags);
1031 /* In case TX was not handled here, queue TX work */
1032 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1033 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001034 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001035 ieee80211_queue_work(wl->hw, &wl->tx_work);
1036 spin_unlock_irqrestore(&wl->wl_lock, flags);
1037
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001038 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001039
1040 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001041}
Ido Yariva6208652011-03-01 15:14:41 +02001042EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044static int wl1271_fetch_firmware(struct wl1271 *wl)
1045{
1046 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001047 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048 int ret;
1049
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001050 if (wl->chip.id == CHIP_ID_1283_PG20)
1051 fw_name = WL128X_FW_NAME;
1052 else
1053 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001054
1055 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1056
1057 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001058
1059 if (ret < 0) {
1060 wl1271_error("could not get firmware: %d", ret);
1061 return ret;
1062 }
1063
1064 if (fw->size % 4) {
1065 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1066 fw->size);
1067 ret = -EILSEQ;
1068 goto out;
1069 }
1070
Arik Nemtsov166d5042010-10-16 21:44:57 +02001071 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001072 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001073 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001074
1075 if (!wl->fw) {
1076 wl1271_error("could not allocate memory for the firmware");
1077 ret = -ENOMEM;
1078 goto out;
1079 }
1080
1081 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001082 ret = 0;
1083
1084out:
1085 release_firmware(fw);
1086
1087 return ret;
1088}
1089
1090static int wl1271_fetch_nvs(struct wl1271 *wl)
1091{
1092 const struct firmware *fw;
1093 int ret;
1094
Shahar Levi5aa42342011-03-06 16:32:07 +02001095 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001096
1097 if (ret < 0) {
1098 wl1271_error("could not get nvs file: %d", ret);
1099 return ret;
1100 }
1101
Shahar Levibc765bf2011-03-06 16:32:10 +02001102 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103
1104 if (!wl->nvs) {
1105 wl1271_error("could not allocate memory for the nvs file");
1106 ret = -ENOMEM;
1107 goto out;
1108 }
1109
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001110 wl->nvs_len = fw->size;
1111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001112out:
1113 release_firmware(fw);
1114
1115 return ret;
1116}
1117
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001118void wl12xx_queue_recovery_work(struct wl1271 *wl)
1119{
1120 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1121 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1122}
1123
Ido Yariv95dac04f2011-06-06 14:57:06 +03001124size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1125{
1126 size_t len = 0;
1127
1128 /* The FW log is a length-value list, find where the log end */
1129 while (len < maxlen) {
1130 if (memblock[len] == 0)
1131 break;
1132 if (len + memblock[len] + 1 > maxlen)
1133 break;
1134 len += memblock[len] + 1;
1135 }
1136
1137 /* Make sure we have enough room */
1138 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1139
1140 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1141 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1142 wl->fwlog_size += len;
1143
1144 return len;
1145}
1146
1147static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1148{
1149 u32 addr;
1150 u32 first_addr;
1151 u8 *block;
1152
1153 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1154 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1155 (wl->conf.fwlog.mem_blocks == 0))
1156 return;
1157
1158 wl1271_info("Reading FW panic log");
1159
1160 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1161 if (!block)
1162 return;
1163
1164 /*
1165 * Make sure the chip is awake and the logger isn't active.
1166 * This might fail if the firmware hanged.
1167 */
1168 if (!wl1271_ps_elp_wakeup(wl))
1169 wl12xx_cmd_stop_fwlog(wl);
1170
1171 /* Read the first memory block address */
1172 wl1271_fw_status(wl, wl->fw_status);
1173 first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr);
1174 if (!first_addr)
1175 goto out;
1176
1177 /* Traverse the memory blocks linked list */
1178 addr = first_addr;
1179 do {
1180 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1181 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1182 false);
1183
1184 /*
1185 * Memory blocks are linked to one another. The first 4 bytes
1186 * of each memory block hold the hardware address of the next
1187 * one. The last memory block points to the first one.
1188 */
1189 addr = __le32_to_cpup((__le32 *)block);
1190 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1191 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1192 break;
1193 } while (addr && (addr != first_addr));
1194
1195 wake_up_interruptible(&wl->fwlog_waitq);
1196
1197out:
1198 kfree(block);
1199}
1200
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001201static void wl1271_recovery_work(struct work_struct *work)
1202{
1203 struct wl1271 *wl =
1204 container_of(work, struct wl1271, recovery_work);
1205
1206 mutex_lock(&wl->mutex);
1207
1208 if (wl->state != WL1271_STATE_ON)
1209 goto out;
1210
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001211 /* Avoid a recursive recovery */
1212 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1213
Ido Yariv95dac04f2011-06-06 14:57:06 +03001214 wl12xx_read_fwlog_panic(wl);
1215
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001216 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1217 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001218
Oz Krakowskib992c682011-06-26 10:36:02 +03001219 /*
1220 * Advance security sequence number to overcome potential progress
1221 * in the firmware during recovery. This doens't hurt if the network is
1222 * not encrypted.
1223 */
1224 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1225 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1226 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1227
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001228 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1229 ieee80211_connection_loss(wl->vif);
1230
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001231 /* Prevent spurious TX during FW restart */
1232 ieee80211_stop_queues(wl->hw);
1233
Luciano Coelho33c2c062011-05-10 14:46:02 +03001234 if (wl->sched_scanning) {
1235 ieee80211_sched_scan_stopped(wl->hw);
1236 wl->sched_scanning = false;
1237 }
1238
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001239 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001240 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001241
1242 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1243
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001244 ieee80211_restart_hw(wl->hw);
1245
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001246 /*
1247 * Its safe to enable TX now - the queues are stopped after a request
1248 * to restart the HW.
1249 */
1250 ieee80211_wake_queues(wl->hw);
1251
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001252out:
1253 mutex_unlock(&wl->mutex);
1254}
1255
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256static void wl1271_fw_wakeup(struct wl1271 *wl)
1257{
1258 u32 elp_reg;
1259
1260 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001261 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262}
1263
1264static int wl1271_setup(struct wl1271 *wl)
1265{
1266 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1267 if (!wl->fw_status)
1268 return -ENOMEM;
1269
1270 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1271 if (!wl->tx_res_if) {
1272 kfree(wl->fw_status);
1273 return -ENOMEM;
1274 }
1275
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001276 return 0;
1277}
1278
1279static int wl1271_chip_wakeup(struct wl1271 *wl)
1280{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001281 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282 int ret = 0;
1283
Juuso Oikarinen01ac17ec2009-12-11 15:41:02 +02001284 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001285 ret = wl1271_power_on(wl);
1286 if (ret < 0)
1287 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001288 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001289 wl1271_io_reset(wl);
1290 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291
1292 /* We don't need a real memory partition here, because we only want
1293 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001294 memset(&partition, 0, sizeof(partition));
1295 partition.reg.start = REGISTERS_BASE;
1296 partition.reg.size = REGISTERS_DOWN_SIZE;
1297 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298
1299 /* ELP module wake up */
1300 wl1271_fw_wakeup(wl);
1301
1302 /* whal_FwCtrl_BootSm() */
1303
1304 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001305 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306
1307 /* 1. check if chip id is valid */
1308
1309 switch (wl->chip.id) {
1310 case CHIP_ID_1271_PG10:
1311 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1312 wl->chip.id);
1313
1314 ret = wl1271_setup(wl);
1315 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001316 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317 break;
1318 case CHIP_ID_1271_PG20:
1319 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1320 wl->chip.id);
1321
Shahar Levi0c005042011-06-12 10:34:43 +03001322 /*
1323 * 'end-of-transaction flag' and 'LPD mode flag'
1324 * should be set in wl127x AP mode only
1325 */
Shahar Levi564f5952011-04-04 10:20:39 +03001326 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001327 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1328 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001329
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330 ret = wl1271_setup(wl);
1331 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001332 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001333 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001334 case CHIP_ID_1283_PG20:
1335 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1336 wl->chip.id);
1337
1338 ret = wl1271_setup(wl);
1339 if (ret < 0)
1340 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001341
Ido Yariv0da13da2011-03-31 10:06:58 +02001342 if (wl1271_set_block_size(wl))
1343 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001344 break;
1345 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001346 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001347 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001348 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001349 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350 }
1351
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001352 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 ret = wl1271_fetch_firmware(wl);
1354 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001355 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356 }
1357
1358 /* No NVS from netlink, try to get it from the filesystem */
1359 if (wl->nvs == NULL) {
1360 ret = wl1271_fetch_nvs(wl);
1361 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001362 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 }
1364
1365out:
1366 return ret;
1367}
1368
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001369int wl1271_plt_start(struct wl1271 *wl)
1370{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001372 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001373 int ret;
1374
1375 mutex_lock(&wl->mutex);
1376
1377 wl1271_notice("power up");
1378
1379 if (wl->state != WL1271_STATE_OFF) {
1380 wl1271_error("cannot go into PLT state because not "
1381 "in off state: %d", wl->state);
1382 ret = -EBUSY;
1383 goto out;
1384 }
1385
Arik Nemtsov166d5042010-10-16 21:44:57 +02001386 wl->bss_type = BSS_TYPE_STA_BSS;
1387
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001388 while (retries) {
1389 retries--;
1390 ret = wl1271_chip_wakeup(wl);
1391 if (ret < 0)
1392 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 ret = wl1271_boot(wl);
1395 if (ret < 0)
1396 goto power_off;
1397
1398 ret = wl1271_plt_init(wl);
1399 if (ret < 0)
1400 goto irq_disable;
1401
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001402 wl->state = WL1271_STATE_PLT;
1403 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001404 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001405
Gery Kahn6f07b722011-07-18 14:21:49 +03001406 /* update hw/fw version info in wiphy struct */
1407 wiphy->hw_version = wl->chip.id;
1408 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1409 sizeof(wiphy->fw_version));
1410
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411 goto out;
1412
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001413irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001414 mutex_unlock(&wl->mutex);
1415 /* Unlocking the mutex in the middle of handling is
1416 inherently unsafe. In this case we deem it safe to do,
1417 because we need to let any possibly pending IRQ out of
1418 the system (and while we are WL1271_STATE_OFF the IRQ
1419 work function will not do anything.) Also, any other
1420 possible concurrent operations will fail due to the
1421 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001422 wl1271_disable_interrupts(wl);
1423 wl1271_flush_deferred_work(wl);
1424 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001425 mutex_lock(&wl->mutex);
1426power_off:
1427 wl1271_power_off(wl);
1428 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001429
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001430 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1431 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432out:
1433 mutex_unlock(&wl->mutex);
1434
1435 return ret;
1436}
1437
Luciano Coelho4623ec72011-03-21 19:26:41 +02001438static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439{
1440 int ret = 0;
1441
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001442 wl1271_notice("power down");
1443
1444 if (wl->state != WL1271_STATE_PLT) {
1445 wl1271_error("cannot power down because not in PLT "
1446 "state: %d", wl->state);
1447 ret = -EBUSY;
1448 goto out;
1449 }
1450
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451 wl1271_power_off(wl);
1452
1453 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001454 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001455
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001456 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001457 wl1271_disable_interrupts(wl);
1458 wl1271_flush_deferred_work(wl);
1459 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001460 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001461 mutex_lock(&wl->mutex);
1462out:
1463 return ret;
1464}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001465
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001466int wl1271_plt_stop(struct wl1271 *wl)
1467{
1468 int ret;
1469
1470 mutex_lock(&wl->mutex);
1471 ret = __wl1271_plt_stop(wl);
1472 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001473 return ret;
1474}
1475
Johannes Berg7bb45682011-02-24 14:42:06 +01001476static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001477{
1478 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001479 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001480 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001481 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001482
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001483 mapping = skb_get_queue_mapping(skb);
1484 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001485
1486 if (wl->bss_type == BSS_TYPE_AP_BSS)
1487 hlid = wl1271_tx_get_hlid(skb);
1488
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001489 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001490
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001491 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001492
1493 /*
1494 * The workqueue is slow to process the tx_queue and we need stop
1495 * the queue here, otherwise the queue will get too long.
1496 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001497 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001498 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1499 ieee80211_stop_queue(wl->hw, mapping);
1500 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001501 }
1502
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001503 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001504 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001505 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1506 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1507 } else {
1508 skb_queue_tail(&wl->tx_queue[q], skb);
1509 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001510
1511 /*
1512 * The chip specific setup must run before the first TX packet -
1513 * before that, the tx_work will not be initialized!
1514 */
1515
Ido Yarivb07d4032011-03-01 15:14:43 +02001516 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1517 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001518 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001519
1520 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001521}
1522
Shahar Leviae47c452011-03-06 16:32:14 +02001523int wl1271_tx_dummy_packet(struct wl1271 *wl)
1524{
Ido Yariv990f5de2011-03-31 10:06:59 +02001525 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001526 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001527
Ido Yariv990f5de2011-03-31 10:06:59 +02001528 spin_lock_irqsave(&wl->wl_lock, flags);
1529 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001530 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001531 spin_unlock_irqrestore(&wl->wl_lock, flags);
1532
1533 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1534 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1535 wl1271_tx_work_locked(wl);
1536
1537 /*
1538 * If the FW TX is busy, TX work will be scheduled by the threaded
1539 * interrupt handler function
1540 */
1541 return 0;
1542}
1543
1544/*
1545 * The size of the dummy packet should be at least 1400 bytes. However, in
1546 * order to minimize the number of bus transactions, aligning it to 512 bytes
1547 * boundaries could be beneficial, performance wise
1548 */
1549#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1550
Luciano Coelhocf27d862011-04-01 21:08:23 +03001551static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001552{
1553 struct sk_buff *skb;
1554 struct ieee80211_hdr_3addr *hdr;
1555 unsigned int dummy_packet_size;
1556
1557 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1558 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1559
1560 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001561 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 wl1271_warning("Failed to allocate a dummy packet skb");
1563 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001564 }
1565
1566 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1567
1568 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1569 memset(hdr, 0, sizeof(*hdr));
1570 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001571 IEEE80211_STYPE_NULLFUNC |
1572 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001573
Ido Yariv990f5de2011-03-31 10:06:59 +02001574 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001575
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001576 /* Dummy packets require the TID to be management */
1577 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001578
1579 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001580 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001581 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001582
Ido Yariv990f5de2011-03-31 10:06:59 +02001583 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001584}
1585
Ido Yariv990f5de2011-03-31 10:06:59 +02001586
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001587static struct notifier_block wl1271_dev_notifier = {
1588 .notifier_call = wl1271_dev_notify,
1589};
1590
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001591#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001592static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001593{
Eliad Pellere85d1622011-06-27 13:06:43 +03001594 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001595
Eliad Peller94390642011-05-13 11:57:13 +03001596 mutex_lock(&wl->mutex);
1597
Eliad Pellere85d1622011-06-27 13:06:43 +03001598 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1599 goto out_unlock;
1600
Eliad Peller94390642011-05-13 11:57:13 +03001601 ret = wl1271_ps_elp_wakeup(wl);
1602 if (ret < 0)
1603 goto out_unlock;
1604
1605 /* enter psm if needed*/
1606 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1607 DECLARE_COMPLETION_ONSTACK(compl);
1608
1609 wl->ps_compl = &compl;
1610 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1611 wl->basic_rate, true);
1612 if (ret < 0)
1613 goto out_sleep;
1614
1615 /* we must unlock here so we will be able to get events */
1616 wl1271_ps_elp_sleep(wl);
1617 mutex_unlock(&wl->mutex);
1618
1619 ret = wait_for_completion_timeout(
1620 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1621 if (ret <= 0) {
1622 wl1271_warning("couldn't enter ps mode!");
1623 ret = -EBUSY;
1624 goto out;
1625 }
1626
1627 /* take mutex again, and wakeup */
1628 mutex_lock(&wl->mutex);
1629
1630 ret = wl1271_ps_elp_wakeup(wl);
1631 if (ret < 0)
1632 goto out_unlock;
1633 }
1634out_sleep:
1635 wl1271_ps_elp_sleep(wl);
1636out_unlock:
1637 mutex_unlock(&wl->mutex);
1638out:
1639 return ret;
1640
1641}
1642
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001643static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001644{
Eliad Pellere85d1622011-06-27 13:06:43 +03001645 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001646
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001647 mutex_lock(&wl->mutex);
1648
Eliad Pellere85d1622011-06-27 13:06:43 +03001649 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1650 goto out_unlock;
1651
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001652 ret = wl1271_ps_elp_wakeup(wl);
1653 if (ret < 0)
1654 goto out_unlock;
1655
1656 ret = wl1271_acx_set_ap_beacon_filter(wl, true);
1657
1658 wl1271_ps_elp_sleep(wl);
1659out_unlock:
1660 mutex_unlock(&wl->mutex);
1661 return ret;
1662
1663}
1664
1665static int wl1271_configure_suspend(struct wl1271 *wl)
1666{
1667 if (wl->bss_type == BSS_TYPE_STA_BSS)
1668 return wl1271_configure_suspend_sta(wl);
1669 if (wl->bss_type == BSS_TYPE_AP_BSS)
1670 return wl1271_configure_suspend_ap(wl);
1671 return 0;
1672}
1673
1674static void wl1271_configure_resume(struct wl1271 *wl)
1675{
1676 int ret;
1677 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1678 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1679
1680 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001681 return;
1682
1683 mutex_lock(&wl->mutex);
1684 ret = wl1271_ps_elp_wakeup(wl);
1685 if (ret < 0)
1686 goto out;
1687
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001688 if (is_sta) {
1689 /* exit psm if it wasn't configured */
1690 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1691 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1692 wl->basic_rate, true);
1693 } else if (is_ap) {
1694 wl1271_acx_set_ap_beacon_filter(wl, false);
1695 }
Eliad Peller94390642011-05-13 11:57:13 +03001696
1697 wl1271_ps_elp_sleep(wl);
1698out:
1699 mutex_unlock(&wl->mutex);
1700}
1701
Eliad Peller402e48612011-05-13 11:57:09 +03001702static int wl1271_op_suspend(struct ieee80211_hw *hw,
1703 struct cfg80211_wowlan *wow)
1704{
1705 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001706 int ret;
1707
Eliad Peller402e48612011-05-13 11:57:09 +03001708 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001709 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001710
Eliad Peller4a859df2011-06-06 12:21:52 +03001711 wl->wow_enabled = true;
1712 ret = wl1271_configure_suspend(wl);
1713 if (ret < 0) {
1714 wl1271_warning("couldn't prepare device to suspend");
1715 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001716 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001717 /* flush any remaining work */
1718 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001719
1720 /*
1721 * disable and re-enable interrupts in order to flush
1722 * the threaded_irq
1723 */
1724 wl1271_disable_interrupts(wl);
1725
1726 /*
1727 * set suspended flag to avoid triggering a new threaded_irq
1728 * work. no need for spinlock as interrupts are disabled.
1729 */
1730 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1731
1732 wl1271_enable_interrupts(wl);
1733 flush_work(&wl->tx_work);
1734 flush_delayed_work(&wl->pspoll_work);
1735 flush_delayed_work(&wl->elp_work);
1736
Eliad Peller402e48612011-05-13 11:57:09 +03001737 return 0;
1738}
1739
1740static int wl1271_op_resume(struct ieee80211_hw *hw)
1741{
1742 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001743 unsigned long flags;
1744 bool run_irq_work = false;
1745
Eliad Peller402e48612011-05-13 11:57:09 +03001746 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1747 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001748 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001749
1750 /*
1751 * re-enable irq_work enqueuing, and call irq_work directly if
1752 * there is a pending work.
1753 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001754 spin_lock_irqsave(&wl->wl_lock, flags);
1755 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1756 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1757 run_irq_work = true;
1758 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001759
Eliad Peller4a859df2011-06-06 12:21:52 +03001760 if (run_irq_work) {
1761 wl1271_debug(DEBUG_MAC80211,
1762 "run postponed irq_work directly");
1763 wl1271_irq(0, wl);
1764 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001765 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001766 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001767 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001768
Eliad Peller402e48612011-05-13 11:57:09 +03001769 return 0;
1770}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001771#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001772
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001773static int wl1271_op_start(struct ieee80211_hw *hw)
1774{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001775 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1776
1777 /*
1778 * We have to delay the booting of the hardware because
1779 * we need to know the local MAC address before downloading and
1780 * initializing the firmware. The MAC address cannot be changed
1781 * after boot, and without the proper MAC address, the firmware
1782 * will not function properly.
1783 *
1784 * The MAC address is first known when the corresponding interface
1785 * is added. That is where we will initialize the hardware.
1786 */
1787
1788 return 0;
1789}
1790
1791static void wl1271_op_stop(struct ieee80211_hw *hw)
1792{
1793 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1794}
1795
1796static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1797 struct ieee80211_vif *vif)
1798{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001799 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001800 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001801 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001802 int ret = 0;
Eliad Peller71125ab2010-10-28 21:46:43 +02001803 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001804
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001805 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1806 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001807
1808 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001809 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001810 wl1271_debug(DEBUG_MAC80211,
1811 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001812 ret = -EBUSY;
1813 goto out;
1814 }
1815
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001816 /*
1817 * in some very corner case HW recovery scenarios its possible to
1818 * get here before __wl1271_op_remove_interface is complete, so
1819 * opt out if that is the case.
1820 */
1821 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1822 ret = -EBUSY;
1823 goto out;
1824 }
1825
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001826 switch (vif->type) {
1827 case NL80211_IFTYPE_STATION:
1828 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001829 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001830 break;
1831 case NL80211_IFTYPE_ADHOC:
1832 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001833 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001834 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001835 case NL80211_IFTYPE_AP:
1836 wl->bss_type = BSS_TYPE_AP_BSS;
1837 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001838 default:
1839 ret = -EOPNOTSUPP;
1840 goto out;
1841 }
1842
1843 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001844
1845 if (wl->state != WL1271_STATE_OFF) {
1846 wl1271_error("cannot start because not in off state: %d",
1847 wl->state);
1848 ret = -EBUSY;
1849 goto out;
1850 }
1851
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001852 while (retries) {
1853 retries--;
1854 ret = wl1271_chip_wakeup(wl);
1855 if (ret < 0)
1856 goto power_off;
1857
1858 ret = wl1271_boot(wl);
1859 if (ret < 0)
1860 goto power_off;
1861
1862 ret = wl1271_hw_init(wl);
1863 if (ret < 0)
1864 goto irq_disable;
1865
Eliad Peller71125ab2010-10-28 21:46:43 +02001866 booted = true;
1867 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001868
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001869irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001870 mutex_unlock(&wl->mutex);
1871 /* Unlocking the mutex in the middle of handling is
1872 inherently unsafe. In this case we deem it safe to do,
1873 because we need to let any possibly pending IRQ out of
1874 the system (and while we are WL1271_STATE_OFF the IRQ
1875 work function will not do anything.) Also, any other
1876 possible concurrent operations will fail due to the
1877 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001878 wl1271_disable_interrupts(wl);
1879 wl1271_flush_deferred_work(wl);
1880 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001881 mutex_lock(&wl->mutex);
1882power_off:
1883 wl1271_power_off(wl);
1884 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001885
Eliad Peller71125ab2010-10-28 21:46:43 +02001886 if (!booted) {
1887 wl1271_error("firmware boot failed despite %d retries",
1888 WL1271_BOOT_RETRIES);
1889 goto out;
1890 }
1891
1892 wl->vif = vif;
1893 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001894 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001895 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001896
1897 /* update hw/fw version info in wiphy struct */
1898 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001899 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001900 sizeof(wiphy->fw_version));
1901
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001902 /*
1903 * Now we know if 11a is supported (info from the NVS), so disable
1904 * 11a channels if not supported
1905 */
1906 if (!wl->enable_11a)
1907 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1908
1909 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1910 wl->enable_11a ? "" : "not ");
1911
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001912out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001913 mutex_unlock(&wl->mutex);
1914
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001915 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001916 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001917 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001918 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001919
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001920 return ret;
1921}
1922
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001923static void __wl1271_op_remove_interface(struct wl1271 *wl,
1924 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001925{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001926 int i;
1927
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001928 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001929
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001930 /* because of hardware recovery, we may get here twice */
1931 if (wl->state != WL1271_STATE_ON)
1932 return;
1933
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001934 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001935
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001936 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001937 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001938 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001939
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001940 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001941 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001942 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001943
Luciano Coelho08688d62010-07-08 17:50:07 +03001944 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001945 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001946 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001947 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001948 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001949 }
1950
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001951 /*
1952 * this must be before the cancel_work calls below, so that the work
1953 * functions don't perform further work.
1954 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001955 wl->state = WL1271_STATE_OFF;
1956
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001957 mutex_unlock(&wl->mutex);
1958
Ido Yariva6208652011-03-01 15:14:41 +02001959 wl1271_disable_interrupts(wl);
1960 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02001961 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02001962 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001963 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03001964 del_timer_sync(&wl->rx_streaming_timer);
1965 cancel_work_sync(&wl->rx_streaming_enable_work);
1966 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03001967 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001968 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001969
1970 mutex_lock(&wl->mutex);
1971
1972 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001973 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001974 wl1271_power_off(wl);
1975
1976 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02001977 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001978 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001979 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001980 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03001981 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001982
1983 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02001984 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001985 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1986 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03001987 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001988 wl->tx_results_count = 0;
1989 wl->tx_packets_count = 0;
1990 wl->time_offset = 0;
1991 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001992 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001993 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02001994 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02001995 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02001996 wl->ap_fw_ps_map = 0;
1997 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03001998 wl->sched_scanning = false;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03001999
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002000 /*
2001 * this is performed after the cancel_work calls and the associated
2002 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2003 * get executed before all these vars have been reset.
2004 */
2005 wl->flags = 0;
2006
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002007 for (i = 0; i < NUM_TX_QUEUES; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002008 wl->tx_blocks_freed[i] = 0;
2009
2010 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002011
2012 kfree(wl->fw_status);
2013 wl->fw_status = NULL;
2014 kfree(wl->tx_res_if);
2015 wl->tx_res_if = NULL;
2016 kfree(wl->target_mem_map);
2017 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002018}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002019
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002020static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2021 struct ieee80211_vif *vif)
2022{
2023 struct wl1271 *wl = hw->priv;
2024
2025 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002026 /*
2027 * wl->vif can be null here if someone shuts down the interface
2028 * just when hardware recovery has been started.
2029 */
2030 if (wl->vif) {
2031 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002032 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002033 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002034
Juuso Oikarinen67353292010-11-18 15:19:02 +02002035 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002036 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037}
2038
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002039static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002040{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002041 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002042 /* we need to use a dummy BSSID for now */
2043 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
2044 0xad, 0xbe, 0xef };
2045
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002046 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
2047
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002048 ret = wl1271_cmd_join(wl, wl->set_bss_type);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002049 if (ret < 0)
2050 goto out;
2051
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002052 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002053
2054out:
2055 return ret;
2056}
2057
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002058static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002059{
2060 int ret;
2061
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002062 /*
2063 * One of the side effects of the JOIN command is that is clears
2064 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2065 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002066 * Currently the only valid scenario for JOIN during association
2067 * is on roaming, in which case we will also be given new keys.
2068 * Keep the below message for now, unless it starts bothering
2069 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002070 */
2071 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2072 wl1271_info("JOIN while associated.");
2073
2074 if (set_assoc)
2075 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2076
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002077 ret = wl1271_cmd_join(wl, wl->set_bss_type);
2078 if (ret < 0)
2079 goto out;
2080
2081 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2082
2083 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2084 goto out;
2085
2086 /*
2087 * The join command disable the keep-alive mode, shut down its process,
2088 * and also clear the template config, so we need to reset it all after
2089 * the join. The acx_aid starts the keep-alive process, and the order
2090 * of the commands below is relevant.
2091 */
2092 ret = wl1271_acx_keep_alive_mode(wl, true);
2093 if (ret < 0)
2094 goto out;
2095
2096 ret = wl1271_acx_aid(wl, wl->aid);
2097 if (ret < 0)
2098 goto out;
2099
2100 ret = wl1271_cmd_build_klv_null_data(wl);
2101 if (ret < 0)
2102 goto out;
2103
2104 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2105 ACX_KEEP_ALIVE_TPL_VALID);
2106 if (ret < 0)
2107 goto out;
2108
2109out:
2110 return ret;
2111}
2112
2113static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002114{
2115 int ret;
2116
2117 /* to stop listening to a channel, we disconnect */
2118 ret = wl1271_cmd_disconnect(wl);
2119 if (ret < 0)
2120 goto out;
2121
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002122 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002123 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002124
Oz Krakowskib992c682011-06-26 10:36:02 +03002125 /* reset TX security counters on a clean disconnect */
2126 wl->tx_security_last_seq_lsb = 0;
2127 wl->tx_security_seq = 0;
2128
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002129out:
2130 return ret;
2131}
2132
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002133static void wl1271_set_band_rate(struct wl1271 *wl)
2134{
2135 if (wl->band == IEEE80211_BAND_2GHZ)
2136 wl->basic_rate_set = wl->conf.tx.basic_rate;
2137 else
2138 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2139}
2140
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002141static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002142{
2143 int ret;
2144
2145 if (idle) {
2146 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2147 ret = wl1271_unjoin(wl);
2148 if (ret < 0)
2149 goto out;
2150 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002151 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002152 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002153 if (ret < 0)
2154 goto out;
2155 ret = wl1271_acx_keep_alive_config(
2156 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2157 ACX_KEEP_ALIVE_TPL_INVALID);
2158 if (ret < 0)
2159 goto out;
2160 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2161 } else {
2162 /* increment the session counter */
2163 wl->session_counter++;
2164 if (wl->session_counter >= SESSION_COUNTER_MAX)
2165 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002166
2167 /* The current firmware only supports sched_scan in idle */
2168 if (wl->sched_scanning) {
2169 wl1271_scan_sched_scan_stop(wl);
2170 ieee80211_sched_scan_stopped(wl->hw);
2171 }
2172
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002173 ret = wl1271_dummy_join(wl);
2174 if (ret < 0)
2175 goto out;
2176 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2177 }
2178
2179out:
2180 return ret;
2181}
2182
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2184{
2185 struct wl1271 *wl = hw->priv;
2186 struct ieee80211_conf *conf = &hw->conf;
2187 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002188 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002189
2190 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2191
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002192 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2193 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194 channel,
2195 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002196 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002197 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2198 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002200 /*
2201 * mac80211 will go to idle nearly immediately after transmitting some
2202 * frames, such as the deauth. To make sure those frames reach the air,
2203 * wait here until the TX queue is fully flushed.
2204 */
2205 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2206 (conf->flags & IEEE80211_CONF_IDLE))
2207 wl1271_tx_flush(wl);
2208
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002209 mutex_lock(&wl->mutex);
2210
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002211 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002212 /* we support configuring the channel and band while off */
2213 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2214 wl->band = conf->channel->band;
2215 wl->channel = channel;
2216 }
2217
Arik Nemtsov097f8822011-06-27 22:06:34 +03002218 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2219 wl->power_level = conf->power_level;
2220
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002221 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002222 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002223
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002224 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2225
Ido Yariva6208652011-03-01 15:14:41 +02002226 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002227 if (ret < 0)
2228 goto out;
2229
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002230 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002231 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2232 ((wl->band != conf->channel->band) ||
2233 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002234 wl->band = conf->channel->band;
2235 wl->channel = channel;
2236
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002237 if (!is_ap) {
2238 /*
2239 * FIXME: the mac80211 should really provide a fixed
2240 * rate to use here. for now, just use the smallest
2241 * possible rate for the band as a fixed rate for
2242 * association frames and other control messages.
2243 */
2244 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2245 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002246
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002247 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2248 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002249 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002250 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002251 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002252
2253 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2254 ret = wl1271_join(wl, false);
2255 if (ret < 0)
2256 wl1271_warning("cmd join on channel "
2257 "failed %d", ret);
2258 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002259 }
2260 }
2261
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002262 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2263 ret = wl1271_sta_handle_idle(wl,
2264 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002265 if (ret < 0)
2266 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002267 }
2268
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002269 /*
2270 * if mac80211 changes the PSM mode, make sure the mode is not
2271 * incorrectly changed after the pspoll failure active window.
2272 */
2273 if (changed & IEEE80211_CONF_CHANGE_PS)
2274 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2275
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002276 if (conf->flags & IEEE80211_CONF_PS &&
2277 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2278 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279
2280 /*
2281 * We enter PSM only if we're already associated.
2282 * If we're not, we'll enter it when joining an SSID,
2283 * through the bss_info_changed() hook.
2284 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002285 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002286 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002287 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002288 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002289 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002290 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002291 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002292 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002293
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002294 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002296 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002297 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002298 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002299 }
2300
2301 if (conf->power_level != wl->power_level) {
2302 ret = wl1271_acx_tx_power(wl, conf->power_level);
2303 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002304 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002305
2306 wl->power_level = conf->power_level;
2307 }
2308
2309out_sleep:
2310 wl1271_ps_elp_sleep(wl);
2311
2312out:
2313 mutex_unlock(&wl->mutex);
2314
2315 return ret;
2316}
2317
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002318struct wl1271_filter_params {
2319 bool enabled;
2320 int mc_list_length;
2321 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2322};
2323
Jiri Pirko22bedad2010-04-01 21:22:57 +00002324static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2325 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002326{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002327 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002328 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002329 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002330
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002331 if (unlikely(wl->state == WL1271_STATE_OFF))
2332 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002333
Juuso Oikarinen74441132009-10-13 12:47:53 +03002334 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002335 if (!fp) {
2336 wl1271_error("Out of memory setting filters.");
2337 return 0;
2338 }
2339
2340 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002341 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002342 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2343 fp->enabled = false;
2344 } else {
2345 fp->enabled = true;
2346 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002347 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002348 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002349 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002350 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002351 }
2352
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002353 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002354}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002355
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002356#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2357 FIF_ALLMULTI | \
2358 FIF_FCSFAIL | \
2359 FIF_BCN_PRBRESP_PROMISC | \
2360 FIF_CONTROL | \
2361 FIF_OTHER_BSS)
2362
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002363static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2364 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002365 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002367 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002368 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002369 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370
Arik Nemtsov7d057862010-10-16 19:25:35 +02002371 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2372 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002374 mutex_lock(&wl->mutex);
2375
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002376 *total &= WL1271_SUPPORTED_FILTERS;
2377 changed &= WL1271_SUPPORTED_FILTERS;
2378
2379 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002380 goto out;
2381
Ido Yariva6208652011-03-01 15:14:41 +02002382 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002383 if (ret < 0)
2384 goto out;
2385
Arik Nemtsov7d057862010-10-16 19:25:35 +02002386 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2387 if (*total & FIF_ALLMULTI)
2388 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2389 else if (fp)
2390 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2391 fp->mc_list,
2392 fp->mc_list_length);
2393 if (ret < 0)
2394 goto out_sleep;
2395 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002396
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002397 /*
2398 * the fw doesn't provide an api to configure the filters. instead,
2399 * the filters configuration is based on the active roles / ROC
2400 * state.
2401 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002402
2403out_sleep:
2404 wl1271_ps_elp_sleep(wl);
2405
2406out:
2407 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002408 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002409}
2410
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002411static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2412 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2413 u16 tx_seq_16)
2414{
2415 struct wl1271_ap_key *ap_key;
2416 int i;
2417
2418 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2419
2420 if (key_size > MAX_KEY_SIZE)
2421 return -EINVAL;
2422
2423 /*
2424 * Find next free entry in ap_keys. Also check we are not replacing
2425 * an existing key.
2426 */
2427 for (i = 0; i < MAX_NUM_KEYS; i++) {
2428 if (wl->recorded_ap_keys[i] == NULL)
2429 break;
2430
2431 if (wl->recorded_ap_keys[i]->id == id) {
2432 wl1271_warning("trying to record key replacement");
2433 return -EINVAL;
2434 }
2435 }
2436
2437 if (i == MAX_NUM_KEYS)
2438 return -EBUSY;
2439
2440 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2441 if (!ap_key)
2442 return -ENOMEM;
2443
2444 ap_key->id = id;
2445 ap_key->key_type = key_type;
2446 ap_key->key_size = key_size;
2447 memcpy(ap_key->key, key, key_size);
2448 ap_key->hlid = hlid;
2449 ap_key->tx_seq_32 = tx_seq_32;
2450 ap_key->tx_seq_16 = tx_seq_16;
2451
2452 wl->recorded_ap_keys[i] = ap_key;
2453 return 0;
2454}
2455
2456static void wl1271_free_ap_keys(struct wl1271 *wl)
2457{
2458 int i;
2459
2460 for (i = 0; i < MAX_NUM_KEYS; i++) {
2461 kfree(wl->recorded_ap_keys[i]);
2462 wl->recorded_ap_keys[i] = NULL;
2463 }
2464}
2465
2466static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2467{
2468 int i, ret = 0;
2469 struct wl1271_ap_key *key;
2470 bool wep_key_added = false;
2471
2472 for (i = 0; i < MAX_NUM_KEYS; i++) {
2473 if (wl->recorded_ap_keys[i] == NULL)
2474 break;
2475
2476 key = wl->recorded_ap_keys[i];
2477 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2478 key->id, key->key_type,
2479 key->key_size, key->key,
2480 key->hlid, key->tx_seq_32,
2481 key->tx_seq_16);
2482 if (ret < 0)
2483 goto out;
2484
2485 if (key->key_type == KEY_WEP)
2486 wep_key_added = true;
2487 }
2488
2489 if (wep_key_added) {
2490 ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key);
2491 if (ret < 0)
2492 goto out;
2493 }
2494
2495out:
2496 wl1271_free_ap_keys(wl);
2497 return ret;
2498}
2499
2500static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2501 u8 key_size, const u8 *key, u32 tx_seq_32,
2502 u16 tx_seq_16, struct ieee80211_sta *sta)
2503{
2504 int ret;
2505 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2506
2507 if (is_ap) {
2508 struct wl1271_station *wl_sta;
2509 u8 hlid;
2510
2511 if (sta) {
2512 wl_sta = (struct wl1271_station *)sta->drv_priv;
2513 hlid = wl_sta->hlid;
2514 } else {
2515 hlid = WL1271_AP_BROADCAST_HLID;
2516 }
2517
2518 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2519 /*
2520 * We do not support removing keys after AP shutdown.
2521 * Pretend we do to make mac80211 happy.
2522 */
2523 if (action != KEY_ADD_OR_REPLACE)
2524 return 0;
2525
2526 ret = wl1271_record_ap_key(wl, id,
2527 key_type, key_size,
2528 key, hlid, tx_seq_32,
2529 tx_seq_16);
2530 } else {
2531 ret = wl1271_cmd_set_ap_key(wl, action,
2532 id, key_type, key_size,
2533 key, hlid, tx_seq_32,
2534 tx_seq_16);
2535 }
2536
2537 if (ret < 0)
2538 return ret;
2539 } else {
2540 const u8 *addr;
2541 static const u8 bcast_addr[ETH_ALEN] = {
2542 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2543 };
2544
2545 addr = sta ? sta->addr : bcast_addr;
2546
2547 if (is_zero_ether_addr(addr)) {
2548 /* We dont support TX only encryption */
2549 return -EOPNOTSUPP;
2550 }
2551
2552 /* The wl1271 does not allow to remove unicast keys - they
2553 will be cleared automatically on next CMD_JOIN. Ignore the
2554 request silently, as we dont want the mac80211 to emit
2555 an error message. */
2556 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2557 return 0;
2558
2559 ret = wl1271_cmd_set_sta_key(wl, action,
2560 id, key_type, key_size,
2561 key, addr, tx_seq_32,
2562 tx_seq_16);
2563 if (ret < 0)
2564 return ret;
2565
2566 /* the default WEP key needs to be configured at least once */
2567 if (key_type == KEY_WEP) {
2568 ret = wl1271_cmd_set_sta_default_wep_key(wl,
2569 wl->default_key);
2570 if (ret < 0)
2571 return ret;
2572 }
2573 }
2574
2575 return 0;
2576}
2577
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2579 struct ieee80211_vif *vif,
2580 struct ieee80211_sta *sta,
2581 struct ieee80211_key_conf *key_conf)
2582{
2583 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002584 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002585 u32 tx_seq_32 = 0;
2586 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002587 u8 key_type;
2588
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002589 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2590
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002591 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002592 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002593 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002594 key_conf->keylen, key_conf->flags);
2595 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2596
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002597 mutex_lock(&wl->mutex);
2598
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002599 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2600 ret = -EAGAIN;
2601 goto out_unlock;
2602 }
2603
Ido Yariva6208652011-03-01 15:14:41 +02002604 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002605 if (ret < 0)
2606 goto out_unlock;
2607
Johannes Berg97359d12010-08-10 09:46:38 +02002608 switch (key_conf->cipher) {
2609 case WLAN_CIPHER_SUITE_WEP40:
2610 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002611 key_type = KEY_WEP;
2612
2613 key_conf->hw_key_idx = key_conf->keyidx;
2614 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002615 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002616 key_type = KEY_TKIP;
2617
2618 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002619 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2620 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002621 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002622 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002623 key_type = KEY_AES;
2624
2625 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002626 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2627 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002628 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002629 case WL1271_CIPHER_SUITE_GEM:
2630 key_type = KEY_GEM;
2631 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2632 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2633 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002634 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002635 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002636
2637 ret = -EOPNOTSUPP;
2638 goto out_sleep;
2639 }
2640
2641 switch (cmd) {
2642 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002643 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2644 key_conf->keyidx, key_type,
2645 key_conf->keylen, key_conf->key,
2646 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002647 if (ret < 0) {
2648 wl1271_error("Could not add or replace key");
2649 goto out_sleep;
2650 }
2651 break;
2652
2653 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002654 ret = wl1271_set_key(wl, KEY_REMOVE,
2655 key_conf->keyidx, key_type,
2656 key_conf->keylen, key_conf->key,
2657 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658 if (ret < 0) {
2659 wl1271_error("Could not remove key");
2660 goto out_sleep;
2661 }
2662 break;
2663
2664 default:
2665 wl1271_error("Unsupported key cmd 0x%x", cmd);
2666 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667 break;
2668 }
2669
2670out_sleep:
2671 wl1271_ps_elp_sleep(wl);
2672
2673out_unlock:
2674 mutex_unlock(&wl->mutex);
2675
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002676 return ret;
2677}
2678
2679static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002680 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681 struct cfg80211_scan_request *req)
2682{
2683 struct wl1271 *wl = hw->priv;
2684 int ret;
2685 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002686 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687
2688 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2689
2690 if (req->n_ssids) {
2691 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002692 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693 }
2694
2695 mutex_lock(&wl->mutex);
2696
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002697 if (wl->state == WL1271_STATE_OFF) {
2698 /*
2699 * We cannot return -EBUSY here because cfg80211 will expect
2700 * a call to ieee80211_scan_completed if we do - in this case
2701 * there won't be any call.
2702 */
2703 ret = -EAGAIN;
2704 goto out;
2705 }
2706
Ido Yariva6208652011-03-01 15:14:41 +02002707 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002708 if (ret < 0)
2709 goto out;
2710
Luciano Coelho5924f892010-08-04 03:46:22 +03002711 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712
2713 wl1271_ps_elp_sleep(wl);
2714
2715out:
2716 mutex_unlock(&wl->mutex);
2717
2718 return ret;
2719}
2720
Eliad Peller73ecce32011-06-27 13:06:45 +03002721static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2722 struct ieee80211_vif *vif)
2723{
2724 struct wl1271 *wl = hw->priv;
2725 int ret;
2726
2727 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2728
2729 mutex_lock(&wl->mutex);
2730
2731 if (wl->state == WL1271_STATE_OFF)
2732 goto out;
2733
2734 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2735 goto out;
2736
2737 ret = wl1271_ps_elp_wakeup(wl);
2738 if (ret < 0)
2739 goto out;
2740
2741 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2742 ret = wl1271_scan_stop(wl);
2743 if (ret < 0)
2744 goto out_sleep;
2745 }
2746 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2747 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2748 wl->scan.req = NULL;
2749 ieee80211_scan_completed(wl->hw, true);
2750
2751out_sleep:
2752 wl1271_ps_elp_sleep(wl);
2753out:
2754 mutex_unlock(&wl->mutex);
2755
2756 cancel_delayed_work_sync(&wl->scan_complete_work);
2757}
2758
Luciano Coelho33c2c062011-05-10 14:46:02 +03002759static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2760 struct ieee80211_vif *vif,
2761 struct cfg80211_sched_scan_request *req,
2762 struct ieee80211_sched_scan_ies *ies)
2763{
2764 struct wl1271 *wl = hw->priv;
2765 int ret;
2766
2767 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2768
2769 mutex_lock(&wl->mutex);
2770
2771 ret = wl1271_ps_elp_wakeup(wl);
2772 if (ret < 0)
2773 goto out;
2774
2775 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2776 if (ret < 0)
2777 goto out_sleep;
2778
2779 ret = wl1271_scan_sched_scan_start(wl);
2780 if (ret < 0)
2781 goto out_sleep;
2782
2783 wl->sched_scanning = true;
2784
2785out_sleep:
2786 wl1271_ps_elp_sleep(wl);
2787out:
2788 mutex_unlock(&wl->mutex);
2789 return ret;
2790}
2791
2792static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2793 struct ieee80211_vif *vif)
2794{
2795 struct wl1271 *wl = hw->priv;
2796 int ret;
2797
2798 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2799
2800 mutex_lock(&wl->mutex);
2801
2802 ret = wl1271_ps_elp_wakeup(wl);
2803 if (ret < 0)
2804 goto out;
2805
2806 wl1271_scan_sched_scan_stop(wl);
2807
2808 wl1271_ps_elp_sleep(wl);
2809out:
2810 mutex_unlock(&wl->mutex);
2811}
2812
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002813static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2814{
2815 struct wl1271 *wl = hw->priv;
2816 int ret = 0;
2817
2818 mutex_lock(&wl->mutex);
2819
2820 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2821 ret = -EAGAIN;
2822 goto out;
2823 }
2824
Ido Yariva6208652011-03-01 15:14:41 +02002825 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002826 if (ret < 0)
2827 goto out;
2828
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002829 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002830 if (ret < 0)
2831 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2832
2833 wl1271_ps_elp_sleep(wl);
2834
2835out:
2836 mutex_unlock(&wl->mutex);
2837
2838 return ret;
2839}
2840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002841static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2842{
2843 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002844 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002845
2846 mutex_lock(&wl->mutex);
2847
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002848 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2849 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002850 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002851 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002852
Ido Yariva6208652011-03-01 15:14:41 +02002853 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002854 if (ret < 0)
2855 goto out;
2856
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002857 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002858 if (ret < 0)
2859 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2860
2861 wl1271_ps_elp_sleep(wl);
2862
2863out:
2864 mutex_unlock(&wl->mutex);
2865
2866 return ret;
2867}
2868
Arik Nemtsove78a2872010-10-16 19:07:21 +02002869static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002870 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002871{
Eliad Peller889cb362011-05-01 09:56:45 +03002872 u8 ssid_len;
2873 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2874 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002875
Eliad Peller889cb362011-05-01 09:56:45 +03002876 if (!ptr) {
2877 wl1271_error("No SSID in IEs!");
2878 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002879 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002880
Eliad Peller889cb362011-05-01 09:56:45 +03002881 ssid_len = ptr[1];
2882 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2883 wl1271_error("SSID is too long!");
2884 return -EINVAL;
2885 }
2886
2887 wl->ssid_len = ssid_len;
2888 memcpy(wl->ssid, ptr+2, ssid_len);
2889 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002890}
2891
Arik Nemtsove78a2872010-10-16 19:07:21 +02002892static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2893 struct ieee80211_bss_conf *bss_conf,
2894 u32 changed)
2895{
2896 int ret = 0;
2897
2898 if (changed & BSS_CHANGED_ERP_SLOT) {
2899 if (bss_conf->use_short_slot)
2900 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2901 else
2902 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2903 if (ret < 0) {
2904 wl1271_warning("Set slot time failed %d", ret);
2905 goto out;
2906 }
2907 }
2908
2909 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2910 if (bss_conf->use_short_preamble)
2911 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2912 else
2913 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2914 }
2915
2916 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2917 if (bss_conf->use_cts_prot)
2918 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2919 else
2920 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2921 if (ret < 0) {
2922 wl1271_warning("Set ctsprotect failed %d", ret);
2923 goto out;
2924 }
2925 }
2926
2927out:
2928 return ret;
2929}
2930
2931static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
2932 struct ieee80211_vif *vif,
2933 struct ieee80211_bss_conf *bss_conf,
2934 u32 changed)
2935{
2936 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2937 int ret = 0;
2938
2939 if ((changed & BSS_CHANGED_BEACON_INT)) {
2940 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
2941 bss_conf->beacon_int);
2942
2943 wl->beacon_int = bss_conf->beacon_int;
2944 }
2945
2946 if ((changed & BSS_CHANGED_BEACON)) {
2947 struct ieee80211_hdr *hdr;
2948 int ieoffset = offsetof(struct ieee80211_mgmt,
2949 u.beacon.variable);
2950 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
2951 u16 tmpl_id;
2952
2953 if (!beacon)
2954 goto out;
2955
2956 wl1271_debug(DEBUG_MASTER, "beacon updated");
2957
2958 ret = wl1271_ssid_set(wl, beacon, ieoffset);
2959 if (ret < 0) {
2960 dev_kfree_skb(beacon);
2961 goto out;
2962 }
2963 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
2964 CMD_TEMPL_BEACON;
2965 ret = wl1271_cmd_template_set(wl, tmpl_id,
2966 beacon->data,
2967 beacon->len, 0,
2968 wl1271_tx_min_rate_get(wl));
2969 if (ret < 0) {
2970 dev_kfree_skb(beacon);
2971 goto out;
2972 }
2973
2974 hdr = (struct ieee80211_hdr *) beacon->data;
2975 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2976 IEEE80211_STYPE_PROBE_RESP);
2977
2978 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
2979 CMD_TEMPL_PROBE_RESPONSE;
2980 ret = wl1271_cmd_template_set(wl,
2981 tmpl_id,
2982 beacon->data,
2983 beacon->len, 0,
2984 wl1271_tx_min_rate_get(wl));
2985 dev_kfree_skb(beacon);
2986 if (ret < 0)
2987 goto out;
2988 }
2989
2990out:
2991 return ret;
2992}
2993
2994/* AP mode changes */
2995static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 struct ieee80211_vif *vif,
2997 struct ieee80211_bss_conf *bss_conf,
2998 u32 changed)
2999{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003000 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003001
Arik Nemtsove78a2872010-10-16 19:07:21 +02003002 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3003 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003004
Arik Nemtsove78a2872010-10-16 19:07:21 +02003005 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3006 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003007
Arik Nemtsov70f47422011-04-18 14:15:25 +03003008 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003009 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003010 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003011 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003012 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003013
3014 ret = wl1271_ap_init_templates(wl);
3015 if (ret < 0)
3016 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003017 }
3018
Arik Nemtsove78a2872010-10-16 19:07:21 +02003019 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3020 if (ret < 0)
3021 goto out;
3022
3023 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3024 if (bss_conf->enable_beacon) {
3025 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
3026 ret = wl1271_cmd_start_bss(wl);
3027 if (ret < 0)
3028 goto out;
3029
3030 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3031 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003032
3033 ret = wl1271_ap_init_hwenc(wl);
3034 if (ret < 0)
3035 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003036 }
3037 } else {
3038 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
3039 ret = wl1271_cmd_stop_bss(wl);
3040 if (ret < 0)
3041 goto out;
3042
3043 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3044 wl1271_debug(DEBUG_AP, "stopped AP");
3045 }
3046 }
3047 }
3048
3049 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3050 if (ret < 0)
3051 goto out;
3052out:
3053 return;
3054}
3055
3056/* STA/IBSS mode changes */
3057static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3058 struct ieee80211_vif *vif,
3059 struct ieee80211_bss_conf *bss_conf,
3060 u32 changed)
3061{
3062 bool do_join = false, set_assoc = false;
3063 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003064 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003065 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003066 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003067 bool sta_exists = false;
3068 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003069
3070 if (is_ibss) {
3071 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3072 changed);
3073 if (ret < 0)
3074 goto out;
3075 }
3076
3077 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
3078 do_join = true;
3079
3080 /* Need to update the SSID (for filtering etc) */
3081 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
3082 do_join = true;
3083
3084 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003085 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3086 bss_conf->enable_beacon ? "enabled" : "disabled");
3087
3088 if (bss_conf->enable_beacon)
3089 wl->set_bss_type = BSS_TYPE_IBSS;
3090 else
3091 wl->set_bss_type = BSS_TYPE_STA_BSS;
3092 do_join = true;
3093 }
3094
Arik Nemtsove78a2872010-10-16 19:07:21 +02003095 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003096 bool enable = false;
3097 if (bss_conf->cqm_rssi_thold)
3098 enable = true;
3099 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3100 bss_conf->cqm_rssi_thold,
3101 bss_conf->cqm_rssi_hyst);
3102 if (ret < 0)
3103 goto out;
3104 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3105 }
3106
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003107 if ((changed & BSS_CHANGED_BSSID) &&
3108 /*
3109 * Now we know the correct bssid, so we send a new join command
3110 * and enable the BSSID filter
3111 */
3112 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003113 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003114
Eliad Pellerfa287b82010-12-26 09:27:50 +01003115 if (!is_zero_ether_addr(wl->bssid)) {
3116 ret = wl1271_cmd_build_null_data(wl);
3117 if (ret < 0)
3118 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003119
Eliad Pellerfa287b82010-12-26 09:27:50 +01003120 ret = wl1271_build_qos_null_data(wl);
3121 if (ret < 0)
3122 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003123
Eliad Pellerfa287b82010-12-26 09:27:50 +01003124 /* Need to update the BSSID (for filtering etc) */
3125 do_join = true;
3126 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003127 }
3128
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003129 rcu_read_lock();
3130 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3131 if (sta) {
3132 /* save the supp_rates of the ap */
3133 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3134 if (sta->ht_cap.ht_supported)
3135 sta_rate_set |=
3136 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003137 sta_ht_cap = sta->ht_cap;
3138 sta_exists = true;
3139 }
3140 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003141
Arik Nemtsova1008852011-02-12 23:24:20 +02003142 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003143 /* handle new association with HT and HT information change */
3144 if ((changed & BSS_CHANGED_HT) &&
3145 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003146 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003147 true);
3148 if (ret < 0) {
3149 wl1271_warning("Set ht cap true failed %d",
3150 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003151 goto out;
3152 }
3153 ret = wl1271_acx_set_ht_information(wl,
3154 bss_conf->ht_operation_mode);
3155 if (ret < 0) {
3156 wl1271_warning("Set ht information failed %d",
3157 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003158 goto out;
3159 }
3160 }
3161 /* handle new association without HT and disassociation */
3162 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003163 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003164 false);
3165 if (ret < 0) {
3166 wl1271_warning("Set ht cap false failed %d",
3167 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003168 goto out;
3169 }
3170 }
3171 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003172
Arik Nemtsove78a2872010-10-16 19:07:21 +02003173 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003174 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003175 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003176 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003178 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003179
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003180 wl->ps_poll_failures = 0;
3181
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003182 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003183 * use basic rates from AP, and determine lowest rate
3184 * to use with control frames.
3185 */
3186 rates = bss_conf->basic_rates;
3187 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3188 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003189 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003190 if (sta_rate_set)
3191 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3192 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003193 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003194 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003195 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003196
3197 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003198 * with wl1271, we don't need to update the
3199 * beacon_int and dtim_period, because the firmware
3200 * updates it by itself when the first beacon is
3201 * received after a join.
3202 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003203 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3204 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003205 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003206
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003207 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003208 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003209 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003210 dev_kfree_skb(wl->probereq);
3211 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3212 ieoffset = offsetof(struct ieee80211_mgmt,
3213 u.probe_req.variable);
3214 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003215
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003216 /* enable the connection monitoring feature */
3217 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003219 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003220
3221 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003222 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3223 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003224 enum wl1271_cmd_ps_mode mode;
3225
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003226 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003227 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003228 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003229 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003230 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003231 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003233 } else {
3234 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003235 bool was_assoc =
3236 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3237 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003238 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003239 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003240
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003241 /* free probe-request template */
3242 dev_kfree_skb(wl->probereq);
3243 wl->probereq = NULL;
3244
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003245 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003246 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003247
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003248 /* revert back to minimum rates for the current band */
3249 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003250 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003251 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003252 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003253 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003254
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003255 /* disable connection monitor features */
3256 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003257
3258 /* Disable the keep-alive feature */
3259 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003260 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003261 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003262
3263 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003264 if (was_assoc) {
3265 wl1271_unjoin(wl);
3266 wl1271_dummy_join(wl);
3267 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003268 }
3269 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003270
Eliad Pellerd192d262011-05-24 14:33:08 +03003271 if (changed & BSS_CHANGED_IBSS) {
3272 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3273 bss_conf->ibss_joined);
3274
3275 if (bss_conf->ibss_joined) {
3276 u32 rates = bss_conf->basic_rates;
3277 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3278 rates);
3279 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3280
3281 /* by default, use 11b rates */
3282 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3283 ret = wl1271_acx_sta_rate_policies(wl);
3284 if (ret < 0)
3285 goto out;
3286 }
3287 }
3288
Arik Nemtsove78a2872010-10-16 19:07:21 +02003289 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3290 if (ret < 0)
3291 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003292
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003293 if (changed & BSS_CHANGED_ARP_FILTER) {
3294 __be32 addr = bss_conf->arp_addr_list[0];
3295 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3296
Eliad Pellerc5312772010-12-09 11:31:27 +02003297 if (bss_conf->arp_addr_cnt == 1 &&
3298 bss_conf->arp_filter_enabled) {
3299 /*
3300 * The template should have been configured only upon
3301 * association. however, it seems that the correct ip
3302 * isn't being set (when sending), so we have to
3303 * reconfigure the template upon every ip change.
3304 */
3305 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3306 if (ret < 0) {
3307 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003308 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003309 }
3310
3311 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003312 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003313 addr);
3314 } else
3315 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003316
3317 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003318 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003319 }
3320
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003321 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003322 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003323 if (ret < 0) {
3324 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003325 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003326 }
Eliad Pelleref4b29e2011-06-06 13:03:12 +03003327 wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003328 }
3329
Arik Nemtsove78a2872010-10-16 19:07:21 +02003330out:
3331 return;
3332}
3333
3334static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3335 struct ieee80211_vif *vif,
3336 struct ieee80211_bss_conf *bss_conf,
3337 u32 changed)
3338{
3339 struct wl1271 *wl = hw->priv;
3340 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3341 int ret;
3342
3343 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3344 (int)changed);
3345
3346 mutex_lock(&wl->mutex);
3347
3348 if (unlikely(wl->state == WL1271_STATE_OFF))
3349 goto out;
3350
Ido Yariva6208652011-03-01 15:14:41 +02003351 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003352 if (ret < 0)
3353 goto out;
3354
3355 if (is_ap)
3356 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3357 else
3358 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3359
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003360 wl1271_ps_elp_sleep(wl);
3361
3362out:
3363 mutex_unlock(&wl->mutex);
3364}
3365
Kalle Valoc6999d82010-02-18 13:25:41 +02003366static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3367 const struct ieee80211_tx_queue_params *params)
3368{
3369 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003370 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003371 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003372
3373 mutex_lock(&wl->mutex);
3374
3375 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3376
Kalle Valo4695dc92010-03-18 12:26:38 +02003377 if (params->uapsd)
3378 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3379 else
3380 ps_scheme = CONF_PS_SCHEME_LEGACY;
3381
Arik Nemtsov488fc542010-10-16 20:33:45 +02003382 if (wl->state == WL1271_STATE_OFF) {
3383 /*
3384 * If the state is off, the parameters will be recorded and
3385 * configured on init. This happens in AP-mode.
3386 */
3387 struct conf_tx_ac_category *conf_ac =
3388 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3389 struct conf_tx_tid *conf_tid =
3390 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3391
3392 conf_ac->ac = wl1271_tx_get_queue(queue);
3393 conf_ac->cw_min = (u8)params->cw_min;
3394 conf_ac->cw_max = params->cw_max;
3395 conf_ac->aifsn = params->aifs;
3396 conf_ac->tx_op_limit = params->txop << 5;
3397
3398 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3399 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3400 conf_tid->tsid = wl1271_tx_get_queue(queue);
3401 conf_tid->ps_scheme = ps_scheme;
3402 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3403 conf_tid->apsd_conf[0] = 0;
3404 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003405 goto out;
3406 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003407
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003408 ret = wl1271_ps_elp_wakeup(wl);
3409 if (ret < 0)
3410 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003411
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003412 /*
3413 * the txop is confed in units of 32us by the mac80211,
3414 * we need us
3415 */
3416 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3417 params->cw_min, params->cw_max,
3418 params->aifs, params->txop << 5);
3419 if (ret < 0)
3420 goto out_sleep;
3421
3422 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3423 CONF_CHANNEL_TYPE_EDCF,
3424 wl1271_tx_get_queue(queue),
3425 ps_scheme, CONF_ACK_POLICY_LEGACY,
3426 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003427
3428out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003429 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003430
3431out:
3432 mutex_unlock(&wl->mutex);
3433
3434 return ret;
3435}
3436
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003437static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3438{
3439
3440 struct wl1271 *wl = hw->priv;
3441 u64 mactime = ULLONG_MAX;
3442 int ret;
3443
3444 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3445
3446 mutex_lock(&wl->mutex);
3447
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003448 if (unlikely(wl->state == WL1271_STATE_OFF))
3449 goto out;
3450
Ido Yariva6208652011-03-01 15:14:41 +02003451 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003452 if (ret < 0)
3453 goto out;
3454
3455 ret = wl1271_acx_tsf_info(wl, &mactime);
3456 if (ret < 0)
3457 goto out_sleep;
3458
3459out_sleep:
3460 wl1271_ps_elp_sleep(wl);
3461
3462out:
3463 mutex_unlock(&wl->mutex);
3464 return mactime;
3465}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003466
John W. Linvilleece550d2010-07-28 16:41:06 -04003467static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3468 struct survey_info *survey)
3469{
3470 struct wl1271 *wl = hw->priv;
3471 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003472
John W. Linvilleece550d2010-07-28 16:41:06 -04003473 if (idx != 0)
3474 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003475
John W. Linvilleece550d2010-07-28 16:41:06 -04003476 survey->channel = conf->channel;
3477 survey->filled = SURVEY_INFO_NOISE_DBM;
3478 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003479
John W. Linvilleece550d2010-07-28 16:41:06 -04003480 return 0;
3481}
3482
Arik Nemtsov409622e2011-02-23 00:22:29 +02003483static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003484 struct ieee80211_sta *sta,
3485 u8 *hlid)
3486{
3487 struct wl1271_station *wl_sta;
3488 int id;
3489
3490 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3491 if (id >= AP_MAX_STATIONS) {
3492 wl1271_warning("could not allocate HLID - too much stations");
3493 return -EBUSY;
3494 }
3495
3496 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003497 __set_bit(id, wl->ap_hlid_map);
3498 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3499 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003500 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003501 return 0;
3502}
3503
Arik Nemtsov409622e2011-02-23 00:22:29 +02003504static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003505{
3506 int id = hlid - WL1271_AP_STA_HLID_START;
3507
Arik Nemtsov409622e2011-02-23 00:22:29 +02003508 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3509 return;
3510
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003511 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003512 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003513 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003514 __clear_bit(hlid, &wl->ap_ps_map);
3515 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003516}
3517
Arik Nemtsov3618f302011-06-26 10:36:03 +03003518bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3519{
3520 int id = hlid - WL1271_AP_STA_HLID_START;
3521 return test_bit(id, wl->ap_hlid_map);
3522}
3523
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003524static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3525 struct ieee80211_vif *vif,
3526 struct ieee80211_sta *sta)
3527{
3528 struct wl1271 *wl = hw->priv;
3529 int ret = 0;
3530 u8 hlid;
3531
3532 mutex_lock(&wl->mutex);
3533
3534 if (unlikely(wl->state == WL1271_STATE_OFF))
3535 goto out;
3536
3537 if (wl->bss_type != BSS_TYPE_AP_BSS)
3538 goto out;
3539
3540 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3541
Arik Nemtsov409622e2011-02-23 00:22:29 +02003542 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003543 if (ret < 0)
3544 goto out;
3545
Ido Yariva6208652011-03-01 15:14:41 +02003546 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003547 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003548 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003549
3550 ret = wl1271_cmd_add_sta(wl, sta, hlid);
3551 if (ret < 0)
3552 goto out_sleep;
3553
3554out_sleep:
3555 wl1271_ps_elp_sleep(wl);
3556
Arik Nemtsov409622e2011-02-23 00:22:29 +02003557out_free_sta:
3558 if (ret < 0)
3559 wl1271_free_sta(wl, hlid);
3560
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003561out:
3562 mutex_unlock(&wl->mutex);
3563 return ret;
3564}
3565
3566static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3567 struct ieee80211_vif *vif,
3568 struct ieee80211_sta *sta)
3569{
3570 struct wl1271 *wl = hw->priv;
3571 struct wl1271_station *wl_sta;
3572 int ret = 0, id;
3573
3574 mutex_lock(&wl->mutex);
3575
3576 if (unlikely(wl->state == WL1271_STATE_OFF))
3577 goto out;
3578
3579 if (wl->bss_type != BSS_TYPE_AP_BSS)
3580 goto out;
3581
3582 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3583
3584 wl_sta = (struct wl1271_station *)sta->drv_priv;
3585 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3586 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3587 goto out;
3588
Ido Yariva6208652011-03-01 15:14:41 +02003589 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003590 if (ret < 0)
3591 goto out;
3592
3593 ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid);
3594 if (ret < 0)
3595 goto out_sleep;
3596
Arik Nemtsov409622e2011-02-23 00:22:29 +02003597 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003598
3599out_sleep:
3600 wl1271_ps_elp_sleep(wl);
3601
3602out:
3603 mutex_unlock(&wl->mutex);
3604 return ret;
3605}
3606
Luciano Coelho4623ec72011-03-21 19:26:41 +02003607static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3608 struct ieee80211_vif *vif,
3609 enum ieee80211_ampdu_mlme_action action,
3610 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3611 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003612{
3613 struct wl1271 *wl = hw->priv;
3614 int ret;
3615
3616 mutex_lock(&wl->mutex);
3617
3618 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3619 ret = -EAGAIN;
3620 goto out;
3621 }
3622
Ido Yariva6208652011-03-01 15:14:41 +02003623 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003624 if (ret < 0)
3625 goto out;
3626
Shahar Levi70559a02011-05-22 16:10:22 +03003627 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3628 tid, action);
3629
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003630 switch (action) {
3631 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003632 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003633 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3634 true);
3635 if (!ret)
3636 wl->ba_rx_bitmap |= BIT(tid);
3637 } else {
3638 ret = -ENOTSUPP;
3639 }
3640 break;
3641
3642 case IEEE80211_AMPDU_RX_STOP:
3643 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3644 if (!ret)
3645 wl->ba_rx_bitmap &= ~BIT(tid);
3646 break;
3647
3648 /*
3649 * The BA initiator session management in FW independently.
3650 * Falling break here on purpose for all TX APDU commands.
3651 */
3652 case IEEE80211_AMPDU_TX_START:
3653 case IEEE80211_AMPDU_TX_STOP:
3654 case IEEE80211_AMPDU_TX_OPERATIONAL:
3655 ret = -EINVAL;
3656 break;
3657
3658 default:
3659 wl1271_error("Incorrect ampdu action id=%x\n", action);
3660 ret = -EINVAL;
3661 }
3662
3663 wl1271_ps_elp_sleep(wl);
3664
3665out:
3666 mutex_unlock(&wl->mutex);
3667
3668 return ret;
3669}
3670
Arik Nemtsov33437892011-04-26 23:35:39 +03003671static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3672{
3673 struct wl1271 *wl = hw->priv;
3674 bool ret = false;
3675
3676 mutex_lock(&wl->mutex);
3677
3678 if (unlikely(wl->state == WL1271_STATE_OFF))
3679 goto out;
3680
3681 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003682 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003683
3684 /* the above is appropriate for STA mode for PS purposes */
3685 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3686
3687out:
3688 mutex_unlock(&wl->mutex);
3689
3690 return ret;
3691}
3692
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003693/* can't be const, mac80211 writes to this */
3694static struct ieee80211_rate wl1271_rates[] = {
3695 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003696 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3697 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003698 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003699 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3700 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003701 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3702 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003703 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3704 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3706 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003707 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3708 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003709 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3710 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003711 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3712 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003713 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003714 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3715 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003716 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003717 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3718 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003719 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003720 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3721 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003722 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003723 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3724 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003725 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003726 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3727 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003728 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003729 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3730 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003731 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003732 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3733 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003734};
3735
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003736/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003737static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003738 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003739 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003740 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3741 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3742 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003743 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003744 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3745 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3746 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003747 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003748 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3749 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3750 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003751 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003752};
3753
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003754/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003755static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003756 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003757 7, /* CONF_HW_RXTX_RATE_MCS7 */
3758 6, /* CONF_HW_RXTX_RATE_MCS6 */
3759 5, /* CONF_HW_RXTX_RATE_MCS5 */
3760 4, /* CONF_HW_RXTX_RATE_MCS4 */
3761 3, /* CONF_HW_RXTX_RATE_MCS3 */
3762 2, /* CONF_HW_RXTX_RATE_MCS2 */
3763 1, /* CONF_HW_RXTX_RATE_MCS1 */
3764 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003765
3766 11, /* CONF_HW_RXTX_RATE_54 */
3767 10, /* CONF_HW_RXTX_RATE_48 */
3768 9, /* CONF_HW_RXTX_RATE_36 */
3769 8, /* CONF_HW_RXTX_RATE_24 */
3770
3771 /* TI-specific rate */
3772 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3773
3774 7, /* CONF_HW_RXTX_RATE_18 */
3775 6, /* CONF_HW_RXTX_RATE_12 */
3776 3, /* CONF_HW_RXTX_RATE_11 */
3777 5, /* CONF_HW_RXTX_RATE_9 */
3778 4, /* CONF_HW_RXTX_RATE_6 */
3779 2, /* CONF_HW_RXTX_RATE_5_5 */
3780 1, /* CONF_HW_RXTX_RATE_2 */
3781 0 /* CONF_HW_RXTX_RATE_1 */
3782};
3783
Shahar Levie8b03a22010-10-13 16:09:39 +02003784/* 11n STA capabilities */
3785#define HW_RX_HIGHEST_RATE 72
3786
Shahar Levi00d20102010-11-08 11:20:10 +00003787#ifdef CONFIG_WL12XX_HT
3788#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003789 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3790 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003791 .ht_supported = true, \
3792 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3793 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3794 .mcs = { \
3795 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3796 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3797 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3798 }, \
3799}
Shahar Levi18357852010-10-13 16:09:41 +02003800#else
Shahar Levi00d20102010-11-08 11:20:10 +00003801#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003802 .ht_supported = false, \
3803}
3804#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003805
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003806/* can't be const, mac80211 writes to this */
3807static struct ieee80211_supported_band wl1271_band_2ghz = {
3808 .channels = wl1271_channels,
3809 .n_channels = ARRAY_SIZE(wl1271_channels),
3810 .bitrates = wl1271_rates,
3811 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003812 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003813};
3814
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003815/* 5 GHz data rates for WL1273 */
3816static struct ieee80211_rate wl1271_rates_5ghz[] = {
3817 { .bitrate = 60,
3818 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3819 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3820 { .bitrate = 90,
3821 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3822 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3823 { .bitrate = 120,
3824 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3825 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3826 { .bitrate = 180,
3827 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3828 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3829 { .bitrate = 240,
3830 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3831 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3832 { .bitrate = 360,
3833 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3834 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3835 { .bitrate = 480,
3836 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3837 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3838 { .bitrate = 540,
3839 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3840 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3841};
3842
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003843/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003844static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03003845 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
3846 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
3847 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
3848 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
3849 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
3850 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
3851 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
3852 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
3853 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
3854 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
3855 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
3856 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
3857 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
3858 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
3859 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
3860 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
3861 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
3862 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
3863 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
3864 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
3865 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
3866 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
3867 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
3868 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
3869 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
3870 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
3871 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
3872 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
3873 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
3874 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
3875 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
3876 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
3877 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
3878 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003879};
3880
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003881/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003882static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003883 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003884 7, /* CONF_HW_RXTX_RATE_MCS7 */
3885 6, /* CONF_HW_RXTX_RATE_MCS6 */
3886 5, /* CONF_HW_RXTX_RATE_MCS5 */
3887 4, /* CONF_HW_RXTX_RATE_MCS4 */
3888 3, /* CONF_HW_RXTX_RATE_MCS3 */
3889 2, /* CONF_HW_RXTX_RATE_MCS2 */
3890 1, /* CONF_HW_RXTX_RATE_MCS1 */
3891 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003892
3893 7, /* CONF_HW_RXTX_RATE_54 */
3894 6, /* CONF_HW_RXTX_RATE_48 */
3895 5, /* CONF_HW_RXTX_RATE_36 */
3896 4, /* CONF_HW_RXTX_RATE_24 */
3897
3898 /* TI-specific rate */
3899 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3900
3901 3, /* CONF_HW_RXTX_RATE_18 */
3902 2, /* CONF_HW_RXTX_RATE_12 */
3903 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3904 1, /* CONF_HW_RXTX_RATE_9 */
3905 0, /* CONF_HW_RXTX_RATE_6 */
3906 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3907 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3908 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3909};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003910
3911static struct ieee80211_supported_band wl1271_band_5ghz = {
3912 .channels = wl1271_channels_5ghz,
3913 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3914 .bitrates = wl1271_rates_5ghz,
3915 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003916 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003917};
3918
Tobias Klausera0ea9492010-05-20 10:38:11 +02003919static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003920 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3921 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3922};
3923
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003924static const struct ieee80211_ops wl1271_ops = {
3925 .start = wl1271_op_start,
3926 .stop = wl1271_op_stop,
3927 .add_interface = wl1271_op_add_interface,
3928 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003929#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03003930 .suspend = wl1271_op_suspend,
3931 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04003932#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003933 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03003934 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003935 .configure_filter = wl1271_op_configure_filter,
3936 .tx = wl1271_op_tx,
3937 .set_key = wl1271_op_set_key,
3938 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03003939 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03003940 .sched_scan_start = wl1271_op_sched_scan_start,
3941 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003942 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003943 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003944 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02003945 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003946 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04003947 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003948 .sta_add = wl1271_op_sta_add,
3949 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003950 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03003951 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02003952 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953};
3954
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003955
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003956u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003957{
3958 u8 idx;
3959
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003960 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003961
3962 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
3963 wl1271_error("Illegal RX rate from HW: %d", rate);
3964 return 0;
3965 }
3966
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02003967 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003968 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
3969 wl1271_error("Unsupported RX rate from HW: %d", rate);
3970 return 0;
3971 }
3972
3973 return idx;
3974}
3975
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003976static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
3977 struct device_attribute *attr,
3978 char *buf)
3979{
3980 struct wl1271 *wl = dev_get_drvdata(dev);
3981 ssize_t len;
3982
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02003983 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02003984
3985 mutex_lock(&wl->mutex);
3986 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
3987 wl->sg_enabled);
3988 mutex_unlock(&wl->mutex);
3989
3990 return len;
3991
3992}
3993
3994static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
3995 struct device_attribute *attr,
3996 const char *buf, size_t count)
3997{
3998 struct wl1271 *wl = dev_get_drvdata(dev);
3999 unsigned long res;
4000 int ret;
4001
Luciano Coelho6277ed62011-04-01 17:49:54 +03004002 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004003 if (ret < 0) {
4004 wl1271_warning("incorrect value written to bt_coex_mode");
4005 return count;
4006 }
4007
4008 mutex_lock(&wl->mutex);
4009
4010 res = !!res;
4011
4012 if (res == wl->sg_enabled)
4013 goto out;
4014
4015 wl->sg_enabled = res;
4016
4017 if (wl->state == WL1271_STATE_OFF)
4018 goto out;
4019
Ido Yariva6208652011-03-01 15:14:41 +02004020 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004021 if (ret < 0)
4022 goto out;
4023
4024 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4025 wl1271_ps_elp_sleep(wl);
4026
4027 out:
4028 mutex_unlock(&wl->mutex);
4029 return count;
4030}
4031
4032static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4033 wl1271_sysfs_show_bt_coex_state,
4034 wl1271_sysfs_store_bt_coex_state);
4035
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004036static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4037 struct device_attribute *attr,
4038 char *buf)
4039{
4040 struct wl1271 *wl = dev_get_drvdata(dev);
4041 ssize_t len;
4042
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004043 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004044
4045 mutex_lock(&wl->mutex);
4046 if (wl->hw_pg_ver >= 0)
4047 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4048 else
4049 len = snprintf(buf, len, "n/a\n");
4050 mutex_unlock(&wl->mutex);
4051
4052 return len;
4053}
4054
Gery Kahn6f07b722011-07-18 14:21:49 +03004055static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004056 wl1271_sysfs_show_hw_pg_ver, NULL);
4057
Ido Yariv95dac04f2011-06-06 14:57:06 +03004058static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4059 struct bin_attribute *bin_attr,
4060 char *buffer, loff_t pos, size_t count)
4061{
4062 struct device *dev = container_of(kobj, struct device, kobj);
4063 struct wl1271 *wl = dev_get_drvdata(dev);
4064 ssize_t len;
4065 int ret;
4066
4067 ret = mutex_lock_interruptible(&wl->mutex);
4068 if (ret < 0)
4069 return -ERESTARTSYS;
4070
4071 /* Let only one thread read the log at a time, blocking others */
4072 while (wl->fwlog_size == 0) {
4073 DEFINE_WAIT(wait);
4074
4075 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4076 &wait,
4077 TASK_INTERRUPTIBLE);
4078
4079 if (wl->fwlog_size != 0) {
4080 finish_wait(&wl->fwlog_waitq, &wait);
4081 break;
4082 }
4083
4084 mutex_unlock(&wl->mutex);
4085
4086 schedule();
4087 finish_wait(&wl->fwlog_waitq, &wait);
4088
4089 if (signal_pending(current))
4090 return -ERESTARTSYS;
4091
4092 ret = mutex_lock_interruptible(&wl->mutex);
4093 if (ret < 0)
4094 return -ERESTARTSYS;
4095 }
4096
4097 /* Check if the fwlog is still valid */
4098 if (wl->fwlog_size < 0) {
4099 mutex_unlock(&wl->mutex);
4100 return 0;
4101 }
4102
4103 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4104 len = min(count, (size_t)wl->fwlog_size);
4105 wl->fwlog_size -= len;
4106 memcpy(buffer, wl->fwlog, len);
4107
4108 /* Make room for new messages */
4109 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4110
4111 mutex_unlock(&wl->mutex);
4112
4113 return len;
4114}
4115
4116static struct bin_attribute fwlog_attr = {
4117 .attr = {.name = "fwlog", .mode = S_IRUSR},
4118 .read = wl1271_sysfs_read_fwlog,
4119};
4120
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004121int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004122{
4123 int ret;
4124
4125 if (wl->mac80211_registered)
4126 return 0;
4127
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004128 ret = wl1271_fetch_nvs(wl);
4129 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004130 /* NOTE: The wl->nvs->nvs element must be first, in
4131 * order to simplify the casting, we assume it is at
4132 * the beginning of the wl->nvs structure.
4133 */
4134 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004135
4136 wl->mac_addr[0] = nvs_ptr[11];
4137 wl->mac_addr[1] = nvs_ptr[10];
4138 wl->mac_addr[2] = nvs_ptr[6];
4139 wl->mac_addr[3] = nvs_ptr[5];
4140 wl->mac_addr[4] = nvs_ptr[4];
4141 wl->mac_addr[5] = nvs_ptr[3];
4142 }
4143
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004144 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4145
4146 ret = ieee80211_register_hw(wl->hw);
4147 if (ret < 0) {
4148 wl1271_error("unable to register mac80211 hw: %d", ret);
4149 return ret;
4150 }
4151
4152 wl->mac80211_registered = true;
4153
Eliad Pellerd60080a2010-11-24 12:53:16 +02004154 wl1271_debugfs_init(wl);
4155
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004156 register_netdevice_notifier(&wl1271_dev_notifier);
4157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004158 wl1271_notice("loaded");
4159
4160 return 0;
4161}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004162EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004163
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004164void wl1271_unregister_hw(struct wl1271 *wl)
4165{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004166 if (wl->state == WL1271_STATE_PLT)
4167 __wl1271_plt_stop(wl);
4168
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004169 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004170 ieee80211_unregister_hw(wl->hw);
4171 wl->mac80211_registered = false;
4172
4173}
4174EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4175
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004176int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004177{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004178 static const u32 cipher_suites[] = {
4179 WLAN_CIPHER_SUITE_WEP40,
4180 WLAN_CIPHER_SUITE_WEP104,
4181 WLAN_CIPHER_SUITE_TKIP,
4182 WLAN_CIPHER_SUITE_CCMP,
4183 WL1271_CIPHER_SUITE_GEM,
4184 };
4185
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004186 /* The tx descriptor buffer and the TKIP space. */
4187 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4188 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004189
4190 /* unit us */
4191 /* FIXME: find a proper value */
4192 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004193 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004194
4195 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004196 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004197 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004198 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004199 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004200 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004201 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004202 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004203 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004204 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004205
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004206 wl->hw->wiphy->cipher_suites = cipher_suites;
4207 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4208
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004209 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004210 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004211 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004212 /*
4213 * Maximum length of elements in scanning probe request templates
4214 * should be the maximum length possible for a template, without
4215 * the IEEE80211 header of the template
4216 */
4217 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
4218 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004219
Luciano Coelho4a31c112011-03-21 23:16:14 +02004220 /* make sure all our channels fit in the scanned_ch bitmask */
4221 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4222 ARRAY_SIZE(wl1271_channels_5ghz) >
4223 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004224 /*
4225 * We keep local copies of the band structs because we need to
4226 * modify them on a per-device basis.
4227 */
4228 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4229 sizeof(wl1271_band_2ghz));
4230 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4231 sizeof(wl1271_band_5ghz));
4232
4233 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4234 &wl->bands[IEEE80211_BAND_2GHZ];
4235 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4236 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004237
Kalle Valo12bd8942010-03-18 12:26:33 +02004238 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004239 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004240
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004241 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4242
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004243 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004244
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004245 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4246
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004247 wl->hw->max_rx_aggregation_subframes = 8;
4248
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004249 return 0;
4250}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004251EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004252
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004253#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004254
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004255struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004256{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004257 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004258 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004259 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004260 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004261 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004262
4263 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4264 if (!hw) {
4265 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004266 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004267 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004268 }
4269
Julia Lawall929ebd32010-05-15 23:16:39 +02004270 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004271 if (!plat_dev) {
4272 wl1271_error("could not allocate platform_device");
4273 ret = -ENOMEM;
4274 goto err_plat_alloc;
4275 }
4276
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004277 wl = hw->priv;
4278 memset(wl, 0, sizeof(*wl));
4279
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004280 INIT_LIST_HEAD(&wl->list);
4281
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004282 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004283 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004284
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004285 for (i = 0; i < NUM_TX_QUEUES; i++)
4286 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004287
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004288 for (i = 0; i < NUM_TX_QUEUES; i++)
4289 for (j = 0; j < AP_MAX_LINKS; j++)
4290 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4291
Ido Yariva6208652011-03-01 15:14:41 +02004292 skb_queue_head_init(&wl->deferred_rx_queue);
4293 skb_queue_head_init(&wl->deferred_tx_queue);
4294
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004295 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004296 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004297 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004298 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4299 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4300 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004301 INIT_WORK(&wl->rx_streaming_enable_work,
4302 wl1271_rx_streaming_enable_work);
4303 INIT_WORK(&wl->rx_streaming_disable_work,
4304 wl1271_rx_streaming_disable_work);
4305
Eliad Peller92ef8962011-06-07 12:50:46 +03004306 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4307 if (!wl->freezable_wq) {
4308 ret = -ENOMEM;
4309 goto err_hw;
4310 }
4311
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004312 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004313 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004314 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004315 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004316 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004317 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004318 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004319 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004320 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004321 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004322 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004323 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004324 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004325 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004326 wl->bss_type = MAX_BSS_TYPE;
4327 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004328 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004329 wl->ap_ps_map = 0;
4330 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004331 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004332 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004333 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004334 wl->tx_security_seq = 0;
4335 wl->tx_security_last_seq_lsb = 0;
4336
Eliad Peller77ddaa12011-05-15 11:10:29 +03004337 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4338 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004339 wl->fwlog_size = 0;
4340 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004341
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004342 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004343 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004344 wl->tx_frames[i] = NULL;
4345
4346 spin_lock_init(&wl->wl_lock);
4347
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004348 wl->state = WL1271_STATE_OFF;
4349 mutex_init(&wl->mutex);
4350
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004351 /* Apply default driver configuration. */
4352 wl1271_conf_init(wl);
4353
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004354 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4355 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4356 if (!wl->aggr_buf) {
4357 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004358 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004359 }
4360
Ido Yariv990f5de2011-03-31 10:06:59 +02004361 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4362 if (!wl->dummy_packet) {
4363 ret = -ENOMEM;
4364 goto err_aggr;
4365 }
4366
Ido Yariv95dac04f2011-06-06 14:57:06 +03004367 /* Allocate one page for the FW log */
4368 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4369 if (!wl->fwlog) {
4370 ret = -ENOMEM;
4371 goto err_dummy_packet;
4372 }
4373
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004374 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004375 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004376 if (ret) {
4377 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004378 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004379 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004380 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004381
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004382 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004383 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004384 if (ret < 0) {
4385 wl1271_error("failed to create sysfs file bt_coex_state");
4386 goto err_platform;
4387 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004388
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004389 /* Create sysfs file to get HW PG version */
4390 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4391 if (ret < 0) {
4392 wl1271_error("failed to create sysfs file hw_pg_ver");
4393 goto err_bt_coex_state;
4394 }
4395
Ido Yariv95dac04f2011-06-06 14:57:06 +03004396 /* Create sysfs file for the FW log */
4397 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4398 if (ret < 0) {
4399 wl1271_error("failed to create sysfs file fwlog");
4400 goto err_hw_pg_ver;
4401 }
4402
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004403 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004404
Ido Yariv95dac04f2011-06-06 14:57:06 +03004405err_hw_pg_ver:
4406 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4407
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004408err_bt_coex_state:
4409 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4410
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004411err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004412 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004413
Ido Yariv95dac04f2011-06-06 14:57:06 +03004414err_fwlog:
4415 free_page((unsigned long)wl->fwlog);
4416
Ido Yariv990f5de2011-03-31 10:06:59 +02004417err_dummy_packet:
4418 dev_kfree_skb(wl->dummy_packet);
4419
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004420err_aggr:
4421 free_pages((unsigned long)wl->aggr_buf, order);
4422
Eliad Peller92ef8962011-06-07 12:50:46 +03004423err_wq:
4424 destroy_workqueue(wl->freezable_wq);
4425
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004426err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004427 wl1271_debugfs_exit(wl);
4428 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004429
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004430err_plat_alloc:
4431 ieee80211_free_hw(hw);
4432
4433err_hw_alloc:
4434
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004435 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004436}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004437EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004438
4439int wl1271_free_hw(struct wl1271 *wl)
4440{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004441 /* Unblock any fwlog readers */
4442 mutex_lock(&wl->mutex);
4443 wl->fwlog_size = -1;
4444 wake_up_interruptible_all(&wl->fwlog_waitq);
4445 mutex_unlock(&wl->mutex);
4446
4447 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004448
4449 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4450
4451 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004452 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004453 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004454 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004455 free_pages((unsigned long)wl->aggr_buf,
4456 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004457 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004458
4459 wl1271_debugfs_exit(wl);
4460
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004461 vfree(wl->fw);
4462 wl->fw = NULL;
4463 kfree(wl->nvs);
4464 wl->nvs = NULL;
4465
4466 kfree(wl->fw_status);
4467 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004468 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004469
4470 ieee80211_free_hw(wl->hw);
4471
4472 return 0;
4473}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004474EXPORT_SYMBOL_GPL(wl1271_free_hw);
4475
Guy Eilam491bbd62011-01-12 10:33:29 +01004476u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004477EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004478module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004479MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4480
Ido Yariv95dac04f2011-06-06 14:57:06 +03004481module_param_named(fwlog, fwlog_param, charp, 0);
4482MODULE_PARM_DESC(keymap,
4483 "FW logger options: continuous, ondemand, dbgpins or disable");
4484
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004485MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004486MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004487MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");