blob: 3db191de3f51c2ace2ac007ea582bef51162dd3c [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030035
Shahar Levi00d20102010-11-08 11:20:10 +000036#include "wl12xx.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "reg.h"
39#include "io.h"
40#include "event.h"
41#include "tx.h"
42#include "rx.h"
43#include "ps.h"
44#include "init.h"
45#include "debugfs.h"
46#include "cmd.h"
47#include "boot.h"
48#include "testmode.h"
49#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030050
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020051#define WL1271_BOOT_RETRIES 3
52
Juuso Oikarinen8a080482009-10-13 12:47:44 +030053static struct conf_drv_settings default_conf = {
54 .sg = {
Arik Nemtsov801f8702011-04-18 14:15:20 +030055 .sta_params = {
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020056 [CONF_SG_BT_PER_THRESHOLD] = 7500,
57 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
58 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
Luciano Coelhod9482e22011-03-21 17:58:32 +020059 [CONF_SG_BT_LOAD_RATIO] = 200,
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +030060 [CONF_SG_AUTO_PS_MODE] = 1,
Juuso Oikarinen1b00f542010-03-18 12:26:30 +020061 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
62 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
63 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
64 [CONF_SG_BEACON_MISS_PERCENT] = 60,
65 [CONF_SG_RATE_ADAPT_THRESH] = 12,
66 [CONF_SG_RATE_ADAPT_SNR] = 0,
67 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
68 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30,
69 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8,
70 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
71 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50,
72 /* Note: with UPSD, this should be 4 */
73 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8,
74 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
75 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
76 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20,
77 /* Note: with UPDS, this should be 15 */
78 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
79 /* Note: with UPDS, this should be 50 */
80 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40,
81 /* Note: with UPDS, this should be 10 */
82 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20,
83 [CONF_SG_RXT] = 1200,
84 [CONF_SG_TXT] = 1000,
85 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
86 [CONF_SG_PS_POLL_TIMEOUT] = 10,
87 [CONF_SG_UPSD_TIMEOUT] = 10,
88 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
89 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
90 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
91 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
92 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
93 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
94 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
95 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
96 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
97 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
98 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
99 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
100 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
101 [CONF_SG_HV3_MAX_SERVED] = 6,
102 [CONF_SG_DHCP_TIME] = 5000,
103 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
104 },
Arik Nemtsov801f8702011-04-18 14:15:20 +0300105 .ap_params = {
106 [CONF_SG_BT_PER_THRESHOLD] = 7500,
107 [CONF_SG_HV3_MAX_OVERRIDE] = 0,
108 [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
109 [CONF_SG_BT_LOAD_RATIO] = 50,
110 [CONF_SG_AUTO_PS_MODE] = 1,
111 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
112 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
113 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
114 [CONF_SG_BEACON_MISS_PERCENT] = 60,
115 [CONF_SG_RATE_ADAPT_THRESH] = 64,
116 [CONF_SG_RATE_ADAPT_SNR] = 1,
117 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
118 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
119 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
120 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
121 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
122 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
123 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
124 [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
125 [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
126 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
127 [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
128 [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
129 [CONF_SG_RXT] = 1200,
130 [CONF_SG_TXT] = 1000,
131 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
132 [CONF_SG_PS_POLL_TIMEOUT] = 10,
133 [CONF_SG_UPSD_TIMEOUT] = 10,
134 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
135 [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
136 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
137 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
138 [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
139 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
140 [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
141 [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
142 [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
143 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
144 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
145 [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
146 [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
147 [CONF_SG_HV3_MAX_SERVED] = 6,
148 [CONF_SG_DHCP_TIME] = 5000,
149 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
150 [CONF_SG_TEMP_PARAM_1] = 0,
151 [CONF_SG_TEMP_PARAM_2] = 0,
152 [CONF_SG_TEMP_PARAM_3] = 0,
153 [CONF_SG_TEMP_PARAM_4] = 0,
154 [CONF_SG_TEMP_PARAM_5] = 0,
155 [CONF_SG_AP_BEACON_MISS_TX] = 3,
156 [CONF_SG_RX_WINDOW_LENGTH] = 6,
157 [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
158 [CONF_SG_TEMP_PARAM_6] = 1,
159 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200160 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300161 },
162 .rx = {
163 .rx_msdu_life_time = 512000,
164 .packet_detection_threshold = 0,
165 .ps_poll_timeout = 15,
166 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300167 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200168 .rx_cca_threshold = 0,
169 .irq_blk_threshold = 0xFFFF,
170 .irq_pkt_threshold = 0,
171 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300172 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
173 },
174 .tx = {
175 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200176 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300177 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300178 .short_retry_limit = 10,
179 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200180 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300181 },
182 .ac_conf_count = 4,
183 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300185 .ac = CONF_TX_AC_BE,
186 .cw_min = 15,
187 .cw_max = 63,
188 .aifsn = 3,
189 .tx_op_limit = 0,
190 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200191 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ac = CONF_TX_AC_BK,
193 .cw_min = 15,
194 .cw_max = 63,
195 .aifsn = 7,
196 .tx_op_limit = 0,
197 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200198 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300199 .ac = CONF_TX_AC_VI,
200 .cw_min = 15,
201 .cw_max = 63,
202 .aifsn = CONF_TX_AIFS_PIFS,
203 .tx_op_limit = 3008,
204 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200205 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300206 .ac = CONF_TX_AC_VO,
207 .cw_min = 15,
208 .cw_max = 63,
209 .aifsn = CONF_TX_AIFS_PIFS,
210 .tx_op_limit = 1504,
211 },
212 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300213 .max_tx_retries = 100,
214 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200215 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200217 [CONF_TX_AC_BE] = {
218 .queue_id = CONF_TX_AC_BE,
219 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .tsid = CONF_TX_AC_BE,
221 .ps_scheme = CONF_PS_SCHEME_LEGACY,
222 .ack_policy = CONF_ACK_POLICY_LEGACY,
223 .apsd_conf = {0, 0},
224 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200225 [CONF_TX_AC_BK] = {
226 .queue_id = CONF_TX_AC_BK,
227 .channel_type = CONF_CHANNEL_TYPE_EDCF,
228 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300229 .ps_scheme = CONF_PS_SCHEME_LEGACY,
230 .ack_policy = CONF_ACK_POLICY_LEGACY,
231 .apsd_conf = {0, 0},
232 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200233 [CONF_TX_AC_VI] = {
234 .queue_id = CONF_TX_AC_VI,
235 .channel_type = CONF_CHANNEL_TYPE_EDCF,
236 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 .ps_scheme = CONF_PS_SCHEME_LEGACY,
238 .ack_policy = CONF_ACK_POLICY_LEGACY,
239 .apsd_conf = {0, 0},
240 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200241 [CONF_TX_AC_VO] = {
242 .queue_id = CONF_TX_AC_VO,
243 .channel_type = CONF_CHANNEL_TYPE_EDCF,
244 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300245 .ps_scheme = CONF_PS_SCHEME_LEGACY,
246 .ack_policy = CONF_ACK_POLICY_LEGACY,
247 .apsd_conf = {0, 0},
248 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300249 },
250 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200251 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300252 .tx_compl_threshold = 4,
253 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
254 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200255 .tmpl_short_retry_limit = 10,
256 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300257 },
258 .conn = {
259 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300260 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300261 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300262 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300263 .bcn_filt_ie = {
264 [0] = {
265 .ie = WLAN_EID_CHANNEL_SWITCH,
266 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300267 },
268 [1] = {
269 .ie = WLAN_EID_HT_INFORMATION,
270 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
271 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300272 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200273 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300274 .bss_lose_timeout = 100,
275 .beacon_rx_timeout = 10000,
276 .broadcast_timeout = 20000,
277 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300278 .ps_poll_threshold = 10,
279 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300280 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200281 .bet_max_consecutive = 50,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200282 .psm_entry_retries = 5,
Shahar Levi23708412011-04-13 14:52:50 +0300283 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200284 .psm_entry_nullfunc_retries = 3,
285 .psm_entry_hangover_period = 1,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300286 .keep_alive_interval = 55000,
287 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300288 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200289 .itrim = {
290 .enable = false,
291 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200292 },
293 .pm_config = {
294 .host_clk_settling_time = 5000,
295 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300296 },
297 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300298 .trigger_pacing = 1,
299 .avg_weight_rssi_beacon = 20,
300 .avg_weight_rssi_data = 10,
301 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100302 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200303 },
304 .scan = {
305 .min_dwell_time_active = 7500,
306 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100307 .min_dwell_time_passive = 100000,
308 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200309 .num_probe_reqs = 2,
310 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300311 .sched_scan = {
312 /* sched_scan requires dwell times in TU instead of TU/1000 */
313 .min_dwell_time_active = 8,
314 .max_dwell_time_active = 30,
315 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300316 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300317 .num_probe_reqs = 2,
318 .rssi_threshold = -90,
319 .snr_threshold = 0,
320 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200321 .rf = {
322 .tx_per_channel_power_compensation_2 = {
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 },
325 .tx_per_channel_power_compensation_5 = {
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 },
330 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100331 .ht = {
332 .tx_ba_win_size = 64,
333 .inactivity_timeout = 10000,
334 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200335 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200336 .num_stations = 1,
337 .ssid_profiles = 1,
338 .rx_block_num = 70,
339 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300340 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200341 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200342 .min_req_rx_blocks = 22,
343 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200344 },
345 .mem_wl128x = {
346 .num_stations = 1,
347 .ssid_profiles = 1,
348 .rx_block_num = 40,
349 .tx_min_block_num = 40,
350 .dynamic_memory = 1,
351 .min_req_tx_blocks = 45,
352 .min_req_rx_blocks = 22,
353 .tx_min = 27,
354 },
Shahar Leviff868432011-04-11 15:41:46 +0300355 .fm_coex = {
356 .enable = true,
357 .swallow_period = 5,
358 .n_divider_fref_set_1 = 0xff, /* default */
359 .n_divider_fref_set_2 = 12,
360 .m_divider_fref_set_1 = 148,
361 .m_divider_fref_set_2 = 0xffff, /* default */
362 .coex_pll_stabilization_time = 0xffffffff, /* default */
363 .ldo_stabilization_time = 0xffff, /* default */
364 .fm_disturbed_band_margin = 0xff, /* default */
365 .swallow_clk_diff = 0xff, /* default */
366 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300367 .rx_streaming = {
368 .duration = 150,
369 .queues = 0x1,
370 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300371 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300372 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300373 .fwlog = {
374 .mode = WL12XX_FWLOG_ON_DEMAND,
375 .mem_blocks = 2,
376 .severity = 0,
377 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
378 .output = WL12XX_FWLOG_OUTPUT_HOST,
379 .threshold = 0,
380 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300381 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300382 .rate = {
383 .rate_retry_score = 32000,
384 .per_add = 8192,
385 .per_th1 = 2048,
386 .per_th2 = 4096,
387 .max_per = 8100,
388 .inverse_curiosity_factor = 5,
389 .tx_fail_low_th = 4,
390 .tx_fail_high_th = 10,
391 .per_alpha_shift = 4,
392 .per_add_shift = 13,
393 .per_beta1_shift = 10,
394 .per_beta2_shift = 8,
395 .rate_check_up = 2,
396 .rate_check_down = 12,
397 .rate_retry_policy = {
398 0x00, 0x00, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00, 0x00,
400 0x00, 0x00, 0x00,
401 },
402 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300403};
404
Ido Yariv95dac04f2011-06-06 14:57:06 +0300405static char *fwlog_param;
406
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300407static void __wl1271_op_remove_interface(struct wl1271 *wl,
408 bool reset_tx_queues);
Arik Nemtsov7f179b42010-10-16 21:39:06 +0200409static void wl1271_free_ap_keys(struct wl1271 *wl);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200410
411
Juuso Oikarinena1dd8182010-03-18 12:26:31 +0200412static void wl1271_device_release(struct device *dev)
413{
414
415}
416
417static struct platform_device wl1271_device = {
418 .name = "wl1271",
419 .id = -1,
420
421 /* device model insists to have a release function */
422 .dev = {
423 .release = wl1271_device_release,
424 },
425};
426
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200427static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300428static LIST_HEAD(wl_list);
429
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300430static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate)
431{
432 int ret;
433 if (operstate != IF_OPER_UP)
434 return 0;
435
436 if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags))
437 return 0;
438
Eliad Pellerc690ec82011-08-14 13:17:07 +0300439 ret = wl12xx_cmd_set_peer_state(wl);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300440 if (ret < 0)
441 return ret;
442
443 wl1271_info("Association completed.");
444 return 0;
445}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300446static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
447 void *arg)
448{
449 struct net_device *dev = arg;
450 struct wireless_dev *wdev;
451 struct wiphy *wiphy;
452 struct ieee80211_hw *hw;
453 struct wl1271 *wl;
454 struct wl1271 *wl_temp;
455 int ret = 0;
456
457 /* Check that this notification is for us. */
458 if (what != NETDEV_CHANGE)
459 return NOTIFY_DONE;
460
461 wdev = dev->ieee80211_ptr;
462 if (wdev == NULL)
463 return NOTIFY_DONE;
464
465 wiphy = wdev->wiphy;
466 if (wiphy == NULL)
467 return NOTIFY_DONE;
468
469 hw = wiphy_priv(wiphy);
470 if (hw == NULL)
471 return NOTIFY_DONE;
472
473 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200474 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475 list_for_each_entry(wl, &wl_list, list) {
476 if (wl == wl_temp)
477 break;
478 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200479 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300480 if (wl != wl_temp)
481 return NOTIFY_DONE;
482
483 mutex_lock(&wl->mutex);
484
485 if (wl->state == WL1271_STATE_OFF)
486 goto out;
487
488 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
489 goto out;
490
Ido Yariva6208652011-03-01 15:14:41 +0200491 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300492 if (ret < 0)
493 goto out;
494
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300495 wl1271_check_operstate(wl, dev->operstate);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300496
497 wl1271_ps_elp_sleep(wl);
498
499out:
500 mutex_unlock(&wl->mutex);
501
502 return NOTIFY_OK;
503}
504
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100505static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200506 struct regulatory_request *request)
507{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100508 struct ieee80211_supported_band *band;
509 struct ieee80211_channel *ch;
510 int i;
511
512 band = wiphy->bands[IEEE80211_BAND_5GHZ];
513 for (i = 0; i < band->n_channels; i++) {
514 ch = &band->channels[i];
515 if (ch->flags & IEEE80211_CHAN_DISABLED)
516 continue;
517
518 if (ch->flags & IEEE80211_CHAN_RADAR)
519 ch->flags |= IEEE80211_CHAN_NO_IBSS |
520 IEEE80211_CHAN_PASSIVE_SCAN;
521
522 }
523
524 return 0;
525}
526
Eliad Peller77ddaa12011-05-15 11:10:29 +0300527static int wl1271_set_rx_streaming(struct wl1271 *wl, bool enable)
528{
529 int ret = 0;
530
531 /* we should hold wl->mutex */
532 ret = wl1271_acx_ps_rx_streaming(wl, enable);
533 if (ret < 0)
534 goto out;
535
536 if (enable)
537 set_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
538 else
539 clear_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags);
540out:
541 return ret;
542}
543
544/*
545 * this function is being called when the rx_streaming interval
546 * has beed changed or rx_streaming should be disabled
547 */
548int wl1271_recalc_rx_streaming(struct wl1271 *wl)
549{
550 int ret = 0;
551 int period = wl->conf.rx_streaming.interval;
552
553 /* don't reconfigure if rx_streaming is disabled */
554 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
555 goto out;
556
557 /* reconfigure/disable according to new streaming_period */
558 if (period &&
559 test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) &&
560 (wl->conf.rx_streaming.always ||
561 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 ret = wl1271_set_rx_streaming(wl, true);
563 else {
564 ret = wl1271_set_rx_streaming(wl, false);
565 /* don't cancel_work_sync since we might deadlock */
566 del_timer_sync(&wl->rx_streaming_timer);
567 }
568out:
569 return ret;
570}
571
572static void wl1271_rx_streaming_enable_work(struct work_struct *work)
573{
574 int ret;
575 struct wl1271 *wl =
576 container_of(work, struct wl1271, rx_streaming_enable_work);
577
578 mutex_lock(&wl->mutex);
579
580 if (test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags) ||
581 !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
582 (!wl->conf.rx_streaming.always &&
583 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
584 goto out;
585
586 if (!wl->conf.rx_streaming.interval)
587 goto out;
588
589 ret = wl1271_ps_elp_wakeup(wl);
590 if (ret < 0)
591 goto out;
592
593 ret = wl1271_set_rx_streaming(wl, true);
594 if (ret < 0)
595 goto out_sleep;
596
597 /* stop it after some time of inactivity */
598 mod_timer(&wl->rx_streaming_timer,
599 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
600
601out_sleep:
602 wl1271_ps_elp_sleep(wl);
603out:
604 mutex_unlock(&wl->mutex);
605}
606
607static void wl1271_rx_streaming_disable_work(struct work_struct *work)
608{
609 int ret;
610 struct wl1271 *wl =
611 container_of(work, struct wl1271, rx_streaming_disable_work);
612
613 mutex_lock(&wl->mutex);
614
615 if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags))
616 goto out;
617
618 ret = wl1271_ps_elp_wakeup(wl);
619 if (ret < 0)
620 goto out;
621
622 ret = wl1271_set_rx_streaming(wl, false);
623 if (ret)
624 goto out_sleep;
625
626out_sleep:
627 wl1271_ps_elp_sleep(wl);
628out:
629 mutex_unlock(&wl->mutex);
630}
631
632static void wl1271_rx_streaming_timer(unsigned long data)
633{
634 struct wl1271 *wl = (struct wl1271 *)data;
635 ieee80211_queue_work(wl->hw, &wl->rx_streaming_disable_work);
636}
637
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300638static void wl1271_conf_init(struct wl1271 *wl)
639{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300640
641 /*
642 * This function applies the default configuration to the driver. This
643 * function is invoked upon driver load (spi probe.)
644 *
645 * The configuration is stored in a run-time structure in order to
646 * facilitate for run-time adjustment of any of the parameters. Making
647 * changes to the configuration structure will apply the new values on
648 * the next interface up (wl1271_op_start.)
649 */
650
651 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300652 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300653
Ido Yariv95dac04f2011-06-06 14:57:06 +0300654 /* Adjust settings according to optional module parameters */
655 if (fwlog_param) {
656 if (!strcmp(fwlog_param, "continuous")) {
657 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
658 } else if (!strcmp(fwlog_param, "ondemand")) {
659 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
660 } else if (!strcmp(fwlog_param, "dbgpins")) {
661 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
662 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
663 } else if (!strcmp(fwlog_param, "disable")) {
664 wl->conf.fwlog.mem_blocks = 0;
665 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
666 } else {
667 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
668 }
669 }
670}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300671
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300672static int wl1271_plt_init(struct wl1271 *wl)
673{
Luciano Coelho12419cc2010-02-18 13:25:44 +0200674 struct conf_tx_ac_category *conf_ac;
675 struct conf_tx_tid *conf_tid;
676 int ret, i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300677
Shahar Levi49d750ca2011-03-06 16:32:09 +0200678 if (wl->chip.id == CHIP_ID_1283_PG20)
679 ret = wl128x_cmd_general_parms(wl);
680 else
681 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200682 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200683 return ret;
684
Shahar Levi49d750ca2011-03-06 16:32:09 +0200685 if (wl->chip.id == CHIP_ID_1283_PG20)
686 ret = wl128x_cmd_radio_parms(wl);
687 else
688 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200689 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200690 return ret;
691
Shahar Levi49d750ca2011-03-06 16:32:09 +0200692 if (wl->chip.id != CHIP_ID_1283_PG20) {
693 ret = wl1271_cmd_ext_radio_parms(wl);
694 if (ret < 0)
695 return ret;
696 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200697 if (ret < 0)
698 return ret;
699
Shahar Levi48a61472011-03-06 16:32:08 +0200700 /* Chip-specific initializations */
701 ret = wl1271_chip_specific_init(wl);
702 if (ret < 0)
703 return ret;
704
Arik Nemtsove0fe3712010-10-16 18:19:53 +0200705 ret = wl1271_sta_init_templates_config(wl);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200706 if (ret < 0)
707 return ret;
708
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300709 ret = wl1271_acx_init_mem_config(wl);
710 if (ret < 0)
711 return ret;
712
Luciano Coelho12419cc2010-02-18 13:25:44 +0200713 /* PHY layer config */
714 ret = wl1271_init_phy_config(wl);
715 if (ret < 0)
716 goto out_free_memmap;
717
718 ret = wl1271_acx_dco_itrim_params(wl);
719 if (ret < 0)
720 goto out_free_memmap;
721
722 /* Initialize connection monitoring thresholds */
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +0200723 ret = wl1271_acx_conn_monit_params(wl, false);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200724 if (ret < 0)
725 goto out_free_memmap;
726
727 /* Bluetooth WLAN coexistence */
728 ret = wl1271_init_pta(wl);
729 if (ret < 0)
730 goto out_free_memmap;
731
Shahar Leviff868432011-04-11 15:41:46 +0300732 /* FM WLAN coexistence */
733 ret = wl1271_acx_fm_coex(wl);
734 if (ret < 0)
735 goto out_free_memmap;
736
Luciano Coelho12419cc2010-02-18 13:25:44 +0200737 /* Energy detection */
738 ret = wl1271_init_energy_detection(wl);
739 if (ret < 0)
740 goto out_free_memmap;
741
Eliad Peller7f0979882011-08-14 13:17:06 +0300742 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600743 if (ret < 0)
744 goto out_free_memmap;
745
Luciano Coelho12419cc2010-02-18 13:25:44 +0200746 /* Default fragmentation threshold */
Arik Nemtsov68d069c2010-11-08 10:51:07 +0100747 ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200748 if (ret < 0)
749 goto out_free_memmap;
750
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200751 /* Default TID/AC configuration */
752 BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
Luciano Coelho12419cc2010-02-18 13:25:44 +0200753 for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200754 conf_ac = &wl->conf.tx.ac_conf[i];
755 ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min,
756 conf_ac->cw_max, conf_ac->aifsn,
757 conf_ac->tx_op_limit);
758 if (ret < 0)
759 goto out_free_memmap;
760
Luciano Coelho12419cc2010-02-18 13:25:44 +0200761 conf_tid = &wl->conf.tx.tid_conf[i];
762 ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id,
763 conf_tid->channel_type,
764 conf_tid->tsid,
765 conf_tid->ps_scheme,
766 conf_tid->ack_policy,
767 conf_tid->apsd_conf[0],
768 conf_tid->apsd_conf[1]);
769 if (ret < 0)
770 goto out_free_memmap;
771 }
772
Luciano Coelho12419cc2010-02-18 13:25:44 +0200773 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200774 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300775 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200776 goto out_free_memmap;
777
778 /* Configure for CAM power saving (ie. always active) */
779 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
780 if (ret < 0)
781 goto out_free_memmap;
782
783 /* configure PM */
784 ret = wl1271_acx_pm_config(wl);
785 if (ret < 0)
786 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
788 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200789
790 out_free_memmap:
791 kfree(wl->target_mem_map);
792 wl->target_mem_map = NULL;
793
794 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300795}
796
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300797#if 0
Arik Nemtsovb622d992011-02-23 00:22:31 +0200798static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks)
799{
800 bool fw_ps;
801
802 /* only regulate station links */
803 if (hlid < WL1271_AP_STA_HLID_START)
804 return;
805
806 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
807
808 /*
809 * Wake up from high level PS if the STA is asleep with too little
810 * blocks in FW or if the STA is awake.
811 */
812 if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS)
813 wl1271_ps_link_end(wl, hlid);
814
815 /* Start high-level PS if the STA is asleep with enough blocks in FW */
816 else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS)
817 wl1271_ps_link_start(wl, hlid, true);
818}
819
820static void wl1271_irq_update_links_status(struct wl1271 *wl,
821 struct wl1271_fw_ap_status *status)
822{
823 u32 cur_fw_ps_map;
824 u8 hlid;
825
826 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
827 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
828 wl1271_debug(DEBUG_PSM,
829 "link ps prev 0x%x cur 0x%x changed 0x%x",
830 wl->ap_fw_ps_map, cur_fw_ps_map,
831 wl->ap_fw_ps_map ^ cur_fw_ps_map);
832
833 wl->ap_fw_ps_map = cur_fw_ps_map;
834 }
835
836 for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) {
837 u8 cnt = status->tx_lnk_free_blks[hlid] -
838 wl->links[hlid].prev_freed_blks;
839
840 wl->links[hlid].prev_freed_blks =
841 status->tx_lnk_free_blks[hlid];
842 wl->links[hlid].allocated_blks -= cnt;
843
844 wl1271_irq_ps_regulate_link(wl, hlid,
845 wl->links[hlid].allocated_blks);
846 }
847}
Eliad Pellerdbe25cb2011-08-14 13:17:03 +0300848#endif
Arik Nemtsovb622d992011-02-23 00:22:31 +0200849
Eliad Peller4d56ad92011-08-14 13:17:05 +0300850static void wl12xx_fw_status(struct wl1271 *wl,
851 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300852{
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200853 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200854 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300855 int avail, freed_blocks;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300856
Eliad Peller4d56ad92011-08-14 13:17:05 +0300857 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200858
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300859 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
860 "drv_rx_counter = %d, tx_results_counter = %d)",
861 status->intr,
862 status->fw_rx_counter,
863 status->drv_rx_counter,
864 status->tx_results_counter);
865
Eliad Peller4d56ad92011-08-14 13:17:05 +0300866 freed_blocks = le32_to_cpu(status->total_released_blks) -
867 wl->tx_blocks_freed;
868 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200869
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300870 wl->tx_allocated_blocks -= freed_blocks;
871
Eliad Peller4d56ad92011-08-14 13:17:05 +0300872 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200873
Eliad Peller4d56ad92011-08-14 13:17:05 +0300874 /*
875 * The FW might change the total number of TX memblocks before
876 * we get a notification about blocks being released. Thus, the
877 * available blocks calculation might yield a temporary result
878 * which is lower than the actual available blocks. Keeping in
879 * mind that only blocks that were allocated can be moved from
880 * TX to RX, tx_blocks_available should never decrease here.
881 */
882 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
883 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884
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
Eliad Peller4d56ad92011-08-14 13:17:05 +0300889 /* for AP update num of allocated TX blocks per link and ps status */
890 if (wl->bss_type == BSS_TYPE_AP_BSS) {
891#if 0
892 wl1271_irq_update_links_status(wl, status);
893#endif
894 }
895
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300896 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200897 getnstimeofday(&ts);
898 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
899 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900}
901
Ido Yariva6208652011-03-01 15:14:41 +0200902static void wl1271_flush_deferred_work(struct wl1271 *wl)
903{
904 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Ido Yariva6208652011-03-01 15:14:41 +0200906 /* Pass all received frames to the network stack */
907 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
908 ieee80211_rx_ni(wl->hw, skb);
909
910 /* Return sent skbs to the network stack */
911 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300912 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200913}
914
915static void wl1271_netstack_work(struct work_struct *work)
916{
917 struct wl1271 *wl =
918 container_of(work, struct wl1271, netstack_work);
919
920 do {
921 wl1271_flush_deferred_work(wl);
922 } while (skb_queue_len(&wl->deferred_rx_queue));
923}
924
925#define WL1271_IRQ_MAX_LOOPS 256
926
927irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300928{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300929 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300930 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200931 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200932 struct wl1271 *wl = (struct wl1271 *)cookie;
933 bool done = false;
934 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200935 unsigned long flags;
936
937 /* TX might be handled here, avoid redundant work */
938 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
939 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300940
Ido Yariv341b7cd2011-03-31 10:07:01 +0200941 /*
942 * In case edge triggered interrupt must be used, we cannot iterate
943 * more than once without introducing race conditions with the hardirq.
944 */
945 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
946 loopcount = 1;
947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300948 mutex_lock(&wl->mutex);
949
950 wl1271_debug(DEBUG_IRQ, "IRQ work");
951
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300953 goto out;
954
Ido Yariva6208652011-03-01 15:14:41 +0200955 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300956 if (ret < 0)
957 goto out;
958
Ido Yariva6208652011-03-01 15:14:41 +0200959 while (!done && loopcount--) {
960 /*
961 * In order to avoid a race with the hardirq, clear the flag
962 * before acknowledging the chip. Since the mutex is held,
963 * wl1271_ps_elp_wakeup cannot be called concurrently.
964 */
965 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
966 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200967
Eliad Peller4d56ad92011-08-14 13:17:05 +0300968 wl12xx_fw_status(wl, wl->fw_status);
969 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200970 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200971 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200972 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200973 continue;
974 }
975
Eliad Pellerccc83b02010-10-27 14:09:57 +0200976 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
977 wl1271_error("watchdog interrupt received! "
978 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300979 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200980
981 /* restarting the chip. ignore any other interrupt. */
982 goto out;
983 }
984
Ido Yariva6208652011-03-01 15:14:41 +0200985 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200986 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
987
Eliad Peller4d56ad92011-08-14 13:17:05 +0300988 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200989
Ido Yariva5225502010-10-12 14:49:10 +0200990 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200991 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200992 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300993 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200994 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200995 /*
996 * In order to avoid starvation of the TX path,
997 * call the work function directly.
998 */
999 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +02001000 } else {
1001 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +02001002 }
1003
Ido Yariv8aad2462011-03-01 15:14:38 +02001004 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001005 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +02001006 (wl->tx_results_count & 0xff))
1007 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +02001008
1009 /* Make sure the deferred queues don't get too long */
1010 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
1011 skb_queue_len(&wl->deferred_rx_queue);
1012 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
1013 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +02001014 }
1015
1016 if (intr & WL1271_ACX_INTR_EVENT_A) {
1017 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
1018 wl1271_event_handle(wl, 0);
1019 }
1020
1021 if (intr & WL1271_ACX_INTR_EVENT_B) {
1022 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
1023 wl1271_event_handle(wl, 1);
1024 }
1025
1026 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
1027 wl1271_debug(DEBUG_IRQ,
1028 "WL1271_ACX_INTR_INIT_COMPLETE");
1029
1030 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
1031 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032 }
1033
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 wl1271_ps_elp_sleep(wl);
1035
1036out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001037 spin_lock_irqsave(&wl->wl_lock, flags);
1038 /* In case TX was not handled here, queue TX work */
1039 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
1040 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001041 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +02001042 ieee80211_queue_work(wl->hw, &wl->tx_work);
1043 spin_unlock_irqrestore(&wl->wl_lock, flags);
1044
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001045 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001046
1047 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048}
Ido Yariva6208652011-03-01 15:14:41 +02001049EXPORT_SYMBOL_GPL(wl1271_irq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051static int wl1271_fetch_firmware(struct wl1271 *wl)
1052{
1053 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001054 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055 int ret;
1056
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001057 if (wl->chip.id == CHIP_ID_1283_PG20)
1058 fw_name = WL128X_FW_NAME;
1059 else
1060 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001061
1062 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1063
1064 ret = request_firmware(&fw, fw_name, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065
1066 if (ret < 0) {
1067 wl1271_error("could not get firmware: %d", ret);
1068 return ret;
1069 }
1070
1071 if (fw->size % 4) {
1072 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1073 fw->size);
1074 ret = -EILSEQ;
1075 goto out;
1076 }
1077
Arik Nemtsov166d5042010-10-16 21:44:57 +02001078 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001079 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001080 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001081
1082 if (!wl->fw) {
1083 wl1271_error("could not allocate memory for the firmware");
1084 ret = -ENOMEM;
1085 goto out;
1086 }
1087
1088 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001089 ret = 0;
1090
1091out:
1092 release_firmware(fw);
1093
1094 return ret;
1095}
1096
1097static int wl1271_fetch_nvs(struct wl1271 *wl)
1098{
1099 const struct firmware *fw;
1100 int ret;
1101
Shahar Levi5aa42342011-03-06 16:32:07 +02001102 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103
1104 if (ret < 0) {
1105 wl1271_error("could not get nvs file: %d", ret);
1106 return ret;
1107 }
1108
Shahar Levibc765bf2011-03-06 16:32:10 +02001109 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001110
1111 if (!wl->nvs) {
1112 wl1271_error("could not allocate memory for the nvs file");
1113 ret = -ENOMEM;
1114 goto out;
1115 }
1116
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001117 wl->nvs_len = fw->size;
1118
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001119out:
1120 release_firmware(fw);
1121
1122 return ret;
1123}
1124
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001125void wl12xx_queue_recovery_work(struct wl1271 *wl)
1126{
1127 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1128 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1129}
1130
Ido Yariv95dac04f2011-06-06 14:57:06 +03001131size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1132{
1133 size_t len = 0;
1134
1135 /* The FW log is a length-value list, find where the log end */
1136 while (len < maxlen) {
1137 if (memblock[len] == 0)
1138 break;
1139 if (len + memblock[len] + 1 > maxlen)
1140 break;
1141 len += memblock[len] + 1;
1142 }
1143
1144 /* Make sure we have enough room */
1145 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1146
1147 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1148 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1149 wl->fwlog_size += len;
1150
1151 return len;
1152}
1153
1154static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1155{
1156 u32 addr;
1157 u32 first_addr;
1158 u8 *block;
1159
1160 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1161 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1162 (wl->conf.fwlog.mem_blocks == 0))
1163 return;
1164
1165 wl1271_info("Reading FW panic log");
1166
1167 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1168 if (!block)
1169 return;
1170
1171 /*
1172 * Make sure the chip is awake and the logger isn't active.
1173 * This might fail if the firmware hanged.
1174 */
1175 if (!wl1271_ps_elp_wakeup(wl))
1176 wl12xx_cmd_stop_fwlog(wl);
1177
1178 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001179 wl12xx_fw_status(wl, wl->fw_status);
1180 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001181 if (!first_addr)
1182 goto out;
1183
1184 /* Traverse the memory blocks linked list */
1185 addr = first_addr;
1186 do {
1187 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1188 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1189 false);
1190
1191 /*
1192 * Memory blocks are linked to one another. The first 4 bytes
1193 * of each memory block hold the hardware address of the next
1194 * one. The last memory block points to the first one.
1195 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001196 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001197 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1198 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1199 break;
1200 } while (addr && (addr != first_addr));
1201
1202 wake_up_interruptible(&wl->fwlog_waitq);
1203
1204out:
1205 kfree(block);
1206}
1207
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001208static void wl1271_recovery_work(struct work_struct *work)
1209{
1210 struct wl1271 *wl =
1211 container_of(work, struct wl1271, recovery_work);
1212
1213 mutex_lock(&wl->mutex);
1214
1215 if (wl->state != WL1271_STATE_ON)
1216 goto out;
1217
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001218 /* Avoid a recursive recovery */
1219 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1220
Ido Yariv95dac04f2011-06-06 14:57:06 +03001221 wl12xx_read_fwlog_panic(wl);
1222
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001223 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1224 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001225
Oz Krakowskib992c682011-06-26 10:36:02 +03001226 /*
1227 * Advance security sequence number to overcome potential progress
1228 * in the firmware during recovery. This doens't hurt if the network is
1229 * not encrypted.
1230 */
1231 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
1232 test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1233 wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
1234
Juuso Oikarinend25611d2010-09-30 10:43:27 +02001235 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1236 ieee80211_connection_loss(wl->vif);
1237
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001238 /* Prevent spurious TX during FW restart */
1239 ieee80211_stop_queues(wl->hw);
1240
Luciano Coelho33c2c062011-05-10 14:46:02 +03001241 if (wl->sched_scanning) {
1242 ieee80211_sched_scan_stopped(wl->hw);
1243 wl->sched_scanning = false;
1244 }
1245
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001246 /* reboot the chipset */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001247 __wl1271_op_remove_interface(wl, false);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001248
1249 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1250
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001251 ieee80211_restart_hw(wl->hw);
1252
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001253 /*
1254 * Its safe to enable TX now - the queues are stopped after a request
1255 * to restart the HW.
1256 */
1257 ieee80211_wake_queues(wl->hw);
1258
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001259out:
1260 mutex_unlock(&wl->mutex);
1261}
1262
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263static void wl1271_fw_wakeup(struct wl1271 *wl)
1264{
1265 u32 elp_reg;
1266
1267 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001268 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269}
1270
1271static int wl1271_setup(struct wl1271 *wl)
1272{
1273 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1274 if (!wl->fw_status)
1275 return -ENOMEM;
1276
1277 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1278 if (!wl->tx_res_if) {
1279 kfree(wl->fw_status);
1280 return -ENOMEM;
1281 }
1282
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001283 return 0;
1284}
1285
1286static int wl1271_chip_wakeup(struct wl1271 *wl)
1287{
Juuso Oikarinen451de972009-10-12 15:08:46 +03001288 struct wl1271_partition_set partition;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001289 int ret = 0;
1290
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001291 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001292 ret = wl1271_power_on(wl);
1293 if (ret < 0)
1294 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001296 wl1271_io_reset(wl);
1297 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001298
1299 /* We don't need a real memory partition here, because we only want
1300 * to use the registers at this point. */
Juuso Oikarinen451de972009-10-12 15:08:46 +03001301 memset(&partition, 0, sizeof(partition));
1302 partition.reg.start = REGISTERS_BASE;
1303 partition.reg.size = REGISTERS_DOWN_SIZE;
1304 wl1271_set_partition(wl, &partition);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305
1306 /* ELP module wake up */
1307 wl1271_fw_wakeup(wl);
1308
1309 /* whal_FwCtrl_BootSm() */
1310
1311 /* 0. read chip id from CHIP_ID */
Teemu Paasikivi7b048c52010-02-18 13:25:55 +02001312 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313
1314 /* 1. check if chip id is valid */
1315
1316 switch (wl->chip.id) {
1317 case CHIP_ID_1271_PG10:
1318 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1319 wl->chip.id);
1320
1321 ret = wl1271_setup(wl);
1322 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001323 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001324 break;
1325 case CHIP_ID_1271_PG20:
1326 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1327 wl->chip.id);
1328
Shahar Levi0c005042011-06-12 10:34:43 +03001329 /*
1330 * 'end-of-transaction flag' and 'LPD mode flag'
1331 * should be set in wl127x AP mode only
1332 */
Shahar Levi564f5952011-04-04 10:20:39 +03001333 if (wl->bss_type == BSS_TYPE_AP_BSS)
Shahar Levi0c005042011-06-12 10:34:43 +03001334 wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION |
1335 WL12XX_QUIRK_LPD_MODE);
Shahar Levi564f5952011-04-04 10:20:39 +03001336
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337 ret = wl1271_setup(wl);
1338 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001339 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340 break;
Shahar Levi0830cee2011-03-06 16:32:20 +02001341 case CHIP_ID_1283_PG20:
1342 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1343 wl->chip.id);
1344
1345 ret = wl1271_setup(wl);
1346 if (ret < 0)
1347 goto out;
Shahar Levi0c005042011-06-12 10:34:43 +03001348
Ido Yariv0da13da2011-03-31 10:06:58 +02001349 if (wl1271_set_block_size(wl))
1350 wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
Shahar Levi0830cee2011-03-06 16:32:20 +02001351 break;
1352 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001353 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001354 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001355 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001356 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 }
1358
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001359 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001360 ret = wl1271_fetch_firmware(wl);
1361 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001362 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001363 }
1364
1365 /* No NVS from netlink, try to get it from the filesystem */
1366 if (wl->nvs == NULL) {
1367 ret = wl1271_fetch_nvs(wl);
1368 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 }
1371
1372out:
1373 return ret;
1374}
1375
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376int wl1271_plt_start(struct wl1271 *wl)
1377{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001378 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001379 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001380 int ret;
1381
1382 mutex_lock(&wl->mutex);
1383
1384 wl1271_notice("power up");
1385
1386 if (wl->state != WL1271_STATE_OFF) {
1387 wl1271_error("cannot go into PLT state because not "
1388 "in off state: %d", wl->state);
1389 ret = -EBUSY;
1390 goto out;
1391 }
1392
Arik Nemtsov166d5042010-10-16 21:44:57 +02001393 wl->bss_type = BSS_TYPE_STA_BSS;
1394
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001395 while (retries) {
1396 retries--;
1397 ret = wl1271_chip_wakeup(wl);
1398 if (ret < 0)
1399 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001400
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001401 ret = wl1271_boot(wl);
1402 if (ret < 0)
1403 goto power_off;
1404
1405 ret = wl1271_plt_init(wl);
1406 if (ret < 0)
1407 goto irq_disable;
1408
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001409 wl->state = WL1271_STATE_PLT;
1410 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001411 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001412
Gery Kahn6f07b722011-07-18 14:21:49 +03001413 /* update hw/fw version info in wiphy struct */
1414 wiphy->hw_version = wl->chip.id;
1415 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1416 sizeof(wiphy->fw_version));
1417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418 goto out;
1419
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001420irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001421 mutex_unlock(&wl->mutex);
1422 /* Unlocking the mutex in the middle of handling is
1423 inherently unsafe. In this case we deem it safe to do,
1424 because we need to let any possibly pending IRQ out of
1425 the system (and while we are WL1271_STATE_OFF the IRQ
1426 work function will not do anything.) Also, any other
1427 possible concurrent operations will fail due to the
1428 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001429 wl1271_disable_interrupts(wl);
1430 wl1271_flush_deferred_work(wl);
1431 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001432 mutex_lock(&wl->mutex);
1433power_off:
1434 wl1271_power_off(wl);
1435 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001436
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001437 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1438 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001439out:
1440 mutex_unlock(&wl->mutex);
1441
1442 return ret;
1443}
1444
Luciano Coelho4623ec72011-03-21 19:26:41 +02001445static int __wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001446{
1447 int ret = 0;
1448
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449 wl1271_notice("power down");
1450
1451 if (wl->state != WL1271_STATE_PLT) {
1452 wl1271_error("cannot power down because not in PLT "
1453 "state: %d", wl->state);
1454 ret = -EBUSY;
1455 goto out;
1456 }
1457
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458 wl1271_power_off(wl);
1459
1460 wl->state = WL1271_STATE_OFF;
Luciano Coelhobd5ea182009-10-13 12:47:58 +03001461 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001462
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001463 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +02001464 wl1271_disable_interrupts(wl);
1465 wl1271_flush_deferred_work(wl);
1466 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001467 cancel_work_sync(&wl->recovery_work);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001468 mutex_lock(&wl->mutex);
1469out:
1470 return ret;
1471}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001472
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001473int wl1271_plt_stop(struct wl1271 *wl)
1474{
1475 int ret;
1476
1477 mutex_lock(&wl->mutex);
1478 ret = __wl1271_plt_stop(wl);
1479 mutex_unlock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480 return ret;
1481}
1482
Johannes Berg7bb45682011-02-24 14:42:06 +01001483static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001484{
1485 struct wl1271 *wl = hw->priv;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001486 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001487 int q, mapping;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001488 u8 hlid = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001489
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001490 mapping = skb_get_queue_mapping(skb);
1491 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001492
1493 if (wl->bss_type == BSS_TYPE_AP_BSS)
1494 hlid = wl1271_tx_get_hlid(skb);
1495
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001496 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001497
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001498 wl->tx_queue_count[q]++;
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001499
1500 /*
1501 * The workqueue is slow to process the tx_queue and we need stop
1502 * the queue here, otherwise the queue will get too long.
1503 */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001504 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001505 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1506 ieee80211_stop_queue(wl->hw, mapping);
1507 set_bit(q, &wl->stopped_queues_map);
Arik Nemtsovf4d08dd2011-02-23 00:22:24 +02001508 }
1509
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001510 /* queue the packet */
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001511 if (wl->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001512 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1513 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1514 } else {
1515 skb_queue_tail(&wl->tx_queue[q], skb);
1516 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001517
1518 /*
1519 * The chip specific setup must run before the first TX packet -
1520 * before that, the tx_work will not be initialized!
1521 */
1522
Ido Yarivb07d4032011-03-01 15:14:43 +02001523 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1524 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001525 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001526
1527 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001528}
1529
Shahar Leviae47c452011-03-06 16:32:14 +02001530int wl1271_tx_dummy_packet(struct wl1271 *wl)
1531{
Ido Yariv990f5de2011-03-31 10:06:59 +02001532 unsigned long flags;
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001533 int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001534
Ido Yariv990f5de2011-03-31 10:06:59 +02001535 spin_lock_irqsave(&wl->wl_lock, flags);
1536 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001537 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001538 spin_unlock_irqrestore(&wl->wl_lock, flags);
1539
1540 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1541 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
1542 wl1271_tx_work_locked(wl);
1543
1544 /*
1545 * If the FW TX is busy, TX work will be scheduled by the threaded
1546 * interrupt handler function
1547 */
1548 return 0;
1549}
1550
1551/*
1552 * The size of the dummy packet should be at least 1400 bytes. However, in
1553 * order to minimize the number of bus transactions, aligning it to 512 bytes
1554 * boundaries could be beneficial, performance wise
1555 */
1556#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1557
Luciano Coelhocf27d862011-04-01 21:08:23 +03001558static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001559{
1560 struct sk_buff *skb;
1561 struct ieee80211_hdr_3addr *hdr;
1562 unsigned int dummy_packet_size;
1563
1564 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1565 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1566
1567 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001568 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001569 wl1271_warning("Failed to allocate a dummy packet skb");
1570 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001571 }
1572
1573 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1574
1575 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1576 memset(hdr, 0, sizeof(*hdr));
1577 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001578 IEEE80211_STYPE_NULLFUNC |
1579 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001580
Ido Yariv990f5de2011-03-31 10:06:59 +02001581 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001582
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001583 /* Dummy packets require the TID to be management */
1584 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001585
1586 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001587 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001588 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001589
Ido Yariv990f5de2011-03-31 10:06:59 +02001590 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001591}
1592
Ido Yariv990f5de2011-03-31 10:06:59 +02001593
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001594static struct notifier_block wl1271_dev_notifier = {
1595 .notifier_call = wl1271_dev_notify,
1596};
1597
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001598#ifdef CONFIG_PM
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001599static int wl1271_configure_suspend_sta(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001600{
Eliad Pellere85d1622011-06-27 13:06:43 +03001601 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001602
Eliad Peller94390642011-05-13 11:57:13 +03001603 mutex_lock(&wl->mutex);
1604
Eliad Pellere85d1622011-06-27 13:06:43 +03001605 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
1606 goto out_unlock;
1607
Eliad Peller94390642011-05-13 11:57:13 +03001608 ret = wl1271_ps_elp_wakeup(wl);
1609 if (ret < 0)
1610 goto out_unlock;
1611
1612 /* enter psm if needed*/
1613 if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
1614 DECLARE_COMPLETION_ONSTACK(compl);
1615
1616 wl->ps_compl = &compl;
1617 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
1618 wl->basic_rate, true);
1619 if (ret < 0)
1620 goto out_sleep;
1621
1622 /* we must unlock here so we will be able to get events */
1623 wl1271_ps_elp_sleep(wl);
1624 mutex_unlock(&wl->mutex);
1625
1626 ret = wait_for_completion_timeout(
1627 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
1628 if (ret <= 0) {
1629 wl1271_warning("couldn't enter ps mode!");
1630 ret = -EBUSY;
1631 goto out;
1632 }
1633
1634 /* take mutex again, and wakeup */
1635 mutex_lock(&wl->mutex);
1636
1637 ret = wl1271_ps_elp_wakeup(wl);
1638 if (ret < 0)
1639 goto out_unlock;
1640 }
1641out_sleep:
1642 wl1271_ps_elp_sleep(wl);
1643out_unlock:
1644 mutex_unlock(&wl->mutex);
1645out:
1646 return ret;
1647
1648}
1649
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650static int wl1271_configure_suspend_ap(struct wl1271 *wl)
Eliad Peller94390642011-05-13 11:57:13 +03001651{
Eliad Pellere85d1622011-06-27 13:06:43 +03001652 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001653
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001654 mutex_lock(&wl->mutex);
1655
Eliad Pellere85d1622011-06-27 13:06:43 +03001656 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
1657 goto out_unlock;
1658
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001659 ret = wl1271_ps_elp_wakeup(wl);
1660 if (ret < 0)
1661 goto out_unlock;
1662
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001663 ret = wl1271_acx_beacon_filter_opt(wl, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664
1665 wl1271_ps_elp_sleep(wl);
1666out_unlock:
1667 mutex_unlock(&wl->mutex);
1668 return ret;
1669
1670}
1671
1672static int wl1271_configure_suspend(struct wl1271 *wl)
1673{
1674 if (wl->bss_type == BSS_TYPE_STA_BSS)
1675 return wl1271_configure_suspend_sta(wl);
1676 if (wl->bss_type == BSS_TYPE_AP_BSS)
1677 return wl1271_configure_suspend_ap(wl);
1678 return 0;
1679}
1680
1681static void wl1271_configure_resume(struct wl1271 *wl)
1682{
1683 int ret;
1684 bool is_sta = wl->bss_type == BSS_TYPE_STA_BSS;
1685 bool is_ap = wl->bss_type == BSS_TYPE_AP_BSS;
1686
1687 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001688 return;
1689
1690 mutex_lock(&wl->mutex);
1691 ret = wl1271_ps_elp_wakeup(wl);
1692 if (ret < 0)
1693 goto out;
1694
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001695 if (is_sta) {
1696 /* exit psm if it wasn't configured */
1697 if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
1698 wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
1699 wl->basic_rate, true);
1700 } else if (is_ap) {
Eliad Pellerf42bd2c2011-08-14 13:17:13 +03001701 wl1271_acx_beacon_filter_opt(wl, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001702 }
Eliad Peller94390642011-05-13 11:57:13 +03001703
1704 wl1271_ps_elp_sleep(wl);
1705out:
1706 mutex_unlock(&wl->mutex);
1707}
1708
Eliad Peller402e48612011-05-13 11:57:09 +03001709static int wl1271_op_suspend(struct ieee80211_hw *hw,
1710 struct cfg80211_wowlan *wow)
1711{
1712 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001713 int ret;
1714
Eliad Peller402e48612011-05-13 11:57:09 +03001715 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001716 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001717
Eliad Peller4a859df2011-06-06 12:21:52 +03001718 wl->wow_enabled = true;
1719 ret = wl1271_configure_suspend(wl);
1720 if (ret < 0) {
1721 wl1271_warning("couldn't prepare device to suspend");
1722 return ret;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001723 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 /* flush any remaining work */
1725 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001726
1727 /*
1728 * disable and re-enable interrupts in order to flush
1729 * the threaded_irq
1730 */
1731 wl1271_disable_interrupts(wl);
1732
1733 /*
1734 * set suspended flag to avoid triggering a new threaded_irq
1735 * work. no need for spinlock as interrupts are disabled.
1736 */
1737 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1738
1739 wl1271_enable_interrupts(wl);
1740 flush_work(&wl->tx_work);
1741 flush_delayed_work(&wl->pspoll_work);
1742 flush_delayed_work(&wl->elp_work);
1743
Eliad Peller402e48612011-05-13 11:57:09 +03001744 return 0;
1745}
1746
1747static int wl1271_op_resume(struct ieee80211_hw *hw)
1748{
1749 struct wl1271 *wl = hw->priv;
Eliad Peller4a859df2011-06-06 12:21:52 +03001750 unsigned long flags;
1751 bool run_irq_work = false;
1752
Eliad Peller402e48612011-05-13 11:57:09 +03001753 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1754 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001755 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001756
1757 /*
1758 * re-enable irq_work enqueuing, and call irq_work directly if
1759 * there is a pending work.
1760 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001761 spin_lock_irqsave(&wl->wl_lock, flags);
1762 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1763 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1764 run_irq_work = true;
1765 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001766
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 if (run_irq_work) {
1768 wl1271_debug(DEBUG_MAC80211,
1769 "run postponed irq_work directly");
1770 wl1271_irq(0, wl);
1771 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001772 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001773 wl1271_configure_resume(wl);
Eliad Pellerff91afc2011-06-06 12:21:53 +03001774 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001775
Eliad Peller402e48612011-05-13 11:57:09 +03001776 return 0;
1777}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001778#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001779
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001780static int wl1271_op_start(struct ieee80211_hw *hw)
1781{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001782 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1783
1784 /*
1785 * We have to delay the booting of the hardware because
1786 * we need to know the local MAC address before downloading and
1787 * initializing the firmware. The MAC address cannot be changed
1788 * after boot, and without the proper MAC address, the firmware
1789 * will not function properly.
1790 *
1791 * The MAC address is first known when the corresponding interface
1792 * is added. That is where we will initialize the hardware.
1793 */
1794
1795 return 0;
1796}
1797
1798static void wl1271_op_stop(struct ieee80211_hw *hw)
1799{
1800 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
1801}
1802
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001803static u8 wl12xx_get_role_type(struct wl1271 *wl)
1804{
1805 switch (wl->bss_type) {
1806 case BSS_TYPE_AP_BSS:
1807 return WL1271_ROLE_AP;
1808
1809 case BSS_TYPE_STA_BSS:
1810 return WL1271_ROLE_STA;
1811
1812 default:
1813 wl1271_error("invalid bss_type: %d", wl->bss_type);
1814 }
1815 return WL12XX_INVALID_ROLE_TYPE;
1816}
1817
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001818static int wl1271_op_add_interface(struct ieee80211_hw *hw,
1819 struct ieee80211_vif *vif)
1820{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001821 struct wl1271 *wl = hw->priv;
John W. Linvilleac01e942010-07-28 17:09:41 -04001822 struct wiphy *wiphy = hw->wiphy;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001823 int retries = WL1271_BOOT_RETRIES;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001824 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001825 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02001826 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001827
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001828 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
1829 vif->type, vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001830
1831 mutex_lock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001832 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02001833 wl1271_debug(DEBUG_MAC80211,
1834 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001835 ret = -EBUSY;
1836 goto out;
1837 }
1838
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001839 /*
1840 * in some very corner case HW recovery scenarios its possible to
1841 * get here before __wl1271_op_remove_interface is complete, so
1842 * opt out if that is the case.
1843 */
1844 if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
1845 ret = -EBUSY;
1846 goto out;
1847 }
1848
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001849 switch (vif->type) {
1850 case NL80211_IFTYPE_STATION:
1851 wl->bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001852 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001853 break;
1854 case NL80211_IFTYPE_ADHOC:
1855 wl->bss_type = BSS_TYPE_IBSS;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02001856 wl->set_bss_type = BSS_TYPE_STA_BSS;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001857 break;
Arik Nemtsov038d9252010-10-16 21:53:24 +02001858 case NL80211_IFTYPE_AP:
1859 wl->bss_type = BSS_TYPE_AP_BSS;
1860 break;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001861 default:
1862 ret = -EOPNOTSUPP;
1863 goto out;
1864 }
1865
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001866 role_type = wl12xx_get_role_type(wl);
1867 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
1868 ret = -EINVAL;
1869 goto out;
1870 }
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001871 memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001872
1873 if (wl->state != WL1271_STATE_OFF) {
1874 wl1271_error("cannot start because not in off state: %d",
1875 wl->state);
1876 ret = -EBUSY;
1877 goto out;
1878 }
1879
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001880 while (retries) {
1881 retries--;
1882 ret = wl1271_chip_wakeup(wl);
1883 if (ret < 0)
1884 goto power_off;
1885
1886 ret = wl1271_boot(wl);
1887 if (ret < 0)
1888 goto power_off;
1889
Eliad Peller04e80792011-08-14 13:17:09 +03001890 if (wl->bss_type == BSS_TYPE_STA_BSS) {
1891 /*
1892 * The device role is a special role used for
1893 * rx and tx frames prior to association (as
1894 * the STA role can get packets only from
1895 * its associated bssid)
1896 */
1897 ret = wl12xx_cmd_role_enable(wl,
1898 WL1271_ROLE_DEVICE,
1899 &wl->dev_role_id);
1900 if (ret < 0)
1901 goto irq_disable;
1902 }
1903
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001904 ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id);
1905 if (ret < 0)
1906 goto irq_disable;
1907
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001908 ret = wl1271_hw_init(wl);
1909 if (ret < 0)
1910 goto irq_disable;
1911
Eliad Peller71125ab2010-10-28 21:46:43 +02001912 booted = true;
1913 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001914
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001915irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001916 mutex_unlock(&wl->mutex);
1917 /* Unlocking the mutex in the middle of handling is
1918 inherently unsafe. In this case we deem it safe to do,
1919 because we need to let any possibly pending IRQ out of
1920 the system (and while we are WL1271_STATE_OFF the IRQ
1921 work function will not do anything.) Also, any other
1922 possible concurrent operations will fail due to the
1923 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001924 wl1271_disable_interrupts(wl);
1925 wl1271_flush_deferred_work(wl);
1926 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001927 mutex_lock(&wl->mutex);
1928power_off:
1929 wl1271_power_off(wl);
1930 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001931
Eliad Peller71125ab2010-10-28 21:46:43 +02001932 if (!booted) {
1933 wl1271_error("firmware boot failed despite %d retries",
1934 WL1271_BOOT_RETRIES);
1935 goto out;
1936 }
1937
1938 wl->vif = vif;
1939 wl->state = WL1271_STATE_ON;
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001940 set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001941 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
Eliad Peller71125ab2010-10-28 21:46:43 +02001942
1943 /* update hw/fw version info in wiphy struct */
1944 wiphy->hw_version = wl->chip.id;
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001945 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
Eliad Peller71125ab2010-10-28 21:46:43 +02001946 sizeof(wiphy->fw_version));
1947
Luciano Coelhofb6a6812010-12-03 17:05:40 +02001948 /*
1949 * Now we know if 11a is supported (info from the NVS), so disable
1950 * 11a channels if not supported
1951 */
1952 if (!wl->enable_11a)
1953 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
1954
1955 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
1956 wl->enable_11a ? "" : "not ");
1957
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03001958out:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001959 mutex_unlock(&wl->mutex);
1960
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001961 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03001962 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001963 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001964 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001965
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001966 return ret;
1967}
1968
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001969static void __wl1271_op_remove_interface(struct wl1271 *wl,
1970 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001971{
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001972 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001973
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001974 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001975
Juuso Oikarinen13026de2011-03-29 16:43:50 +03001976 /* because of hardware recovery, we may get here twice */
1977 if (wl->state != WL1271_STATE_ON)
1978 return;
1979
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001980 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001981
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001982 mutex_lock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001983 list_del(&wl->list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02001984 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03001985
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001986 /* enable dyn ps just in case (if left on due to fw crash etc) */
Juuso Oikarinen9a547bf2010-07-08 17:50:04 +03001987 if (wl->bss_type == BSS_TYPE_STA_BSS)
Juuso Oikarinenf532be62010-07-08 17:50:05 +03001988 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03001989
Luciano Coelho08688d62010-07-08 17:50:07 +03001990 if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
Luciano Coelho08688d62010-07-08 17:50:07 +03001991 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02001992 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Juuso Oikarinenb739a422010-10-26 13:24:38 +02001993 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03001994 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001995 }
1996
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001997 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
1998 /* disable active roles */
1999 ret = wl1271_ps_elp_wakeup(wl);
2000 if (ret < 0)
2001 goto deinit;
2002
Eliad Peller04e80792011-08-14 13:17:09 +03002003 if (wl->bss_type == BSS_TYPE_STA_BSS) {
2004 ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id);
2005 if (ret < 0)
2006 goto deinit;
2007 }
2008
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002009 ret = wl12xx_cmd_role_disable(wl, &wl->role_id);
2010 if (ret < 0)
2011 goto deinit;
2012
2013 wl1271_ps_elp_sleep(wl);
2014 }
2015deinit:
2016 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002017 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002018
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002019 /*
2020 * this must be before the cancel_work calls below, so that the work
2021 * functions don't perform further work.
2022 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002023 wl->state = WL1271_STATE_OFF;
2024
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002025 mutex_unlock(&wl->mutex);
2026
Ido Yariva6208652011-03-01 15:14:41 +02002027 wl1271_disable_interrupts(wl);
2028 wl1271_flush_deferred_work(wl);
Juuso Oikarinen78abd322010-09-21 06:23:32 +02002029 cancel_delayed_work_sync(&wl->scan_complete_work);
Ido Yariva6208652011-03-01 15:14:41 +02002030 cancel_work_sync(&wl->netstack_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002031 cancel_work_sync(&wl->tx_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03002032 del_timer_sync(&wl->rx_streaming_timer);
2033 cancel_work_sync(&wl->rx_streaming_enable_work);
2034 cancel_work_sync(&wl->rx_streaming_disable_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002035 cancel_delayed_work_sync(&wl->pspoll_work);
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02002036 cancel_delayed_work_sync(&wl->elp_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002037
2038 mutex_lock(&wl->mutex);
2039
2040 /* let's notify MAC80211 about the remaining pending TX frames */
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002041 wl1271_tx_reset(wl, reset_tx_queues);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002042 wl1271_power_off(wl);
2043
2044 memset(wl->bssid, 0, ETH_ALEN);
Johannes Berg3b40c042011-07-13 10:39:16 +02002045 memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002046 wl->ssid_len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002047 wl->bss_type = MAX_BSS_TYPE;
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02002048 wl->set_bss_type = MAX_BSS_TYPE;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002049 wl->band = IEEE80211_BAND_2GHZ;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002050
2051 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02002052 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002053 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
2054 wl->tx_blocks_available = 0;
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +03002055 wl->tx_allocated_blocks = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002056 wl->tx_results_count = 0;
2057 wl->tx_packets_count = 0;
2058 wl->time_offset = 0;
2059 wl->session_counter = 0;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002060 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061 wl->vif = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002062 wl1271_free_ap_keys(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02002063 memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
Arik Nemtsovb622d992011-02-23 00:22:31 +02002064 wl->ap_fw_ps_map = 0;
2065 wl->ap_ps_map = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002066 wl->sched_scanning = false;
Eliad Peller7f0979882011-08-14 13:17:06 +03002067 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03002068 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerc690ec82011-08-14 13:17:07 +03002069 memset(wl->roles_map, 0, sizeof(wl->roles_map));
2070 memset(wl->links_map, 0, sizeof(wl->links_map));
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002071
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002072 /*
2073 * this is performed after the cancel_work calls and the associated
2074 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2075 * get executed before all these vars have been reset.
2076 */
2077 wl->flags = 0;
2078
Eliad Peller4d56ad92011-08-14 13:17:05 +03002079 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002080
2081 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002082
2083 kfree(wl->fw_status);
2084 wl->fw_status = NULL;
2085 kfree(wl->tx_res_if);
2086 wl->tx_res_if = NULL;
2087 kfree(wl->target_mem_map);
2088 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002089}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002090
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002091static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2092 struct ieee80211_vif *vif)
2093{
2094 struct wl1271 *wl = hw->priv;
2095
2096 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002097 /*
2098 * wl->vif can be null here if someone shuts down the interface
2099 * just when hardware recovery has been started.
2100 */
2101 if (wl->vif) {
2102 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002103 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002104 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002105
Juuso Oikarinen67353292010-11-18 15:19:02 +02002106 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002107 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002108}
2109
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002110static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002111{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002112 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002113 /* we need to use a dummy BSSID for now */
2114 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
2115 0xad, 0xbe, 0xef };
2116
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002117 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
2118
Eliad Pellerc690ec82011-08-14 13:17:07 +03002119 ret = wl12xx_cmd_role_start_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002120 if (ret < 0)
2121 goto out;
2122
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002123 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002124
2125out:
2126 return ret;
2127}
2128
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002129static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002130{
2131 int ret;
2132
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002133 /*
2134 * One of the side effects of the JOIN command is that is clears
2135 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2136 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002137 * Currently the only valid scenario for JOIN during association
2138 * is on roaming, in which case we will also be given new keys.
2139 * Keep the below message for now, unless it starts bothering
2140 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002141 */
2142 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2143 wl1271_info("JOIN while associated.");
2144
2145 if (set_assoc)
2146 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2147
Eliad Pellerc690ec82011-08-14 13:17:07 +03002148 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002149 if (ret < 0)
2150 goto out;
2151
2152 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2153
2154 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2155 goto out;
2156
2157 /*
2158 * The join command disable the keep-alive mode, shut down its process,
2159 * and also clear the template config, so we need to reset it all after
2160 * the join. The acx_aid starts the keep-alive process, and the order
2161 * of the commands below is relevant.
2162 */
2163 ret = wl1271_acx_keep_alive_mode(wl, true);
2164 if (ret < 0)
2165 goto out;
2166
2167 ret = wl1271_acx_aid(wl, wl->aid);
2168 if (ret < 0)
2169 goto out;
2170
2171 ret = wl1271_cmd_build_klv_null_data(wl);
2172 if (ret < 0)
2173 goto out;
2174
2175 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2176 ACX_KEEP_ALIVE_TPL_VALID);
2177 if (ret < 0)
2178 goto out;
2179
2180out:
2181 return ret;
2182}
2183
2184static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002185{
2186 int ret;
2187
2188 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002189 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002190 if (ret < 0)
2191 goto out;
2192
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002193 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002194 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002195
Oz Krakowskib992c682011-06-26 10:36:02 +03002196 /* reset TX security counters on a clean disconnect */
2197 wl->tx_security_last_seq_lsb = 0;
2198 wl->tx_security_seq = 0;
2199
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002200out:
2201 return ret;
2202}
2203
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002204static void wl1271_set_band_rate(struct wl1271 *wl)
2205{
2206 if (wl->band == IEEE80211_BAND_2GHZ)
2207 wl->basic_rate_set = wl->conf.tx.basic_rate;
2208 else
2209 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2210}
2211
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002212static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002213{
2214 int ret;
2215
2216 if (idle) {
2217 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2218 ret = wl1271_unjoin(wl);
2219 if (ret < 0)
2220 goto out;
2221 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002222 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002223 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002224 if (ret < 0)
2225 goto out;
2226 ret = wl1271_acx_keep_alive_config(
2227 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2228 ACX_KEEP_ALIVE_TPL_INVALID);
2229 if (ret < 0)
2230 goto out;
2231 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2232 } else {
2233 /* increment the session counter */
2234 wl->session_counter++;
2235 if (wl->session_counter >= SESSION_COUNTER_MAX)
2236 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002237
2238 /* The current firmware only supports sched_scan in idle */
2239 if (wl->sched_scanning) {
2240 wl1271_scan_sched_scan_stop(wl);
2241 ieee80211_sched_scan_stopped(wl->hw);
2242 }
2243
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002244 ret = wl1271_dummy_join(wl);
2245 if (ret < 0)
2246 goto out;
2247 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2248 }
2249
2250out:
2251 return ret;
2252}
2253
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002254static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2255{
2256 struct wl1271 *wl = hw->priv;
2257 struct ieee80211_conf *conf = &hw->conf;
2258 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002259 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002260
2261 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2262
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002263 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2264 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002265 channel,
2266 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002267 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002268 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2269 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002270
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002271 /*
2272 * mac80211 will go to idle nearly immediately after transmitting some
2273 * frames, such as the deauth. To make sure those frames reach the air,
2274 * wait here until the TX queue is fully flushed.
2275 */
2276 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2277 (conf->flags & IEEE80211_CONF_IDLE))
2278 wl1271_tx_flush(wl);
2279
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002280 mutex_lock(&wl->mutex);
2281
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002282 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002283 /* we support configuring the channel and band while off */
2284 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2285 wl->band = conf->channel->band;
2286 wl->channel = channel;
2287 }
2288
Arik Nemtsov097f8822011-06-27 22:06:34 +03002289 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2290 wl->power_level = conf->power_level;
2291
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002292 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002293 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002294
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002295 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2296
Ido Yariva6208652011-03-01 15:14:41 +02002297 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002298 if (ret < 0)
2299 goto out;
2300
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002301 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002302 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2303 ((wl->band != conf->channel->band) ||
2304 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002305 wl->band = conf->channel->band;
2306 wl->channel = channel;
2307
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002308 if (!is_ap) {
2309 /*
2310 * FIXME: the mac80211 should really provide a fixed
2311 * rate to use here. for now, just use the smallest
2312 * possible rate for the band as a fixed rate for
2313 * association frames and other control messages.
2314 */
2315 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2316 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002317
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002318 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2319 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002320 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002321 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002322 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002323
2324 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2325 ret = wl1271_join(wl, false);
2326 if (ret < 0)
2327 wl1271_warning("cmd join on channel "
2328 "failed %d", ret);
2329 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002330 }
2331 }
2332
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002333 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2334 ret = wl1271_sta_handle_idle(wl,
2335 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002336 if (ret < 0)
2337 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002338 }
2339
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002340 /*
2341 * if mac80211 changes the PSM mode, make sure the mode is not
2342 * incorrectly changed after the pspoll failure active window.
2343 */
2344 if (changed & IEEE80211_CONF_CHANGE_PS)
2345 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2346
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002347 if (conf->flags & IEEE80211_CONF_PS &&
2348 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2349 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002350
2351 /*
2352 * We enter PSM only if we're already associated.
2353 * If we're not, we'll enter it when joining an SSID,
2354 * through the bss_info_changed() hook.
2355 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002356 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002357 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002358 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002359 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002360 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002361 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002362 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002363 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002365 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002366
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002367 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002368 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002369 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002370 }
2371
2372 if (conf->power_level != wl->power_level) {
2373 ret = wl1271_acx_tx_power(wl, conf->power_level);
2374 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002375 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002376
2377 wl->power_level = conf->power_level;
2378 }
2379
2380out_sleep:
2381 wl1271_ps_elp_sleep(wl);
2382
2383out:
2384 mutex_unlock(&wl->mutex);
2385
2386 return ret;
2387}
2388
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002389struct wl1271_filter_params {
2390 bool enabled;
2391 int mc_list_length;
2392 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2393};
2394
Jiri Pirko22bedad32010-04-01 21:22:57 +00002395static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2396 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002397{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002398 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002399 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002400 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002401
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002402 if (unlikely(wl->state == WL1271_STATE_OFF))
2403 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002404
Juuso Oikarinen74441132009-10-13 12:47:53 +03002405 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002406 if (!fp) {
2407 wl1271_error("Out of memory setting filters.");
2408 return 0;
2409 }
2410
2411 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002412 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002413 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2414 fp->enabled = false;
2415 } else {
2416 fp->enabled = true;
2417 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002418 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002419 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002420 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002421 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002422 }
2423
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002424 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002425}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002426
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002427#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2428 FIF_ALLMULTI | \
2429 FIF_FCSFAIL | \
2430 FIF_BCN_PRBRESP_PROMISC | \
2431 FIF_CONTROL | \
2432 FIF_OTHER_BSS)
2433
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002434static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2435 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002436 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002438 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002439 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002440 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002441
Arik Nemtsov7d057862010-10-16 19:25:35 +02002442 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2443 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002445 mutex_lock(&wl->mutex);
2446
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002447 *total &= WL1271_SUPPORTED_FILTERS;
2448 changed &= WL1271_SUPPORTED_FILTERS;
2449
2450 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002451 goto out;
2452
Ido Yariva6208652011-03-01 15:14:41 +02002453 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002454 if (ret < 0)
2455 goto out;
2456
Arik Nemtsov7d057862010-10-16 19:25:35 +02002457 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2458 if (*total & FIF_ALLMULTI)
2459 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2460 else if (fp)
2461 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2462 fp->mc_list,
2463 fp->mc_list_length);
2464 if (ret < 0)
2465 goto out_sleep;
2466 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002467
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002468 /*
2469 * the fw doesn't provide an api to configure the filters. instead,
2470 * the filters configuration is based on the active roles / ROC
2471 * state.
2472 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002473
2474out_sleep:
2475 wl1271_ps_elp_sleep(wl);
2476
2477out:
2478 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002479 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002480}
2481
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002482static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2483 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2484 u16 tx_seq_16)
2485{
2486 struct wl1271_ap_key *ap_key;
2487 int i;
2488
2489 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2490
2491 if (key_size > MAX_KEY_SIZE)
2492 return -EINVAL;
2493
2494 /*
2495 * Find next free entry in ap_keys. Also check we are not replacing
2496 * an existing key.
2497 */
2498 for (i = 0; i < MAX_NUM_KEYS; i++) {
2499 if (wl->recorded_ap_keys[i] == NULL)
2500 break;
2501
2502 if (wl->recorded_ap_keys[i]->id == id) {
2503 wl1271_warning("trying to record key replacement");
2504 return -EINVAL;
2505 }
2506 }
2507
2508 if (i == MAX_NUM_KEYS)
2509 return -EBUSY;
2510
2511 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2512 if (!ap_key)
2513 return -ENOMEM;
2514
2515 ap_key->id = id;
2516 ap_key->key_type = key_type;
2517 ap_key->key_size = key_size;
2518 memcpy(ap_key->key, key, key_size);
2519 ap_key->hlid = hlid;
2520 ap_key->tx_seq_32 = tx_seq_32;
2521 ap_key->tx_seq_16 = tx_seq_16;
2522
2523 wl->recorded_ap_keys[i] = ap_key;
2524 return 0;
2525}
2526
2527static void wl1271_free_ap_keys(struct wl1271 *wl)
2528{
2529 int i;
2530
2531 for (i = 0; i < MAX_NUM_KEYS; i++) {
2532 kfree(wl->recorded_ap_keys[i]);
2533 wl->recorded_ap_keys[i] = NULL;
2534 }
2535}
2536
2537static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2538{
2539 int i, ret = 0;
2540 struct wl1271_ap_key *key;
2541 bool wep_key_added = false;
2542
2543 for (i = 0; i < MAX_NUM_KEYS; i++) {
2544 if (wl->recorded_ap_keys[i] == NULL)
2545 break;
2546
2547 key = wl->recorded_ap_keys[i];
2548 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2549 key->id, key->key_type,
2550 key->key_size, key->key,
2551 key->hlid, key->tx_seq_32,
2552 key->tx_seq_16);
2553 if (ret < 0)
2554 goto out;
2555
2556 if (key->key_type == KEY_WEP)
2557 wep_key_added = true;
2558 }
2559
2560 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002561 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
2562 WL1271_AP_BROADCAST_HLID);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002563 if (ret < 0)
2564 goto out;
2565 }
2566
2567out:
2568 wl1271_free_ap_keys(wl);
2569 return ret;
2570}
2571
2572static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2573 u8 key_size, const u8 *key, u32 tx_seq_32,
2574 u16 tx_seq_16, struct ieee80211_sta *sta)
2575{
2576 int ret;
2577 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2578
2579 if (is_ap) {
2580 struct wl1271_station *wl_sta;
2581 u8 hlid;
2582
2583 if (sta) {
2584 wl_sta = (struct wl1271_station *)sta->drv_priv;
2585 hlid = wl_sta->hlid;
2586 } else {
2587 hlid = WL1271_AP_BROADCAST_HLID;
2588 }
2589
2590 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2591 /*
2592 * We do not support removing keys after AP shutdown.
2593 * Pretend we do to make mac80211 happy.
2594 */
2595 if (action != KEY_ADD_OR_REPLACE)
2596 return 0;
2597
2598 ret = wl1271_record_ap_key(wl, id,
2599 key_type, key_size,
2600 key, hlid, tx_seq_32,
2601 tx_seq_16);
2602 } else {
2603 ret = wl1271_cmd_set_ap_key(wl, action,
2604 id, key_type, key_size,
2605 key, hlid, tx_seq_32,
2606 tx_seq_16);
2607 }
2608
2609 if (ret < 0)
2610 return ret;
2611 } else {
2612 const u8 *addr;
2613 static const u8 bcast_addr[ETH_ALEN] = {
2614 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2615 };
2616
2617 addr = sta ? sta->addr : bcast_addr;
2618
2619 if (is_zero_ether_addr(addr)) {
2620 /* We dont support TX only encryption */
2621 return -EOPNOTSUPP;
2622 }
2623
2624 /* The wl1271 does not allow to remove unicast keys - they
2625 will be cleared automatically on next CMD_JOIN. Ignore the
2626 request silently, as we dont want the mac80211 to emit
2627 an error message. */
2628 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2629 return 0;
2630
2631 ret = wl1271_cmd_set_sta_key(wl, action,
2632 id, key_type, key_size,
2633 key, addr, tx_seq_32,
2634 tx_seq_16);
2635 if (ret < 0)
2636 return ret;
2637
2638 /* the default WEP key needs to be configured at least once */
2639 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002640 ret = wl12xx_cmd_set_default_wep_key(wl,
2641 wl->default_key,
2642 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002643 if (ret < 0)
2644 return ret;
2645 }
2646 }
2647
2648 return 0;
2649}
2650
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002651static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2652 struct ieee80211_vif *vif,
2653 struct ieee80211_sta *sta,
2654 struct ieee80211_key_conf *key_conf)
2655{
2656 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002657 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002658 u32 tx_seq_32 = 0;
2659 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002660 u8 key_type;
2661
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002662 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2663
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002664 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002666 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667 key_conf->keylen, key_conf->flags);
2668 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2669
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002670 mutex_lock(&wl->mutex);
2671
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002672 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2673 ret = -EAGAIN;
2674 goto out_unlock;
2675 }
2676
Ido Yariva6208652011-03-01 15:14:41 +02002677 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678 if (ret < 0)
2679 goto out_unlock;
2680
Johannes Berg97359d12010-08-10 09:46:38 +02002681 switch (key_conf->cipher) {
2682 case WLAN_CIPHER_SUITE_WEP40:
2683 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684 key_type = KEY_WEP;
2685
2686 key_conf->hw_key_idx = key_conf->keyidx;
2687 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002688 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002689 key_type = KEY_TKIP;
2690
2691 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002692 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2693 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002694 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002695 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002696 key_type = KEY_AES;
2697
2698 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002699 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2700 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002701 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002702 case WL1271_CIPHER_SUITE_GEM:
2703 key_type = KEY_GEM;
2704 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2705 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2706 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002707 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002708 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002709
2710 ret = -EOPNOTSUPP;
2711 goto out_sleep;
2712 }
2713
2714 switch (cmd) {
2715 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002716 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2717 key_conf->keyidx, key_type,
2718 key_conf->keylen, key_conf->key,
2719 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720 if (ret < 0) {
2721 wl1271_error("Could not add or replace key");
2722 goto out_sleep;
2723 }
2724 break;
2725
2726 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 ret = wl1271_set_key(wl, KEY_REMOVE,
2728 key_conf->keyidx, key_type,
2729 key_conf->keylen, key_conf->key,
2730 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002731 if (ret < 0) {
2732 wl1271_error("Could not remove key");
2733 goto out_sleep;
2734 }
2735 break;
2736
2737 default:
2738 wl1271_error("Unsupported key cmd 0x%x", cmd);
2739 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002740 break;
2741 }
2742
2743out_sleep:
2744 wl1271_ps_elp_sleep(wl);
2745
2746out_unlock:
2747 mutex_unlock(&wl->mutex);
2748
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002749 return ret;
2750}
2751
2752static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002753 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002754 struct cfg80211_scan_request *req)
2755{
2756 struct wl1271 *wl = hw->priv;
2757 int ret;
2758 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002759 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002760
2761 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2762
2763 if (req->n_ssids) {
2764 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002765 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002766 }
2767
2768 mutex_lock(&wl->mutex);
2769
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002770 if (wl->state == WL1271_STATE_OFF) {
2771 /*
2772 * We cannot return -EBUSY here because cfg80211 will expect
2773 * a call to ieee80211_scan_completed if we do - in this case
2774 * there won't be any call.
2775 */
2776 ret = -EAGAIN;
2777 goto out;
2778 }
2779
Ido Yariva6208652011-03-01 15:14:41 +02002780 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002781 if (ret < 0)
2782 goto out;
2783
Luciano Coelho5924f892010-08-04 03:46:22 +03002784 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002785
2786 wl1271_ps_elp_sleep(wl);
2787
2788out:
2789 mutex_unlock(&wl->mutex);
2790
2791 return ret;
2792}
2793
Eliad Peller73ecce32011-06-27 13:06:45 +03002794static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2795 struct ieee80211_vif *vif)
2796{
2797 struct wl1271 *wl = hw->priv;
2798 int ret;
2799
2800 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2801
2802 mutex_lock(&wl->mutex);
2803
2804 if (wl->state == WL1271_STATE_OFF)
2805 goto out;
2806
2807 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2808 goto out;
2809
2810 ret = wl1271_ps_elp_wakeup(wl);
2811 if (ret < 0)
2812 goto out;
2813
2814 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2815 ret = wl1271_scan_stop(wl);
2816 if (ret < 0)
2817 goto out_sleep;
2818 }
2819 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2820 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2821 wl->scan.req = NULL;
2822 ieee80211_scan_completed(wl->hw, true);
2823
2824out_sleep:
2825 wl1271_ps_elp_sleep(wl);
2826out:
2827 mutex_unlock(&wl->mutex);
2828
2829 cancel_delayed_work_sync(&wl->scan_complete_work);
2830}
2831
Luciano Coelho33c2c062011-05-10 14:46:02 +03002832static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2833 struct ieee80211_vif *vif,
2834 struct cfg80211_sched_scan_request *req,
2835 struct ieee80211_sched_scan_ies *ies)
2836{
2837 struct wl1271 *wl = hw->priv;
2838 int ret;
2839
2840 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2841
2842 mutex_lock(&wl->mutex);
2843
2844 ret = wl1271_ps_elp_wakeup(wl);
2845 if (ret < 0)
2846 goto out;
2847
2848 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2849 if (ret < 0)
2850 goto out_sleep;
2851
2852 ret = wl1271_scan_sched_scan_start(wl);
2853 if (ret < 0)
2854 goto out_sleep;
2855
2856 wl->sched_scanning = true;
2857
2858out_sleep:
2859 wl1271_ps_elp_sleep(wl);
2860out:
2861 mutex_unlock(&wl->mutex);
2862 return ret;
2863}
2864
2865static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2866 struct ieee80211_vif *vif)
2867{
2868 struct wl1271 *wl = hw->priv;
2869 int ret;
2870
2871 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2872
2873 mutex_lock(&wl->mutex);
2874
2875 ret = wl1271_ps_elp_wakeup(wl);
2876 if (ret < 0)
2877 goto out;
2878
2879 wl1271_scan_sched_scan_stop(wl);
2880
2881 wl1271_ps_elp_sleep(wl);
2882out:
2883 mutex_unlock(&wl->mutex);
2884}
2885
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002886static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2887{
2888 struct wl1271 *wl = hw->priv;
2889 int ret = 0;
2890
2891 mutex_lock(&wl->mutex);
2892
2893 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2894 ret = -EAGAIN;
2895 goto out;
2896 }
2897
Ido Yariva6208652011-03-01 15:14:41 +02002898 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002899 if (ret < 0)
2900 goto out;
2901
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002902 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002903 if (ret < 0)
2904 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2905
2906 wl1271_ps_elp_sleep(wl);
2907
2908out:
2909 mutex_unlock(&wl->mutex);
2910
2911 return ret;
2912}
2913
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2915{
2916 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002917 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002918
2919 mutex_lock(&wl->mutex);
2920
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002921 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2922 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002923 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002924 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002925
Ido Yariva6208652011-03-01 15:14:41 +02002926 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002927 if (ret < 0)
2928 goto out;
2929
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002930 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 if (ret < 0)
2932 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2933
2934 wl1271_ps_elp_sleep(wl);
2935
2936out:
2937 mutex_unlock(&wl->mutex);
2938
2939 return ret;
2940}
2941
Arik Nemtsove78a2872010-10-16 19:07:21 +02002942static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002943 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002944{
Eliad Peller889cb362011-05-01 09:56:45 +03002945 u8 ssid_len;
2946 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2947 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002948
Eliad Peller889cb362011-05-01 09:56:45 +03002949 if (!ptr) {
2950 wl1271_error("No SSID in IEs!");
2951 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002952 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002953
Eliad Peller889cb362011-05-01 09:56:45 +03002954 ssid_len = ptr[1];
2955 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2956 wl1271_error("SSID is too long!");
2957 return -EINVAL;
2958 }
2959
2960 wl->ssid_len = ssid_len;
2961 memcpy(wl->ssid, ptr+2, ssid_len);
2962 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002963}
2964
Arik Nemtsove78a2872010-10-16 19:07:21 +02002965static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2966 struct ieee80211_bss_conf *bss_conf,
2967 u32 changed)
2968{
2969 int ret = 0;
2970
2971 if (changed & BSS_CHANGED_ERP_SLOT) {
2972 if (bss_conf->use_short_slot)
2973 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2974 else
2975 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2976 if (ret < 0) {
2977 wl1271_warning("Set slot time failed %d", ret);
2978 goto out;
2979 }
2980 }
2981
2982 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2983 if (bss_conf->use_short_preamble)
2984 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2985 else
2986 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2987 }
2988
2989 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2990 if (bss_conf->use_cts_prot)
2991 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2992 else
2993 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2994 if (ret < 0) {
2995 wl1271_warning("Set ctsprotect failed %d", ret);
2996 goto out;
2997 }
2998 }
2999
3000out:
3001 return ret;
3002}
3003
3004static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3005 struct ieee80211_vif *vif,
3006 struct ieee80211_bss_conf *bss_conf,
3007 u32 changed)
3008{
3009 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3010 int ret = 0;
3011
3012 if ((changed & BSS_CHANGED_BEACON_INT)) {
3013 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3014 bss_conf->beacon_int);
3015
3016 wl->beacon_int = bss_conf->beacon_int;
3017 }
3018
3019 if ((changed & BSS_CHANGED_BEACON)) {
3020 struct ieee80211_hdr *hdr;
3021 int ieoffset = offsetof(struct ieee80211_mgmt,
3022 u.beacon.variable);
3023 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3024 u16 tmpl_id;
3025
3026 if (!beacon)
3027 goto out;
3028
3029 wl1271_debug(DEBUG_MASTER, "beacon updated");
3030
3031 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3032 if (ret < 0) {
3033 dev_kfree_skb(beacon);
3034 goto out;
3035 }
3036 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3037 CMD_TEMPL_BEACON;
3038 ret = wl1271_cmd_template_set(wl, tmpl_id,
3039 beacon->data,
3040 beacon->len, 0,
3041 wl1271_tx_min_rate_get(wl));
3042 if (ret < 0) {
3043 dev_kfree_skb(beacon);
3044 goto out;
3045 }
3046
3047 hdr = (struct ieee80211_hdr *) beacon->data;
3048 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3049 IEEE80211_STYPE_PROBE_RESP);
3050
3051 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3052 CMD_TEMPL_PROBE_RESPONSE;
3053 ret = wl1271_cmd_template_set(wl,
3054 tmpl_id,
3055 beacon->data,
3056 beacon->len, 0,
3057 wl1271_tx_min_rate_get(wl));
3058 dev_kfree_skb(beacon);
3059 if (ret < 0)
3060 goto out;
3061 }
3062
3063out:
3064 return ret;
3065}
3066
3067/* AP mode changes */
3068static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003069 struct ieee80211_vif *vif,
3070 struct ieee80211_bss_conf *bss_conf,
3071 u32 changed)
3072{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003073 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074
Arik Nemtsove78a2872010-10-16 19:07:21 +02003075 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3076 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077
Arik Nemtsove78a2872010-10-16 19:07:21 +02003078 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3079 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080
Arik Nemtsov70f47422011-04-18 14:15:25 +03003081 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003082 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003083 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003084 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003085 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003086
3087 ret = wl1271_ap_init_templates(wl);
3088 if (ret < 0)
3089 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003090 }
3091
Arik Nemtsove78a2872010-10-16 19:07:21 +02003092 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3093 if (ret < 0)
3094 goto out;
3095
3096 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3097 if (bss_conf->enable_beacon) {
3098 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003099 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003100 if (ret < 0)
3101 goto out;
3102
3103 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3104 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003105
3106 ret = wl1271_ap_init_hwenc(wl);
3107 if (ret < 0)
3108 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003109 }
3110 } else {
3111 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003112 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003113 if (ret < 0)
3114 goto out;
3115
3116 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3117 wl1271_debug(DEBUG_AP, "stopped AP");
3118 }
3119 }
3120 }
3121
3122 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3123 if (ret < 0)
3124 goto out;
3125out:
3126 return;
3127}
3128
3129/* STA/IBSS mode changes */
3130static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3131 struct ieee80211_vif *vif,
3132 struct ieee80211_bss_conf *bss_conf,
3133 u32 changed)
3134{
3135 bool do_join = false, set_assoc = false;
3136 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003137 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003138 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003139 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003140 bool sta_exists = false;
3141 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003142
3143 if (is_ibss) {
3144 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3145 changed);
3146 if (ret < 0)
3147 goto out;
3148 }
3149
3150 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
3151 do_join = true;
3152
3153 /* Need to update the SSID (for filtering etc) */
3154 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
3155 do_join = true;
3156
3157 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003158 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3159 bss_conf->enable_beacon ? "enabled" : "disabled");
3160
3161 if (bss_conf->enable_beacon)
3162 wl->set_bss_type = BSS_TYPE_IBSS;
3163 else
3164 wl->set_bss_type = BSS_TYPE_STA_BSS;
3165 do_join = true;
3166 }
3167
Arik Nemtsove78a2872010-10-16 19:07:21 +02003168 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003169 bool enable = false;
3170 if (bss_conf->cqm_rssi_thold)
3171 enable = true;
3172 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3173 bss_conf->cqm_rssi_thold,
3174 bss_conf->cqm_rssi_hyst);
3175 if (ret < 0)
3176 goto out;
3177 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3178 }
3179
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003180 if ((changed & BSS_CHANGED_BSSID) &&
3181 /*
3182 * Now we know the correct bssid, so we send a new join command
3183 * and enable the BSSID filter
3184 */
3185 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003186 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003187
Eliad Pellerfa287b82010-12-26 09:27:50 +01003188 if (!is_zero_ether_addr(wl->bssid)) {
3189 ret = wl1271_cmd_build_null_data(wl);
3190 if (ret < 0)
3191 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003192
Eliad Pellerfa287b82010-12-26 09:27:50 +01003193 ret = wl1271_build_qos_null_data(wl);
3194 if (ret < 0)
3195 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003196
Eliad Pellerfa287b82010-12-26 09:27:50 +01003197 /* Need to update the BSSID (for filtering etc) */
3198 do_join = true;
3199 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003200 }
3201
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003202 rcu_read_lock();
3203 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3204 if (sta) {
3205 /* save the supp_rates of the ap */
3206 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3207 if (sta->ht_cap.ht_supported)
3208 sta_rate_set |=
3209 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003210 sta_ht_cap = sta->ht_cap;
3211 sta_exists = true;
3212 }
3213 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003214
Arik Nemtsova1008852011-02-12 23:24:20 +02003215 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003216 /* handle new association with HT and HT information change */
3217 if ((changed & BSS_CHANGED_HT) &&
3218 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003219 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003220 true);
3221 if (ret < 0) {
3222 wl1271_warning("Set ht cap true failed %d",
3223 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003224 goto out;
3225 }
3226 ret = wl1271_acx_set_ht_information(wl,
3227 bss_conf->ht_operation_mode);
3228 if (ret < 0) {
3229 wl1271_warning("Set ht information failed %d",
3230 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003231 goto out;
3232 }
3233 }
3234 /* handle new association without HT and disassociation */
3235 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003236 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003237 false);
3238 if (ret < 0) {
3239 wl1271_warning("Set ht cap false failed %d",
3240 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003241 goto out;
3242 }
3243 }
3244 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003245
Arik Nemtsove78a2872010-10-16 19:07:21 +02003246 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003247 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003248 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003249 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003250 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003251 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003252
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003253 wl->ps_poll_failures = 0;
3254
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003255 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003256 * use basic rates from AP, and determine lowest rate
3257 * to use with control frames.
3258 */
3259 rates = bss_conf->basic_rates;
3260 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3261 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003262 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003263 if (sta_rate_set)
3264 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3265 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003266 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003267 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003268 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003269
3270 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003271 * with wl1271, we don't need to update the
3272 * beacon_int and dtim_period, because the firmware
3273 * updates it by itself when the first beacon is
3274 * received after a join.
3275 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003276 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3277 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003278 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003279
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003280 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003281 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003282 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003283 dev_kfree_skb(wl->probereq);
3284 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3285 ieoffset = offsetof(struct ieee80211_mgmt,
3286 u.probe_req.variable);
3287 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003288
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003289 /* enable the connection monitoring feature */
3290 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003291 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003292 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003293
3294 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003295 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3296 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003297 enum wl1271_cmd_ps_mode mode;
3298
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003299 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003300 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003301 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003302 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003303 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003304 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003305 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003306 } else {
3307 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003308 bool was_assoc =
3309 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3310 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003311 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003312 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003313
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003314 /* free probe-request template */
3315 dev_kfree_skb(wl->probereq);
3316 wl->probereq = NULL;
3317
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003318 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003319 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003320
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003321 /* revert back to minimum rates for the current band */
3322 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003323 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003324 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003325 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003326 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003327
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003328 /* disable connection monitor features */
3329 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003330
3331 /* Disable the keep-alive feature */
3332 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003333 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003334 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003335
3336 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003337 if (was_assoc) {
3338 wl1271_unjoin(wl);
3339 wl1271_dummy_join(wl);
3340 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341 }
3342 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003343
Eliad Pellerd192d262011-05-24 14:33:08 +03003344 if (changed & BSS_CHANGED_IBSS) {
3345 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3346 bss_conf->ibss_joined);
3347
3348 if (bss_conf->ibss_joined) {
3349 u32 rates = bss_conf->basic_rates;
3350 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3351 rates);
3352 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3353
3354 /* by default, use 11b rates */
3355 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3356 ret = wl1271_acx_sta_rate_policies(wl);
3357 if (ret < 0)
3358 goto out;
3359 }
3360 }
3361
Arik Nemtsove78a2872010-10-16 19:07:21 +02003362 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3363 if (ret < 0)
3364 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003365
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003366 if (changed & BSS_CHANGED_ARP_FILTER) {
3367 __be32 addr = bss_conf->arp_addr_list[0];
3368 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3369
Eliad Pellerc5312772010-12-09 11:31:27 +02003370 if (bss_conf->arp_addr_cnt == 1 &&
3371 bss_conf->arp_filter_enabled) {
3372 /*
3373 * The template should have been configured only upon
3374 * association. however, it seems that the correct ip
3375 * isn't being set (when sending), so we have to
3376 * reconfigure the template upon every ip change.
3377 */
3378 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3379 if (ret < 0) {
3380 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003382 }
3383
3384 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003385 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003386 addr);
3387 } else
3388 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003389
3390 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003392 }
3393
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003394 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003395 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003396 if (ret < 0) {
3397 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003399 }
Eliad Pelleref4b29e2011-06-06 13:03:12 +03003400 wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003401 }
3402
Arik Nemtsove78a2872010-10-16 19:07:21 +02003403out:
3404 return;
3405}
3406
3407static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3408 struct ieee80211_vif *vif,
3409 struct ieee80211_bss_conf *bss_conf,
3410 u32 changed)
3411{
3412 struct wl1271 *wl = hw->priv;
3413 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3414 int ret;
3415
3416 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3417 (int)changed);
3418
3419 mutex_lock(&wl->mutex);
3420
3421 if (unlikely(wl->state == WL1271_STATE_OFF))
3422 goto out;
3423
Ido Yariva6208652011-03-01 15:14:41 +02003424 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 if (ret < 0)
3426 goto out;
3427
3428 if (is_ap)
3429 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3430 else
3431 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3432
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003433 wl1271_ps_elp_sleep(wl);
3434
3435out:
3436 mutex_unlock(&wl->mutex);
3437}
3438
Kalle Valoc6999d82010-02-18 13:25:41 +02003439static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3440 const struct ieee80211_tx_queue_params *params)
3441{
3442 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003443 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003444 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003445
3446 mutex_lock(&wl->mutex);
3447
3448 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3449
Kalle Valo4695dc92010-03-18 12:26:38 +02003450 if (params->uapsd)
3451 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3452 else
3453 ps_scheme = CONF_PS_SCHEME_LEGACY;
3454
Arik Nemtsov488fc542010-10-16 20:33:45 +02003455 if (wl->state == WL1271_STATE_OFF) {
3456 /*
3457 * If the state is off, the parameters will be recorded and
3458 * configured on init. This happens in AP-mode.
3459 */
3460 struct conf_tx_ac_category *conf_ac =
3461 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3462 struct conf_tx_tid *conf_tid =
3463 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3464
3465 conf_ac->ac = wl1271_tx_get_queue(queue);
3466 conf_ac->cw_min = (u8)params->cw_min;
3467 conf_ac->cw_max = params->cw_max;
3468 conf_ac->aifsn = params->aifs;
3469 conf_ac->tx_op_limit = params->txop << 5;
3470
3471 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3472 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3473 conf_tid->tsid = wl1271_tx_get_queue(queue);
3474 conf_tid->ps_scheme = ps_scheme;
3475 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3476 conf_tid->apsd_conf[0] = 0;
3477 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003478 goto out;
3479 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003480
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003481 ret = wl1271_ps_elp_wakeup(wl);
3482 if (ret < 0)
3483 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003484
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003485 /*
3486 * the txop is confed in units of 32us by the mac80211,
3487 * we need us
3488 */
3489 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3490 params->cw_min, params->cw_max,
3491 params->aifs, params->txop << 5);
3492 if (ret < 0)
3493 goto out_sleep;
3494
3495 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3496 CONF_CHANNEL_TYPE_EDCF,
3497 wl1271_tx_get_queue(queue),
3498 ps_scheme, CONF_ACK_POLICY_LEGACY,
3499 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003500
3501out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003502 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003503
3504out:
3505 mutex_unlock(&wl->mutex);
3506
3507 return ret;
3508}
3509
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003510static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3511{
3512
3513 struct wl1271 *wl = hw->priv;
3514 u64 mactime = ULLONG_MAX;
3515 int ret;
3516
3517 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3518
3519 mutex_lock(&wl->mutex);
3520
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003521 if (unlikely(wl->state == WL1271_STATE_OFF))
3522 goto out;
3523
Ido Yariva6208652011-03-01 15:14:41 +02003524 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003525 if (ret < 0)
3526 goto out;
3527
3528 ret = wl1271_acx_tsf_info(wl, &mactime);
3529 if (ret < 0)
3530 goto out_sleep;
3531
3532out_sleep:
3533 wl1271_ps_elp_sleep(wl);
3534
3535out:
3536 mutex_unlock(&wl->mutex);
3537 return mactime;
3538}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003539
John W. Linvilleece550d2010-07-28 16:41:06 -04003540static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3541 struct survey_info *survey)
3542{
3543 struct wl1271 *wl = hw->priv;
3544 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003545
John W. Linvilleece550d2010-07-28 16:41:06 -04003546 if (idx != 0)
3547 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003548
John W. Linvilleece550d2010-07-28 16:41:06 -04003549 survey->channel = conf->channel;
3550 survey->filled = SURVEY_INFO_NOISE_DBM;
3551 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003552
John W. Linvilleece550d2010-07-28 16:41:06 -04003553 return 0;
3554}
3555
Arik Nemtsov409622e2011-02-23 00:22:29 +02003556static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003557 struct ieee80211_sta *sta,
3558 u8 *hlid)
3559{
3560 struct wl1271_station *wl_sta;
3561 int id;
3562
3563 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3564 if (id >= AP_MAX_STATIONS) {
3565 wl1271_warning("could not allocate HLID - too much stations");
3566 return -EBUSY;
3567 }
3568
3569 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003570 __set_bit(id, wl->ap_hlid_map);
3571 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3572 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003573 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003574 return 0;
3575}
3576
Arik Nemtsov409622e2011-02-23 00:22:29 +02003577static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003578{
3579 int id = hlid - WL1271_AP_STA_HLID_START;
3580
Arik Nemtsov409622e2011-02-23 00:22:29 +02003581 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3582 return;
3583
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003584 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003585 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003586 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003587 __clear_bit(hlid, &wl->ap_ps_map);
3588 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003589}
3590
Arik Nemtsov3618f302011-06-26 10:36:03 +03003591bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3592{
3593 int id = hlid - WL1271_AP_STA_HLID_START;
3594 return test_bit(id, wl->ap_hlid_map);
3595}
3596
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003597static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3598 struct ieee80211_vif *vif,
3599 struct ieee80211_sta *sta)
3600{
3601 struct wl1271 *wl = hw->priv;
3602 int ret = 0;
3603 u8 hlid;
3604
3605 mutex_lock(&wl->mutex);
3606
3607 if (unlikely(wl->state == WL1271_STATE_OFF))
3608 goto out;
3609
3610 if (wl->bss_type != BSS_TYPE_AP_BSS)
3611 goto out;
3612
3613 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3614
Arik Nemtsov409622e2011-02-23 00:22:29 +02003615 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003616 if (ret < 0)
3617 goto out;
3618
Ido Yariva6208652011-03-01 15:14:41 +02003619 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003620 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003621 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003622
Eliad Pellerc690ec82011-08-14 13:17:07 +03003623 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003624 if (ret < 0)
3625 goto out_sleep;
3626
3627out_sleep:
3628 wl1271_ps_elp_sleep(wl);
3629
Arik Nemtsov409622e2011-02-23 00:22:29 +02003630out_free_sta:
3631 if (ret < 0)
3632 wl1271_free_sta(wl, hlid);
3633
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003634out:
3635 mutex_unlock(&wl->mutex);
3636 return ret;
3637}
3638
3639static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3640 struct ieee80211_vif *vif,
3641 struct ieee80211_sta *sta)
3642{
3643 struct wl1271 *wl = hw->priv;
3644 struct wl1271_station *wl_sta;
3645 int ret = 0, id;
3646
3647 mutex_lock(&wl->mutex);
3648
3649 if (unlikely(wl->state == WL1271_STATE_OFF))
3650 goto out;
3651
3652 if (wl->bss_type != BSS_TYPE_AP_BSS)
3653 goto out;
3654
3655 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3656
3657 wl_sta = (struct wl1271_station *)sta->drv_priv;
3658 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3659 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3660 goto out;
3661
Ido Yariva6208652011-03-01 15:14:41 +02003662 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003663 if (ret < 0)
3664 goto out;
3665
Eliad Pellerc690ec82011-08-14 13:17:07 +03003666 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003667 if (ret < 0)
3668 goto out_sleep;
3669
Arik Nemtsov409622e2011-02-23 00:22:29 +02003670 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003671
3672out_sleep:
3673 wl1271_ps_elp_sleep(wl);
3674
3675out:
3676 mutex_unlock(&wl->mutex);
3677 return ret;
3678}
3679
Luciano Coelho4623ec72011-03-21 19:26:41 +02003680static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3681 struct ieee80211_vif *vif,
3682 enum ieee80211_ampdu_mlme_action action,
3683 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3684 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003685{
3686 struct wl1271 *wl = hw->priv;
3687 int ret;
3688
3689 mutex_lock(&wl->mutex);
3690
3691 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3692 ret = -EAGAIN;
3693 goto out;
3694 }
3695
Ido Yariva6208652011-03-01 15:14:41 +02003696 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003697 if (ret < 0)
3698 goto out;
3699
Shahar Levi70559a02011-05-22 16:10:22 +03003700 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3701 tid, action);
3702
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003703 switch (action) {
3704 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003705 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003706 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3707 true);
3708 if (!ret)
3709 wl->ba_rx_bitmap |= BIT(tid);
3710 } else {
3711 ret = -ENOTSUPP;
3712 }
3713 break;
3714
3715 case IEEE80211_AMPDU_RX_STOP:
3716 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3717 if (!ret)
3718 wl->ba_rx_bitmap &= ~BIT(tid);
3719 break;
3720
3721 /*
3722 * The BA initiator session management in FW independently.
3723 * Falling break here on purpose for all TX APDU commands.
3724 */
3725 case IEEE80211_AMPDU_TX_START:
3726 case IEEE80211_AMPDU_TX_STOP:
3727 case IEEE80211_AMPDU_TX_OPERATIONAL:
3728 ret = -EINVAL;
3729 break;
3730
3731 default:
3732 wl1271_error("Incorrect ampdu action id=%x\n", action);
3733 ret = -EINVAL;
3734 }
3735
3736 wl1271_ps_elp_sleep(wl);
3737
3738out:
3739 mutex_unlock(&wl->mutex);
3740
3741 return ret;
3742}
3743
Arik Nemtsov33437892011-04-26 23:35:39 +03003744static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3745{
3746 struct wl1271 *wl = hw->priv;
3747 bool ret = false;
3748
3749 mutex_lock(&wl->mutex);
3750
3751 if (unlikely(wl->state == WL1271_STATE_OFF))
3752 goto out;
3753
3754 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003755 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003756
3757 /* the above is appropriate for STA mode for PS purposes */
3758 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3759
3760out:
3761 mutex_unlock(&wl->mutex);
3762
3763 return ret;
3764}
3765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003766/* can't be const, mac80211 writes to this */
3767static struct ieee80211_rate wl1271_rates[] = {
3768 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003769 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3770 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003771 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003772 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3773 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003774 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3775 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003776 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3777 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003778 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3779 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003780 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3781 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003782 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3783 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003784 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3785 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003786 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003787 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3788 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003789 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003790 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3791 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003792 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003793 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3794 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003795 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003796 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3797 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003798 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003799 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3800 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003801 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003802 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3803 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003804 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003805 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3806 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003807};
3808
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003809/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003810static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003811 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003812 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003813 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3814 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3815 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003816 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003817 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3818 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3819 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003820 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003821 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3822 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3823 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003824 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003825};
3826
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003827/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003828static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003829 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003830 7, /* CONF_HW_RXTX_RATE_MCS7 */
3831 6, /* CONF_HW_RXTX_RATE_MCS6 */
3832 5, /* CONF_HW_RXTX_RATE_MCS5 */
3833 4, /* CONF_HW_RXTX_RATE_MCS4 */
3834 3, /* CONF_HW_RXTX_RATE_MCS3 */
3835 2, /* CONF_HW_RXTX_RATE_MCS2 */
3836 1, /* CONF_HW_RXTX_RATE_MCS1 */
3837 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003838
3839 11, /* CONF_HW_RXTX_RATE_54 */
3840 10, /* CONF_HW_RXTX_RATE_48 */
3841 9, /* CONF_HW_RXTX_RATE_36 */
3842 8, /* CONF_HW_RXTX_RATE_24 */
3843
3844 /* TI-specific rate */
3845 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3846
3847 7, /* CONF_HW_RXTX_RATE_18 */
3848 6, /* CONF_HW_RXTX_RATE_12 */
3849 3, /* CONF_HW_RXTX_RATE_11 */
3850 5, /* CONF_HW_RXTX_RATE_9 */
3851 4, /* CONF_HW_RXTX_RATE_6 */
3852 2, /* CONF_HW_RXTX_RATE_5_5 */
3853 1, /* CONF_HW_RXTX_RATE_2 */
3854 0 /* CONF_HW_RXTX_RATE_1 */
3855};
3856
Shahar Levie8b03a22010-10-13 16:09:39 +02003857/* 11n STA capabilities */
3858#define HW_RX_HIGHEST_RATE 72
3859
Shahar Levi00d20102010-11-08 11:20:10 +00003860#ifdef CONFIG_WL12XX_HT
3861#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003862 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3863 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003864 .ht_supported = true, \
3865 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3866 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3867 .mcs = { \
3868 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3869 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3870 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3871 }, \
3872}
Shahar Levi18357852010-10-13 16:09:41 +02003873#else
Shahar Levi00d20102010-11-08 11:20:10 +00003874#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003875 .ht_supported = false, \
3876}
3877#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003878
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003879/* can't be const, mac80211 writes to this */
3880static struct ieee80211_supported_band wl1271_band_2ghz = {
3881 .channels = wl1271_channels,
3882 .n_channels = ARRAY_SIZE(wl1271_channels),
3883 .bitrates = wl1271_rates,
3884 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003885 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003886};
3887
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003888/* 5 GHz data rates for WL1273 */
3889static struct ieee80211_rate wl1271_rates_5ghz[] = {
3890 { .bitrate = 60,
3891 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3892 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3893 { .bitrate = 90,
3894 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3895 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3896 { .bitrate = 120,
3897 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3898 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3899 { .bitrate = 180,
3900 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3901 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3902 { .bitrate = 240,
3903 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3904 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3905 { .bitrate = 360,
3906 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3907 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3908 { .bitrate = 480,
3909 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3910 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3911 { .bitrate = 540,
3912 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3913 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3914};
3915
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003916/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003917static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03003918 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
3919 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
3920 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
3921 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
3922 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
3923 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
3924 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
3925 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
3926 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
3927 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
3928 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
3929 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
3930 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
3931 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
3932 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
3933 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
3934 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
3935 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
3936 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
3937 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
3938 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
3939 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
3940 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
3941 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
3942 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
3943 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
3944 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
3945 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
3946 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
3947 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
3948 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
3949 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
3950 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
3951 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003952};
3953
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003954/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003955static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003956 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003957 7, /* CONF_HW_RXTX_RATE_MCS7 */
3958 6, /* CONF_HW_RXTX_RATE_MCS6 */
3959 5, /* CONF_HW_RXTX_RATE_MCS5 */
3960 4, /* CONF_HW_RXTX_RATE_MCS4 */
3961 3, /* CONF_HW_RXTX_RATE_MCS3 */
3962 2, /* CONF_HW_RXTX_RATE_MCS2 */
3963 1, /* CONF_HW_RXTX_RATE_MCS1 */
3964 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003965
3966 7, /* CONF_HW_RXTX_RATE_54 */
3967 6, /* CONF_HW_RXTX_RATE_48 */
3968 5, /* CONF_HW_RXTX_RATE_36 */
3969 4, /* CONF_HW_RXTX_RATE_24 */
3970
3971 /* TI-specific rate */
3972 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3973
3974 3, /* CONF_HW_RXTX_RATE_18 */
3975 2, /* CONF_HW_RXTX_RATE_12 */
3976 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3977 1, /* CONF_HW_RXTX_RATE_9 */
3978 0, /* CONF_HW_RXTX_RATE_6 */
3979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3980 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3981 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3982};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003983
3984static struct ieee80211_supported_band wl1271_band_5ghz = {
3985 .channels = wl1271_channels_5ghz,
3986 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3987 .bitrates = wl1271_rates_5ghz,
3988 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003989 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003990};
3991
Tobias Klausera0ea9492010-05-20 10:38:11 +02003992static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003993 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3994 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3995};
3996
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003997static const struct ieee80211_ops wl1271_ops = {
3998 .start = wl1271_op_start,
3999 .stop = wl1271_op_stop,
4000 .add_interface = wl1271_op_add_interface,
4001 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004002#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004003 .suspend = wl1271_op_suspend,
4004 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004005#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004006 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004007 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004008 .configure_filter = wl1271_op_configure_filter,
4009 .tx = wl1271_op_tx,
4010 .set_key = wl1271_op_set_key,
4011 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004012 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004013 .sched_scan_start = wl1271_op_sched_scan_start,
4014 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004015 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004016 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004017 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004018 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004019 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004020 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004021 .sta_add = wl1271_op_sta_add,
4022 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004023 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004024 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004025 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004026};
4027
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004028
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004029u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004030{
4031 u8 idx;
4032
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004033 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004034
4035 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4036 wl1271_error("Illegal RX rate from HW: %d", rate);
4037 return 0;
4038 }
4039
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004040 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004041 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4042 wl1271_error("Unsupported RX rate from HW: %d", rate);
4043 return 0;
4044 }
4045
4046 return idx;
4047}
4048
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004049static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4050 struct device_attribute *attr,
4051 char *buf)
4052{
4053 struct wl1271 *wl = dev_get_drvdata(dev);
4054 ssize_t len;
4055
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004056 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004057
4058 mutex_lock(&wl->mutex);
4059 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4060 wl->sg_enabled);
4061 mutex_unlock(&wl->mutex);
4062
4063 return len;
4064
4065}
4066
4067static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4068 struct device_attribute *attr,
4069 const char *buf, size_t count)
4070{
4071 struct wl1271 *wl = dev_get_drvdata(dev);
4072 unsigned long res;
4073 int ret;
4074
Luciano Coelho6277ed62011-04-01 17:49:54 +03004075 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004076 if (ret < 0) {
4077 wl1271_warning("incorrect value written to bt_coex_mode");
4078 return count;
4079 }
4080
4081 mutex_lock(&wl->mutex);
4082
4083 res = !!res;
4084
4085 if (res == wl->sg_enabled)
4086 goto out;
4087
4088 wl->sg_enabled = res;
4089
4090 if (wl->state == WL1271_STATE_OFF)
4091 goto out;
4092
Ido Yariva6208652011-03-01 15:14:41 +02004093 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004094 if (ret < 0)
4095 goto out;
4096
4097 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4098 wl1271_ps_elp_sleep(wl);
4099
4100 out:
4101 mutex_unlock(&wl->mutex);
4102 return count;
4103}
4104
4105static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4106 wl1271_sysfs_show_bt_coex_state,
4107 wl1271_sysfs_store_bt_coex_state);
4108
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004109static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4110 struct device_attribute *attr,
4111 char *buf)
4112{
4113 struct wl1271 *wl = dev_get_drvdata(dev);
4114 ssize_t len;
4115
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004116 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004117
4118 mutex_lock(&wl->mutex);
4119 if (wl->hw_pg_ver >= 0)
4120 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4121 else
4122 len = snprintf(buf, len, "n/a\n");
4123 mutex_unlock(&wl->mutex);
4124
4125 return len;
4126}
4127
Gery Kahn6f07b722011-07-18 14:21:49 +03004128static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004129 wl1271_sysfs_show_hw_pg_ver, NULL);
4130
Ido Yariv95dac04f2011-06-06 14:57:06 +03004131static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4132 struct bin_attribute *bin_attr,
4133 char *buffer, loff_t pos, size_t count)
4134{
4135 struct device *dev = container_of(kobj, struct device, kobj);
4136 struct wl1271 *wl = dev_get_drvdata(dev);
4137 ssize_t len;
4138 int ret;
4139
4140 ret = mutex_lock_interruptible(&wl->mutex);
4141 if (ret < 0)
4142 return -ERESTARTSYS;
4143
4144 /* Let only one thread read the log at a time, blocking others */
4145 while (wl->fwlog_size == 0) {
4146 DEFINE_WAIT(wait);
4147
4148 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4149 &wait,
4150 TASK_INTERRUPTIBLE);
4151
4152 if (wl->fwlog_size != 0) {
4153 finish_wait(&wl->fwlog_waitq, &wait);
4154 break;
4155 }
4156
4157 mutex_unlock(&wl->mutex);
4158
4159 schedule();
4160 finish_wait(&wl->fwlog_waitq, &wait);
4161
4162 if (signal_pending(current))
4163 return -ERESTARTSYS;
4164
4165 ret = mutex_lock_interruptible(&wl->mutex);
4166 if (ret < 0)
4167 return -ERESTARTSYS;
4168 }
4169
4170 /* Check if the fwlog is still valid */
4171 if (wl->fwlog_size < 0) {
4172 mutex_unlock(&wl->mutex);
4173 return 0;
4174 }
4175
4176 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4177 len = min(count, (size_t)wl->fwlog_size);
4178 wl->fwlog_size -= len;
4179 memcpy(buffer, wl->fwlog, len);
4180
4181 /* Make room for new messages */
4182 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4183
4184 mutex_unlock(&wl->mutex);
4185
4186 return len;
4187}
4188
4189static struct bin_attribute fwlog_attr = {
4190 .attr = {.name = "fwlog", .mode = S_IRUSR},
4191 .read = wl1271_sysfs_read_fwlog,
4192};
4193
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004194int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004195{
4196 int ret;
4197
4198 if (wl->mac80211_registered)
4199 return 0;
4200
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004201 ret = wl1271_fetch_nvs(wl);
4202 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004203 /* NOTE: The wl->nvs->nvs element must be first, in
4204 * order to simplify the casting, we assume it is at
4205 * the beginning of the wl->nvs structure.
4206 */
4207 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004208
4209 wl->mac_addr[0] = nvs_ptr[11];
4210 wl->mac_addr[1] = nvs_ptr[10];
4211 wl->mac_addr[2] = nvs_ptr[6];
4212 wl->mac_addr[3] = nvs_ptr[5];
4213 wl->mac_addr[4] = nvs_ptr[4];
4214 wl->mac_addr[5] = nvs_ptr[3];
4215 }
4216
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004217 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4218
4219 ret = ieee80211_register_hw(wl->hw);
4220 if (ret < 0) {
4221 wl1271_error("unable to register mac80211 hw: %d", ret);
4222 return ret;
4223 }
4224
4225 wl->mac80211_registered = true;
4226
Eliad Pellerd60080a2010-11-24 12:53:16 +02004227 wl1271_debugfs_init(wl);
4228
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004229 register_netdevice_notifier(&wl1271_dev_notifier);
4230
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004231 wl1271_notice("loaded");
4232
4233 return 0;
4234}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004235EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004236
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004237void wl1271_unregister_hw(struct wl1271 *wl)
4238{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004239 if (wl->state == WL1271_STATE_PLT)
4240 __wl1271_plt_stop(wl);
4241
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004242 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004243 ieee80211_unregister_hw(wl->hw);
4244 wl->mac80211_registered = false;
4245
4246}
4247EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4248
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004249int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004250{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004251 static const u32 cipher_suites[] = {
4252 WLAN_CIPHER_SUITE_WEP40,
4253 WLAN_CIPHER_SUITE_WEP104,
4254 WLAN_CIPHER_SUITE_TKIP,
4255 WLAN_CIPHER_SUITE_CCMP,
4256 WL1271_CIPHER_SUITE_GEM,
4257 };
4258
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004259 /* The tx descriptor buffer and the TKIP space. */
4260 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4261 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004262
4263 /* unit us */
4264 /* FIXME: find a proper value */
4265 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004266 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004267
4268 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004269 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004270 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004271 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004272 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004273 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004274 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004275 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004276 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004277 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004278
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004279 wl->hw->wiphy->cipher_suites = cipher_suites;
4280 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4281
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004282 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004283 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004284 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004285 /*
4286 * Maximum length of elements in scanning probe request templates
4287 * should be the maximum length possible for a template, without
4288 * the IEEE80211 header of the template
4289 */
Eliad Peller154037d2011-08-14 13:17:12 +03004290 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004291 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004292
Luciano Coelho4a31c112011-03-21 23:16:14 +02004293 /* make sure all our channels fit in the scanned_ch bitmask */
4294 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4295 ARRAY_SIZE(wl1271_channels_5ghz) >
4296 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004297 /*
4298 * We keep local copies of the band structs because we need to
4299 * modify them on a per-device basis.
4300 */
4301 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4302 sizeof(wl1271_band_2ghz));
4303 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4304 sizeof(wl1271_band_5ghz));
4305
4306 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4307 &wl->bands[IEEE80211_BAND_2GHZ];
4308 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4309 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004310
Kalle Valo12bd8942010-03-18 12:26:33 +02004311 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004312 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004313
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004314 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4315
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004316 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004317
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004318 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4319
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004320 wl->hw->max_rx_aggregation_subframes = 8;
4321
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004322 return 0;
4323}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004324EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004325
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004326#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004327
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004328struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004329{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004330 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004331 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004332 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004333 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004334 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004335
4336 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4337 if (!hw) {
4338 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004339 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004340 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004341 }
4342
Julia Lawall929ebd32010-05-15 23:16:39 +02004343 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004344 if (!plat_dev) {
4345 wl1271_error("could not allocate platform_device");
4346 ret = -ENOMEM;
4347 goto err_plat_alloc;
4348 }
4349
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004350 wl = hw->priv;
4351 memset(wl, 0, sizeof(*wl));
4352
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004353 INIT_LIST_HEAD(&wl->list);
4354
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004355 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004356 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004357
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004358 for (i = 0; i < NUM_TX_QUEUES; i++)
4359 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004360
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004361 for (i = 0; i < NUM_TX_QUEUES; i++)
4362 for (j = 0; j < AP_MAX_LINKS; j++)
4363 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4364
Ido Yariva6208652011-03-01 15:14:41 +02004365 skb_queue_head_init(&wl->deferred_rx_queue);
4366 skb_queue_head_init(&wl->deferred_tx_queue);
4367
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004368 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004369 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004370 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004371 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4372 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4373 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004374 INIT_WORK(&wl->rx_streaming_enable_work,
4375 wl1271_rx_streaming_enable_work);
4376 INIT_WORK(&wl->rx_streaming_disable_work,
4377 wl1271_rx_streaming_disable_work);
4378
Eliad Peller92ef8962011-06-07 12:50:46 +03004379 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4380 if (!wl->freezable_wq) {
4381 ret = -ENOMEM;
4382 goto err_hw;
4383 }
4384
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004385 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004386 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004387 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004388 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004389 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004390 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004391 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004392 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004393 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004394 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004395 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004396 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004397 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004398 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004399 wl->bss_type = MAX_BSS_TYPE;
4400 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004401 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004402 wl->ap_ps_map = 0;
4403 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004404 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004405 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004406 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004407 wl->tx_security_seq = 0;
4408 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004409 wl->role_id = WL12XX_INVALID_ROLE_ID;
4410 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004411 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4412 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004413 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4414 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004415 wl->fwlog_size = 0;
4416 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004417
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004418 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004419 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004420 wl->tx_frames[i] = NULL;
4421
4422 spin_lock_init(&wl->wl_lock);
4423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004424 wl->state = WL1271_STATE_OFF;
4425 mutex_init(&wl->mutex);
4426
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004427 /* Apply default driver configuration. */
4428 wl1271_conf_init(wl);
4429
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004430 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4431 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4432 if (!wl->aggr_buf) {
4433 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004434 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004435 }
4436
Ido Yariv990f5de2011-03-31 10:06:59 +02004437 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4438 if (!wl->dummy_packet) {
4439 ret = -ENOMEM;
4440 goto err_aggr;
4441 }
4442
Ido Yariv95dac04f2011-06-06 14:57:06 +03004443 /* Allocate one page for the FW log */
4444 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4445 if (!wl->fwlog) {
4446 ret = -ENOMEM;
4447 goto err_dummy_packet;
4448 }
4449
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004450 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004451 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004452 if (ret) {
4453 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004454 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004455 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004456 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004457
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004458 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004459 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004460 if (ret < 0) {
4461 wl1271_error("failed to create sysfs file bt_coex_state");
4462 goto err_platform;
4463 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004464
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004465 /* Create sysfs file to get HW PG version */
4466 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4467 if (ret < 0) {
4468 wl1271_error("failed to create sysfs file hw_pg_ver");
4469 goto err_bt_coex_state;
4470 }
4471
Ido Yariv95dac04f2011-06-06 14:57:06 +03004472 /* Create sysfs file for the FW log */
4473 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4474 if (ret < 0) {
4475 wl1271_error("failed to create sysfs file fwlog");
4476 goto err_hw_pg_ver;
4477 }
4478
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004479 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004480
Ido Yariv95dac04f2011-06-06 14:57:06 +03004481err_hw_pg_ver:
4482 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4483
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004484err_bt_coex_state:
4485 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4486
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004487err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004488 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004489
Ido Yariv95dac04f2011-06-06 14:57:06 +03004490err_fwlog:
4491 free_page((unsigned long)wl->fwlog);
4492
Ido Yariv990f5de2011-03-31 10:06:59 +02004493err_dummy_packet:
4494 dev_kfree_skb(wl->dummy_packet);
4495
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004496err_aggr:
4497 free_pages((unsigned long)wl->aggr_buf, order);
4498
Eliad Peller92ef8962011-06-07 12:50:46 +03004499err_wq:
4500 destroy_workqueue(wl->freezable_wq);
4501
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004502err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004503 wl1271_debugfs_exit(wl);
4504 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004505
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004506err_plat_alloc:
4507 ieee80211_free_hw(hw);
4508
4509err_hw_alloc:
4510
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004511 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004512}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004513EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004514
4515int wl1271_free_hw(struct wl1271 *wl)
4516{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004517 /* Unblock any fwlog readers */
4518 mutex_lock(&wl->mutex);
4519 wl->fwlog_size = -1;
4520 wake_up_interruptible_all(&wl->fwlog_waitq);
4521 mutex_unlock(&wl->mutex);
4522
4523 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004524
4525 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4526
4527 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004528 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004529 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004530 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004531 free_pages((unsigned long)wl->aggr_buf,
4532 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004533 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004534
4535 wl1271_debugfs_exit(wl);
4536
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004537 vfree(wl->fw);
4538 wl->fw = NULL;
4539 kfree(wl->nvs);
4540 wl->nvs = NULL;
4541
4542 kfree(wl->fw_status);
4543 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004544 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004545
4546 ieee80211_free_hw(wl->hw);
4547
4548 return 0;
4549}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004550EXPORT_SYMBOL_GPL(wl1271_free_hw);
4551
Guy Eilam491bbd62011-01-12 10:33:29 +01004552u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004553EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004554module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004555MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4556
Ido Yariv95dac04f2011-06-06 14:57:06 +03004557module_param_named(fwlog, fwlog_param, charp, 0);
4558MODULE_PARM_DESC(keymap,
4559 "FW logger options: continuous, ondemand, dbgpins or disable");
4560
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004561MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004562MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004563MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");