blob: e4081e2221842d3d5fc98778790405a5cc2e22b9 [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-Cohen958b20e2011-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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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 Yarivbaacb9a2011-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)
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03001494 hlid = wl12xx_tx_get_hlid_ap(wl, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001495
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 Coelhod6e19d12009-10-12 15:08:43 +03002071
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002072 /* The system link is always allocated */
2073 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
2074
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002075 /*
2076 * this is performed after the cancel_work calls and the associated
2077 * mutex_lock, so that wl1271_op_add_interface does not accidentally
2078 * get executed before all these vars have been reset.
2079 */
2080 wl->flags = 0;
2081
Eliad Peller4d56ad92011-08-14 13:17:05 +03002082 wl->tx_blocks_freed = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002083
2084 wl1271_debugfs_reset(wl);
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002085
2086 kfree(wl->fw_status);
2087 wl->fw_status = NULL;
2088 kfree(wl->tx_res_if);
2089 wl->tx_res_if = NULL;
2090 kfree(wl->target_mem_map);
2091 wl->target_mem_map = NULL;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002092}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002093
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002094static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2095 struct ieee80211_vif *vif)
2096{
2097 struct wl1271 *wl = hw->priv;
2098
2099 mutex_lock(&wl->mutex);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002100 /*
2101 * wl->vif can be null here if someone shuts down the interface
2102 * just when hardware recovery has been started.
2103 */
2104 if (wl->vif) {
2105 WARN_ON(wl->vif != vif);
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002106 __wl1271_op_remove_interface(wl, true);
Juuso Oikarinen67353292010-11-18 15:19:02 +02002107 }
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002108
Juuso Oikarinen67353292010-11-18 15:19:02 +02002109 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002110 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002111}
2112
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002113static int wl1271_dummy_join(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002114{
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02002115 int ret = 0;
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002116 /* we need to use a dummy BSSID for now */
2117 static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde,
2118 0xad, 0xbe, 0xef };
2119
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002120 memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
2121
Eliad Pellerc690ec82011-08-14 13:17:07 +03002122 ret = wl12xx_cmd_role_start_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002123 if (ret < 0)
2124 goto out;
2125
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002126 set_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002127
2128out:
2129 return ret;
2130}
2131
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002132static int wl1271_join(struct wl1271 *wl, bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002133{
2134 int ret;
2135
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002136 /*
2137 * One of the side effects of the JOIN command is that is clears
2138 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2139 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002140 * Currently the only valid scenario for JOIN during association
2141 * is on roaming, in which case we will also be given new keys.
2142 * Keep the below message for now, unless it starts bothering
2143 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002144 */
2145 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2146 wl1271_info("JOIN while associated.");
2147
2148 if (set_assoc)
2149 set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
2150
Eliad Pellerc690ec82011-08-14 13:17:07 +03002151 ret = wl12xx_cmd_role_start_sta(wl);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002152 if (ret < 0)
2153 goto out;
2154
2155 set_bit(WL1271_FLAG_JOINED, &wl->flags);
2156
2157 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2158 goto out;
2159
2160 /*
2161 * The join command disable the keep-alive mode, shut down its process,
2162 * and also clear the template config, so we need to reset it all after
2163 * the join. The acx_aid starts the keep-alive process, and the order
2164 * of the commands below is relevant.
2165 */
2166 ret = wl1271_acx_keep_alive_mode(wl, true);
2167 if (ret < 0)
2168 goto out;
2169
2170 ret = wl1271_acx_aid(wl, wl->aid);
2171 if (ret < 0)
2172 goto out;
2173
2174 ret = wl1271_cmd_build_klv_null_data(wl);
2175 if (ret < 0)
2176 goto out;
2177
2178 ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2179 ACX_KEEP_ALIVE_TPL_VALID);
2180 if (ret < 0)
2181 goto out;
2182
2183out:
2184 return ret;
2185}
2186
2187static int wl1271_unjoin(struct wl1271 *wl)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002188{
2189 int ret;
2190
2191 /* to stop listening to a channel, we disconnect */
Eliad Pellerc690ec82011-08-14 13:17:07 +03002192 ret = wl12xx_cmd_role_stop_sta(wl);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002193 if (ret < 0)
2194 goto out;
2195
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002196 clear_bit(WL1271_FLAG_JOINED, &wl->flags);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002197 memset(wl->bssid, 0, ETH_ALEN);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002198
Oz Krakowskib992c682011-06-26 10:36:02 +03002199 /* reset TX security counters on a clean disconnect */
2200 wl->tx_security_last_seq_lsb = 0;
2201 wl->tx_security_seq = 0;
2202
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002203out:
2204 return ret;
2205}
2206
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002207static void wl1271_set_band_rate(struct wl1271 *wl)
2208{
2209 if (wl->band == IEEE80211_BAND_2GHZ)
2210 wl->basic_rate_set = wl->conf.tx.basic_rate;
2211 else
2212 wl->basic_rate_set = wl->conf.tx.basic_rate_5;
2213}
2214
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002215static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002216{
2217 int ret;
2218
2219 if (idle) {
2220 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2221 ret = wl1271_unjoin(wl);
2222 if (ret < 0)
2223 goto out;
2224 }
Arik Nemtsove0fe3712010-10-16 18:19:53 +02002225 wl->rate_set = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02002226 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002227 if (ret < 0)
2228 goto out;
2229 ret = wl1271_acx_keep_alive_config(
2230 wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
2231 ACX_KEEP_ALIVE_TPL_INVALID);
2232 if (ret < 0)
2233 goto out;
2234 set_bit(WL1271_FLAG_IDLE, &wl->flags);
2235 } else {
2236 /* increment the session counter */
2237 wl->session_counter++;
2238 if (wl->session_counter >= SESSION_COUNTER_MAX)
2239 wl->session_counter = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03002240
2241 /* The current firmware only supports sched_scan in idle */
2242 if (wl->sched_scanning) {
2243 wl1271_scan_sched_scan_stop(wl);
2244 ieee80211_sched_scan_stopped(wl->hw);
2245 }
2246
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002247 ret = wl1271_dummy_join(wl);
2248 if (ret < 0)
2249 goto out;
2250 clear_bit(WL1271_FLAG_IDLE, &wl->flags);
2251 }
2252
2253out:
2254 return ret;
2255}
2256
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002257static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2258{
2259 struct wl1271 *wl = hw->priv;
2260 struct ieee80211_conf *conf = &hw->conf;
2261 int channel, ret = 0;
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002262 bool is_ap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002263
2264 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2265
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002266 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2267 " changed 0x%x",
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002268 channel,
2269 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002270 conf->power_level,
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002271 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2272 changed);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002273
Juuso Oikarinen781608c2010-05-24 11:18:17 +03002274 /*
2275 * mac80211 will go to idle nearly immediately after transmitting some
2276 * frames, such as the deauth. To make sure those frames reach the air,
2277 * wait here until the TX queue is fully flushed.
2278 */
2279 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2280 (conf->flags & IEEE80211_CONF_IDLE))
2281 wl1271_tx_flush(wl);
2282
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002283 mutex_lock(&wl->mutex);
2284
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002285 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Arik Nemtsov17e672d2011-03-22 10:07:47 +02002286 /* we support configuring the channel and band while off */
2287 if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
2288 wl->band = conf->channel->band;
2289 wl->channel = channel;
2290 }
2291
Arik Nemtsov097f8822011-06-27 22:06:34 +03002292 if ((changed & IEEE80211_CONF_CHANGE_POWER))
2293 wl->power_level = conf->power_level;
2294
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002295 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002296 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03002297
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002298 is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2299
Ido Yariva6208652011-03-01 15:14:41 +02002300 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002301 if (ret < 0)
2302 goto out;
2303
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002304 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002305 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
2306 ((wl->band != conf->channel->band) ||
2307 (wl->channel != channel))) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002308 wl->band = conf->channel->band;
2309 wl->channel = channel;
2310
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002311 if (!is_ap) {
2312 /*
2313 * FIXME: the mac80211 should really provide a fixed
2314 * rate to use here. for now, just use the smallest
2315 * possible rate for the band as a fixed rate for
2316 * association frames and other control messages.
2317 */
2318 if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
2319 wl1271_set_band_rate(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002320
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002321 wl->basic_rate = wl1271_tx_min_rate_get(wl);
2322 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002323 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002324 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002325 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002326
2327 if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
2328 ret = wl1271_join(wl, false);
2329 if (ret < 0)
2330 wl1271_warning("cmd join on channel "
2331 "failed %d", ret);
2332 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002333 }
2334 }
2335
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002336 if (changed & IEEE80211_CONF_CHANGE_IDLE && !is_ap) {
2337 ret = wl1271_sta_handle_idle(wl,
2338 conf->flags & IEEE80211_CONF_IDLE);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002339 if (ret < 0)
2340 wl1271_warning("idle mode change failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002341 }
2342
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002343 /*
2344 * if mac80211 changes the PSM mode, make sure the mode is not
2345 * incorrectly changed after the pspoll failure active window.
2346 */
2347 if (changed & IEEE80211_CONF_CHANGE_PS)
2348 clear_bit(WL1271_FLAG_PSPOLL_FAILURE, &wl->flags);
2349
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002350 if (conf->flags & IEEE80211_CONF_PS &&
2351 !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
2352 set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002353
2354 /*
2355 * We enter PSM only if we're already associated.
2356 * If we're not, we'll enter it when joining an SSID,
2357 * through the bss_info_changed() hook.
2358 */
Juuso Oikarinen830fb672009-12-11 15:41:06 +02002359 if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002360 wl1271_debug(DEBUG_PSM, "psm enabled");
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002361 ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002362 wl->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002363 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002364 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002365 test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002366 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002367
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002368 clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002369
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002370 if (test_bit(WL1271_FLAG_PSM, &wl->flags))
Juuso Oikarinend8c42c02010-02-18 13:25:36 +02002371 ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02002372 wl->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002373 }
2374
2375 if (conf->power_level != wl->power_level) {
2376 ret = wl1271_acx_tx_power(wl, conf->power_level);
2377 if (ret < 0)
Juuso Oikarinenc6317a52009-11-02 20:22:08 +02002378 goto out_sleep;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002379
2380 wl->power_level = conf->power_level;
2381 }
2382
2383out_sleep:
2384 wl1271_ps_elp_sleep(wl);
2385
2386out:
2387 mutex_unlock(&wl->mutex);
2388
2389 return ret;
2390}
2391
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002392struct wl1271_filter_params {
2393 bool enabled;
2394 int mc_list_length;
2395 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2396};
2397
Jiri Pirko22bedad2010-04-01 21:22:57 +00002398static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2399 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002400{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002401 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002402 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002403 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002404
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002405 if (unlikely(wl->state == WL1271_STATE_OFF))
2406 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002407
Juuso Oikarinen74441132009-10-13 12:47:53 +03002408 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002409 if (!fp) {
2410 wl1271_error("Out of memory setting filters.");
2411 return 0;
2412 }
2413
2414 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002415 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002416 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2417 fp->enabled = false;
2418 } else {
2419 fp->enabled = true;
2420 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002421 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002422 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002423 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002424 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002425 }
2426
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002427 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002428}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002429
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002430#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2431 FIF_ALLMULTI | \
2432 FIF_FCSFAIL | \
2433 FIF_BCN_PRBRESP_PROMISC | \
2434 FIF_CONTROL | \
2435 FIF_OTHER_BSS)
2436
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002437static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2438 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002439 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002440{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002441 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002442 struct wl1271 *wl = hw->priv;
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002443 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444
Arik Nemtsov7d057862010-10-16 19:25:35 +02002445 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2446 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002448 mutex_lock(&wl->mutex);
2449
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002450 *total &= WL1271_SUPPORTED_FILTERS;
2451 changed &= WL1271_SUPPORTED_FILTERS;
2452
2453 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002454 goto out;
2455
Ido Yariva6208652011-03-01 15:14:41 +02002456 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002457 if (ret < 0)
2458 goto out;
2459
Arik Nemtsov7d057862010-10-16 19:25:35 +02002460 if (wl->bss_type != BSS_TYPE_AP_BSS) {
2461 if (*total & FIF_ALLMULTI)
2462 ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
2463 else if (fp)
2464 ret = wl1271_acx_group_address_tbl(wl, fp->enabled,
2465 fp->mc_list,
2466 fp->mc_list_length);
2467 if (ret < 0)
2468 goto out_sleep;
2469 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002470
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002471 /*
2472 * the fw doesn't provide an api to configure the filters. instead,
2473 * the filters configuration is based on the active roles / ROC
2474 * state.
2475 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002476
2477out_sleep:
2478 wl1271_ps_elp_sleep(wl);
2479
2480out:
2481 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002482 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002483}
2484
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002485static int wl1271_record_ap_key(struct wl1271 *wl, u8 id, u8 key_type,
2486 u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
2487 u16 tx_seq_16)
2488{
2489 struct wl1271_ap_key *ap_key;
2490 int i;
2491
2492 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2493
2494 if (key_size > MAX_KEY_SIZE)
2495 return -EINVAL;
2496
2497 /*
2498 * Find next free entry in ap_keys. Also check we are not replacing
2499 * an existing key.
2500 */
2501 for (i = 0; i < MAX_NUM_KEYS; i++) {
2502 if (wl->recorded_ap_keys[i] == NULL)
2503 break;
2504
2505 if (wl->recorded_ap_keys[i]->id == id) {
2506 wl1271_warning("trying to record key replacement");
2507 return -EINVAL;
2508 }
2509 }
2510
2511 if (i == MAX_NUM_KEYS)
2512 return -EBUSY;
2513
2514 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2515 if (!ap_key)
2516 return -ENOMEM;
2517
2518 ap_key->id = id;
2519 ap_key->key_type = key_type;
2520 ap_key->key_size = key_size;
2521 memcpy(ap_key->key, key, key_size);
2522 ap_key->hlid = hlid;
2523 ap_key->tx_seq_32 = tx_seq_32;
2524 ap_key->tx_seq_16 = tx_seq_16;
2525
2526 wl->recorded_ap_keys[i] = ap_key;
2527 return 0;
2528}
2529
2530static void wl1271_free_ap_keys(struct wl1271 *wl)
2531{
2532 int i;
2533
2534 for (i = 0; i < MAX_NUM_KEYS; i++) {
2535 kfree(wl->recorded_ap_keys[i]);
2536 wl->recorded_ap_keys[i] = NULL;
2537 }
2538}
2539
2540static int wl1271_ap_init_hwenc(struct wl1271 *wl)
2541{
2542 int i, ret = 0;
2543 struct wl1271_ap_key *key;
2544 bool wep_key_added = false;
2545
2546 for (i = 0; i < MAX_NUM_KEYS; i++) {
2547 if (wl->recorded_ap_keys[i] == NULL)
2548 break;
2549
2550 key = wl->recorded_ap_keys[i];
2551 ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE,
2552 key->id, key->key_type,
2553 key->key_size, key->key,
2554 key->hlid, key->tx_seq_32,
2555 key->tx_seq_16);
2556 if (ret < 0)
2557 goto out;
2558
2559 if (key->key_type == KEY_WEP)
2560 wep_key_added = true;
2561 }
2562
2563 if (wep_key_added) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002564 ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key,
2565 WL1271_AP_BROADCAST_HLID);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002566 if (ret < 0)
2567 goto out;
2568 }
2569
2570out:
2571 wl1271_free_ap_keys(wl);
2572 return ret;
2573}
2574
2575static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
2576 u8 key_size, const u8 *key, u32 tx_seq_32,
2577 u16 tx_seq_16, struct ieee80211_sta *sta)
2578{
2579 int ret;
2580 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
2581
2582 if (is_ap) {
2583 struct wl1271_station *wl_sta;
2584 u8 hlid;
2585
2586 if (sta) {
2587 wl_sta = (struct wl1271_station *)sta->drv_priv;
2588 hlid = wl_sta->hlid;
2589 } else {
2590 hlid = WL1271_AP_BROADCAST_HLID;
2591 }
2592
2593 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
2594 /*
2595 * We do not support removing keys after AP shutdown.
2596 * Pretend we do to make mac80211 happy.
2597 */
2598 if (action != KEY_ADD_OR_REPLACE)
2599 return 0;
2600
2601 ret = wl1271_record_ap_key(wl, id,
2602 key_type, key_size,
2603 key, hlid, tx_seq_32,
2604 tx_seq_16);
2605 } else {
2606 ret = wl1271_cmd_set_ap_key(wl, action,
2607 id, key_type, key_size,
2608 key, hlid, tx_seq_32,
2609 tx_seq_16);
2610 }
2611
2612 if (ret < 0)
2613 return ret;
2614 } else {
2615 const u8 *addr;
2616 static const u8 bcast_addr[ETH_ALEN] = {
2617 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2618 };
2619
2620 addr = sta ? sta->addr : bcast_addr;
2621
2622 if (is_zero_ether_addr(addr)) {
2623 /* We dont support TX only encryption */
2624 return -EOPNOTSUPP;
2625 }
2626
2627 /* The wl1271 does not allow to remove unicast keys - they
2628 will be cleared automatically on next CMD_JOIN. Ignore the
2629 request silently, as we dont want the mac80211 to emit
2630 an error message. */
2631 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2632 return 0;
2633
2634 ret = wl1271_cmd_set_sta_key(wl, action,
2635 id, key_type, key_size,
2636 key, addr, tx_seq_32,
2637 tx_seq_16);
2638 if (ret < 0)
2639 return ret;
2640
2641 /* the default WEP key needs to be configured at least once */
2642 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002643 ret = wl12xx_cmd_set_default_wep_key(wl,
2644 wl->default_key,
2645 wl->sta_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002646 if (ret < 0)
2647 return ret;
2648 }
2649 }
2650
2651 return 0;
2652}
2653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002654static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2655 struct ieee80211_vif *vif,
2656 struct ieee80211_sta *sta,
2657 struct ieee80211_key_conf *key_conf)
2658{
2659 struct wl1271 *wl = hw->priv;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002660 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002661 u32 tx_seq_32 = 0;
2662 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663 u8 key_type;
2664
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002665 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2666
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002667 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002669 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002670 key_conf->keylen, key_conf->flags);
2671 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2672
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002673 mutex_lock(&wl->mutex);
2674
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002675 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2676 ret = -EAGAIN;
2677 goto out_unlock;
2678 }
2679
Ido Yariva6208652011-03-01 15:14:41 +02002680 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681 if (ret < 0)
2682 goto out_unlock;
2683
Johannes Berg97359d12010-08-10 09:46:38 +02002684 switch (key_conf->cipher) {
2685 case WLAN_CIPHER_SUITE_WEP40:
2686 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 key_type = KEY_WEP;
2688
2689 key_conf->hw_key_idx = key_conf->keyidx;
2690 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002691 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002692 key_type = KEY_TKIP;
2693
2694 key_conf->hw_key_idx = key_conf->keyidx;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002695 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2696 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002697 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002698 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002699 key_type = KEY_AES;
2700
2701 key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
Juuso Oikarinen04e36fc2010-02-22 08:38:40 +02002702 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2703 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002704 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002705 case WL1271_CIPHER_SUITE_GEM:
2706 key_type = KEY_GEM;
2707 tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
2708 tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
2709 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002710 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002711 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002712
2713 ret = -EOPNOTSUPP;
2714 goto out_sleep;
2715 }
2716
2717 switch (cmd) {
2718 case SET_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002719 ret = wl1271_set_key(wl, KEY_ADD_OR_REPLACE,
2720 key_conf->keyidx, key_type,
2721 key_conf->keylen, key_conf->key,
2722 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002723 if (ret < 0) {
2724 wl1271_error("Could not add or replace key");
2725 goto out_sleep;
2726 }
2727 break;
2728
2729 case DISABLE_KEY:
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002730 ret = wl1271_set_key(wl, KEY_REMOVE,
2731 key_conf->keyidx, key_type,
2732 key_conf->keylen, key_conf->key,
2733 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734 if (ret < 0) {
2735 wl1271_error("Could not remove key");
2736 goto out_sleep;
2737 }
2738 break;
2739
2740 default:
2741 wl1271_error("Unsupported key cmd 0x%x", cmd);
2742 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743 break;
2744 }
2745
2746out_sleep:
2747 wl1271_ps_elp_sleep(wl);
2748
2749out_unlock:
2750 mutex_unlock(&wl->mutex);
2751
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002752 return ret;
2753}
2754
2755static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02002756 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002757 struct cfg80211_scan_request *req)
2758{
2759 struct wl1271 *wl = hw->priv;
2760 int ret;
2761 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002762 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002763
2764 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
2765
2766 if (req->n_ssids) {
2767 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03002768 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002769 }
2770
2771 mutex_lock(&wl->mutex);
2772
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002773 if (wl->state == WL1271_STATE_OFF) {
2774 /*
2775 * We cannot return -EBUSY here because cfg80211 will expect
2776 * a call to ieee80211_scan_completed if we do - in this case
2777 * there won't be any call.
2778 */
2779 ret = -EAGAIN;
2780 goto out;
2781 }
2782
Ido Yariva6208652011-03-01 15:14:41 +02002783 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002784 if (ret < 0)
2785 goto out;
2786
Luciano Coelho5924f892010-08-04 03:46:22 +03002787 ret = wl1271_scan(hw->priv, ssid, len, req);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002788
2789 wl1271_ps_elp_sleep(wl);
2790
2791out:
2792 mutex_unlock(&wl->mutex);
2793
2794 return ret;
2795}
2796
Eliad Peller73ecce32011-06-27 13:06:45 +03002797static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
2798 struct ieee80211_vif *vif)
2799{
2800 struct wl1271 *wl = hw->priv;
2801 int ret;
2802
2803 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
2804
2805 mutex_lock(&wl->mutex);
2806
2807 if (wl->state == WL1271_STATE_OFF)
2808 goto out;
2809
2810 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
2811 goto out;
2812
2813 ret = wl1271_ps_elp_wakeup(wl);
2814 if (ret < 0)
2815 goto out;
2816
2817 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
2818 ret = wl1271_scan_stop(wl);
2819 if (ret < 0)
2820 goto out_sleep;
2821 }
2822 wl->scan.state = WL1271_SCAN_STATE_IDLE;
2823 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
2824 wl->scan.req = NULL;
2825 ieee80211_scan_completed(wl->hw, true);
2826
2827out_sleep:
2828 wl1271_ps_elp_sleep(wl);
2829out:
2830 mutex_unlock(&wl->mutex);
2831
2832 cancel_delayed_work_sync(&wl->scan_complete_work);
2833}
2834
Luciano Coelho33c2c062011-05-10 14:46:02 +03002835static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
2836 struct ieee80211_vif *vif,
2837 struct cfg80211_sched_scan_request *req,
2838 struct ieee80211_sched_scan_ies *ies)
2839{
2840 struct wl1271 *wl = hw->priv;
2841 int ret;
2842
2843 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
2844
2845 mutex_lock(&wl->mutex);
2846
2847 ret = wl1271_ps_elp_wakeup(wl);
2848 if (ret < 0)
2849 goto out;
2850
2851 ret = wl1271_scan_sched_scan_config(wl, req, ies);
2852 if (ret < 0)
2853 goto out_sleep;
2854
2855 ret = wl1271_scan_sched_scan_start(wl);
2856 if (ret < 0)
2857 goto out_sleep;
2858
2859 wl->sched_scanning = true;
2860
2861out_sleep:
2862 wl1271_ps_elp_sleep(wl);
2863out:
2864 mutex_unlock(&wl->mutex);
2865 return ret;
2866}
2867
2868static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
2869 struct ieee80211_vif *vif)
2870{
2871 struct wl1271 *wl = hw->priv;
2872 int ret;
2873
2874 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
2875
2876 mutex_lock(&wl->mutex);
2877
2878 ret = wl1271_ps_elp_wakeup(wl);
2879 if (ret < 0)
2880 goto out;
2881
2882 wl1271_scan_sched_scan_stop(wl);
2883
2884 wl1271_ps_elp_sleep(wl);
2885out:
2886 mutex_unlock(&wl->mutex);
2887}
2888
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002889static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
2890{
2891 struct wl1271 *wl = hw->priv;
2892 int ret = 0;
2893
2894 mutex_lock(&wl->mutex);
2895
2896 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2897 ret = -EAGAIN;
2898 goto out;
2899 }
2900
Ido Yariva6208652011-03-01 15:14:41 +02002901 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002902 if (ret < 0)
2903 goto out;
2904
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002905 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01002906 if (ret < 0)
2907 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
2908
2909 wl1271_ps_elp_sleep(wl);
2910
2911out:
2912 mutex_unlock(&wl->mutex);
2913
2914 return ret;
2915}
2916
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
2918{
2919 struct wl1271 *wl = hw->priv;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002920 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921
2922 mutex_lock(&wl->mutex);
2923
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002924 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2925 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002926 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002927 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03002928
Ido Yariva6208652011-03-01 15:14:41 +02002929 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 if (ret < 0)
2931 goto out;
2932
Arik Nemtsov5f704d12011-04-18 14:15:21 +03002933 ret = wl1271_acx_rts_threshold(wl, value);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 if (ret < 0)
2935 wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
2936
2937 wl1271_ps_elp_sleep(wl);
2938
2939out:
2940 mutex_unlock(&wl->mutex);
2941
2942 return ret;
2943}
2944
Arik Nemtsove78a2872010-10-16 19:07:21 +02002945static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02002946 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002947{
Eliad Peller889cb362011-05-01 09:56:45 +03002948 u8 ssid_len;
2949 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
2950 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002951
Eliad Peller889cb362011-05-01 09:56:45 +03002952 if (!ptr) {
2953 wl1271_error("No SSID in IEs!");
2954 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002955 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02002956
Eliad Peller889cb362011-05-01 09:56:45 +03002957 ssid_len = ptr[1];
2958 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
2959 wl1271_error("SSID is too long!");
2960 return -EINVAL;
2961 }
2962
2963 wl->ssid_len = ssid_len;
2964 memcpy(wl->ssid, ptr+2, ssid_len);
2965 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02002966}
2967
Arik Nemtsove78a2872010-10-16 19:07:21 +02002968static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
2969 struct ieee80211_bss_conf *bss_conf,
2970 u32 changed)
2971{
2972 int ret = 0;
2973
2974 if (changed & BSS_CHANGED_ERP_SLOT) {
2975 if (bss_conf->use_short_slot)
2976 ret = wl1271_acx_slot(wl, SLOT_TIME_SHORT);
2977 else
2978 ret = wl1271_acx_slot(wl, SLOT_TIME_LONG);
2979 if (ret < 0) {
2980 wl1271_warning("Set slot time failed %d", ret);
2981 goto out;
2982 }
2983 }
2984
2985 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
2986 if (bss_conf->use_short_preamble)
2987 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
2988 else
2989 wl1271_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
2990 }
2991
2992 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
2993 if (bss_conf->use_cts_prot)
2994 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_ENABLE);
2995 else
2996 ret = wl1271_acx_cts_protect(wl, CTSPROTECT_DISABLE);
2997 if (ret < 0) {
2998 wl1271_warning("Set ctsprotect failed %d", ret);
2999 goto out;
3000 }
3001 }
3002
3003out:
3004 return ret;
3005}
3006
3007static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3008 struct ieee80211_vif *vif,
3009 struct ieee80211_bss_conf *bss_conf,
3010 u32 changed)
3011{
3012 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3013 int ret = 0;
3014
3015 if ((changed & BSS_CHANGED_BEACON_INT)) {
3016 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3017 bss_conf->beacon_int);
3018
3019 wl->beacon_int = bss_conf->beacon_int;
3020 }
3021
3022 if ((changed & BSS_CHANGED_BEACON)) {
3023 struct ieee80211_hdr *hdr;
3024 int ieoffset = offsetof(struct ieee80211_mgmt,
3025 u.beacon.variable);
3026 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3027 u16 tmpl_id;
3028
3029 if (!beacon)
3030 goto out;
3031
3032 wl1271_debug(DEBUG_MASTER, "beacon updated");
3033
3034 ret = wl1271_ssid_set(wl, beacon, ieoffset);
3035 if (ret < 0) {
3036 dev_kfree_skb(beacon);
3037 goto out;
3038 }
3039 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3040 CMD_TEMPL_BEACON;
3041 ret = wl1271_cmd_template_set(wl, tmpl_id,
3042 beacon->data,
3043 beacon->len, 0,
3044 wl1271_tx_min_rate_get(wl));
3045 if (ret < 0) {
3046 dev_kfree_skb(beacon);
3047 goto out;
3048 }
3049
3050 hdr = (struct ieee80211_hdr *) beacon->data;
3051 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3052 IEEE80211_STYPE_PROBE_RESP);
3053
3054 tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
3055 CMD_TEMPL_PROBE_RESPONSE;
3056 ret = wl1271_cmd_template_set(wl,
3057 tmpl_id,
3058 beacon->data,
3059 beacon->len, 0,
3060 wl1271_tx_min_rate_get(wl));
3061 dev_kfree_skb(beacon);
3062 if (ret < 0)
3063 goto out;
3064 }
3065
3066out:
3067 return ret;
3068}
3069
3070/* AP mode changes */
3071static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072 struct ieee80211_vif *vif,
3073 struct ieee80211_bss_conf *bss_conf,
3074 u32 changed)
3075{
Arik Nemtsove78a2872010-10-16 19:07:21 +02003076 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077
Arik Nemtsove78a2872010-10-16 19:07:21 +02003078 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3079 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003080
Arik Nemtsove78a2872010-10-16 19:07:21 +02003081 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
3082 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003083
Arik Nemtsov70f47422011-04-18 14:15:25 +03003084 ret = wl1271_init_ap_rates(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003085 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003086 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003087 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003088 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003089
3090 ret = wl1271_ap_init_templates(wl);
3091 if (ret < 0)
3092 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003093 }
3094
Arik Nemtsove78a2872010-10-16 19:07:21 +02003095 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3096 if (ret < 0)
3097 goto out;
3098
3099 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3100 if (bss_conf->enable_beacon) {
3101 if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003102 ret = wl12xx_cmd_role_start_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003103 if (ret < 0)
3104 goto out;
3105
3106 set_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3107 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003108
3109 ret = wl1271_ap_init_hwenc(wl);
3110 if (ret < 0)
3111 goto out;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003112 }
3113 } else {
3114 if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003115 ret = wl12xx_cmd_role_stop_ap(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003116 if (ret < 0)
3117 goto out;
3118
3119 clear_bit(WL1271_FLAG_AP_STARTED, &wl->flags);
3120 wl1271_debug(DEBUG_AP, "stopped AP");
3121 }
3122 }
3123 }
3124
3125 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3126 if (ret < 0)
3127 goto out;
3128out:
3129 return;
3130}
3131
3132/* STA/IBSS mode changes */
3133static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3134 struct ieee80211_vif *vif,
3135 struct ieee80211_bss_conf *bss_conf,
3136 u32 changed)
3137{
3138 bool do_join = false, set_assoc = false;
3139 bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003140 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003141 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003142 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003143 bool sta_exists = false;
3144 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003145
3146 if (is_ibss) {
3147 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3148 changed);
3149 if (ret < 0)
3150 goto out;
3151 }
3152
3153 if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss)
3154 do_join = true;
3155
3156 /* Need to update the SSID (for filtering etc) */
3157 if ((changed & BSS_CHANGED_BEACON) && is_ibss)
3158 do_join = true;
3159
3160 if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003161 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3162 bss_conf->enable_beacon ? "enabled" : "disabled");
3163
3164 if (bss_conf->enable_beacon)
3165 wl->set_bss_type = BSS_TYPE_IBSS;
3166 else
3167 wl->set_bss_type = BSS_TYPE_STA_BSS;
3168 do_join = true;
3169 }
3170
Arik Nemtsove78a2872010-10-16 19:07:21 +02003171 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003172 bool enable = false;
3173 if (bss_conf->cqm_rssi_thold)
3174 enable = true;
3175 ret = wl1271_acx_rssi_snr_trigger(wl, enable,
3176 bss_conf->cqm_rssi_thold,
3177 bss_conf->cqm_rssi_hyst);
3178 if (ret < 0)
3179 goto out;
3180 wl->rssi_thold = bss_conf->cqm_rssi_thold;
3181 }
3182
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003183 if ((changed & BSS_CHANGED_BSSID) &&
3184 /*
3185 * Now we know the correct bssid, so we send a new join command
3186 * and enable the BSSID filter
3187 */
3188 memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003189 memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
Juuso Oikarinena0cb7be2010-03-18 12:26:44 +02003190
Eliad Pellerfa287b82010-12-26 09:27:50 +01003191 if (!is_zero_ether_addr(wl->bssid)) {
3192 ret = wl1271_cmd_build_null_data(wl);
3193 if (ret < 0)
3194 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003195
Eliad Pellerfa287b82010-12-26 09:27:50 +01003196 ret = wl1271_build_qos_null_data(wl);
3197 if (ret < 0)
3198 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003199
Eliad Pellerfa287b82010-12-26 09:27:50 +01003200 /* Need to update the BSSID (for filtering etc) */
3201 do_join = true;
3202 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003203 }
3204
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003205 rcu_read_lock();
3206 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3207 if (sta) {
3208 /* save the supp_rates of the ap */
3209 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3210 if (sta->ht_cap.ht_supported)
3211 sta_rate_set |=
3212 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003213 sta_ht_cap = sta->ht_cap;
3214 sta_exists = true;
3215 }
3216 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003217
Arik Nemtsova1008852011-02-12 23:24:20 +02003218 if (sta_exists) {
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003219 /* handle new association with HT and HT information change */
3220 if ((changed & BSS_CHANGED_HT) &&
3221 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003222 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003223 true);
3224 if (ret < 0) {
3225 wl1271_warning("Set ht cap true failed %d",
3226 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003227 goto out;
3228 }
3229 ret = wl1271_acx_set_ht_information(wl,
3230 bss_conf->ht_operation_mode);
3231 if (ret < 0) {
3232 wl1271_warning("Set ht information failed %d",
3233 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003234 goto out;
3235 }
3236 }
3237 /* handle new association without HT and disassociation */
3238 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsova1008852011-02-12 23:24:20 +02003239 ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap,
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003240 false);
3241 if (ret < 0) {
3242 wl1271_warning("Set ht cap false failed %d",
3243 ret);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003244 goto out;
3245 }
3246 }
3247 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003248
Arik Nemtsove78a2872010-10-16 19:07:21 +02003249 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003250 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003251 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003252 int ieoffset;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003253 wl->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003254 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003255
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003256 wl->ps_poll_failures = 0;
3257
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003258 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003259 * use basic rates from AP, and determine lowest rate
3260 * to use with control frames.
3261 */
3262 rates = bss_conf->basic_rates;
3263 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3264 rates);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003265 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003266 if (sta_rate_set)
3267 wl->rate_set = wl1271_tx_enabled_rates_get(wl,
3268 sta_rate_set);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003269 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003270 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003271 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003272
3273 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003274 * with wl1271, we don't need to update the
3275 * beacon_int and dtim_period, because the firmware
3276 * updates it by itself when the first beacon is
3277 * received after a join.
3278 */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003279 ret = wl1271_cmd_build_ps_poll(wl, wl->aid);
3280 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003281 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003282
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003283 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003284 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003285 */
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003286 dev_kfree_skb(wl->probereq);
3287 wl->probereq = wl1271_cmd_build_ap_probe_req(wl, NULL);
3288 ieoffset = offsetof(struct ieee80211_mgmt,
3289 u.probe_req.variable);
3290 wl1271_ssid_set(wl, wl->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003291
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003292 /* enable the connection monitoring feature */
3293 ret = wl1271_acx_conn_monit_params(wl, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003294 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003295 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003296
3297 /* If we want to go in PSM but we're not there yet */
Juuso Oikarinen71449f82009-12-11 15:41:07 +02003298 if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) &&
3299 !test_bit(WL1271_FLAG_PSM, &wl->flags)) {
Arik Nemtsove78a2872010-10-16 19:07:21 +02003300 enum wl1271_cmd_ps_mode mode;
3301
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003302 mode = STATION_POWER_SAVE_MODE;
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003303 ret = wl1271_ps_set_mode(wl, mode,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +02003304 wl->basic_rate,
Juuso Oikarinen65cddbf2010-08-24 06:28:03 +03003305 true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003306 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003307 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003308 }
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003309 } else {
3310 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003311 bool was_assoc =
3312 !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
3313 &wl->flags);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03003314 clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003315 wl->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003316
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003317 /* free probe-request template */
3318 dev_kfree_skb(wl->probereq);
3319 wl->probereq = NULL;
3320
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003321 /* re-enable dynamic ps - just in case */
Juuso Oikarinenf532be62010-07-08 17:50:05 +03003322 ieee80211_enable_dyn_ps(wl->vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003323
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003324 /* revert back to minimum rates for the current band */
3325 wl1271_set_band_rate(wl);
Arik Nemtsove0fe3712010-10-16 18:19:53 +02003326 wl->basic_rate = wl1271_tx_min_rate_get(wl);
Arik Nemtsov79b223f2010-10-16 17:52:59 +02003327 ret = wl1271_acx_sta_rate_policies(wl);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003328 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003329 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003330
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003331 /* disable connection monitor features */
3332 ret = wl1271_acx_conn_monit_params(wl, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003333
3334 /* Disable the keep-alive feature */
3335 ret = wl1271_acx_keep_alive_mode(wl, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003336 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003337 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003338
3339 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003340 if (was_assoc) {
3341 wl1271_unjoin(wl);
3342 wl1271_dummy_join(wl);
3343 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003344 }
3345 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003346
Eliad Pellerd192d262011-05-24 14:33:08 +03003347 if (changed & BSS_CHANGED_IBSS) {
3348 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3349 bss_conf->ibss_joined);
3350
3351 if (bss_conf->ibss_joined) {
3352 u32 rates = bss_conf->basic_rates;
3353 wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
3354 rates);
3355 wl->basic_rate = wl1271_tx_min_rate_get(wl);
3356
3357 /* by default, use 11b rates */
3358 wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3359 ret = wl1271_acx_sta_rate_policies(wl);
3360 if (ret < 0)
3361 goto out;
3362 }
3363 }
3364
Arik Nemtsove78a2872010-10-16 19:07:21 +02003365 ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
3366 if (ret < 0)
3367 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003368
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003369 if (changed & BSS_CHANGED_ARP_FILTER) {
3370 __be32 addr = bss_conf->arp_addr_list[0];
3371 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3372
Eliad Pellerc5312772010-12-09 11:31:27 +02003373 if (bss_conf->arp_addr_cnt == 1 &&
3374 bss_conf->arp_filter_enabled) {
3375 /*
3376 * The template should have been configured only upon
3377 * association. however, it seems that the correct ip
3378 * isn't being set (when sending), so we have to
3379 * reconfigure the template upon every ip change.
3380 */
3381 ret = wl1271_cmd_build_arp_rsp(wl, addr);
3382 if (ret < 0) {
3383 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003385 }
3386
3387 ret = wl1271_acx_arp_ip_filter(wl,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003388 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003389 addr);
3390 } else
3391 ret = wl1271_acx_arp_ip_filter(wl, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003392
3393 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003394 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003395 }
3396
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003397 if (do_join) {
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003398 ret = wl1271_join(wl, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003399 if (ret < 0) {
3400 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003401 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003402 }
Eliad Pelleref4b29e2011-06-06 13:03:12 +03003403 wl1271_check_operstate(wl, ieee80211_get_operstate(vif));
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003404 }
3405
Arik Nemtsove78a2872010-10-16 19:07:21 +02003406out:
3407 return;
3408}
3409
3410static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3411 struct ieee80211_vif *vif,
3412 struct ieee80211_bss_conf *bss_conf,
3413 u32 changed)
3414{
3415 struct wl1271 *wl = hw->priv;
3416 bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
3417 int ret;
3418
3419 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3420 (int)changed);
3421
3422 mutex_lock(&wl->mutex);
3423
3424 if (unlikely(wl->state == WL1271_STATE_OFF))
3425 goto out;
3426
Ido Yariva6208652011-03-01 15:14:41 +02003427 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003428 if (ret < 0)
3429 goto out;
3430
3431 if (is_ap)
3432 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3433 else
3434 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3435
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003436 wl1271_ps_elp_sleep(wl);
3437
3438out:
3439 mutex_unlock(&wl->mutex);
3440}
3441
Kalle Valoc6999d82010-02-18 13:25:41 +02003442static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
3443 const struct ieee80211_tx_queue_params *params)
3444{
3445 struct wl1271 *wl = hw->priv;
Kalle Valo4695dc92010-03-18 12:26:38 +02003446 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003447 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003448
3449 mutex_lock(&wl->mutex);
3450
3451 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3452
Kalle Valo4695dc92010-03-18 12:26:38 +02003453 if (params->uapsd)
3454 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3455 else
3456 ps_scheme = CONF_PS_SCHEME_LEGACY;
3457
Arik Nemtsov488fc542010-10-16 20:33:45 +02003458 if (wl->state == WL1271_STATE_OFF) {
3459 /*
3460 * If the state is off, the parameters will be recorded and
3461 * configured on init. This happens in AP-mode.
3462 */
3463 struct conf_tx_ac_category *conf_ac =
3464 &wl->conf.tx.ac_conf[wl1271_tx_get_queue(queue)];
3465 struct conf_tx_tid *conf_tid =
3466 &wl->conf.tx.tid_conf[wl1271_tx_get_queue(queue)];
3467
3468 conf_ac->ac = wl1271_tx_get_queue(queue);
3469 conf_ac->cw_min = (u8)params->cw_min;
3470 conf_ac->cw_max = params->cw_max;
3471 conf_ac->aifsn = params->aifs;
3472 conf_ac->tx_op_limit = params->txop << 5;
3473
3474 conf_tid->queue_id = wl1271_tx_get_queue(queue);
3475 conf_tid->channel_type = CONF_CHANNEL_TYPE_EDCF;
3476 conf_tid->tsid = wl1271_tx_get_queue(queue);
3477 conf_tid->ps_scheme = ps_scheme;
3478 conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
3479 conf_tid->apsd_conf[0] = 0;
3480 conf_tid->apsd_conf[1] = 0;
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003481 goto out;
3482 }
Arik Nemtsov488fc542010-10-16 20:33:45 +02003483
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003484 ret = wl1271_ps_elp_wakeup(wl);
3485 if (ret < 0)
3486 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003487
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003488 /*
3489 * the txop is confed in units of 32us by the mac80211,
3490 * we need us
3491 */
3492 ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
3493 params->cw_min, params->cw_max,
3494 params->aifs, params->txop << 5);
3495 if (ret < 0)
3496 goto out_sleep;
3497
3498 ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
3499 CONF_CHANNEL_TYPE_EDCF,
3500 wl1271_tx_get_queue(queue),
3501 ps_scheme, CONF_ACK_POLICY_LEGACY,
3502 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003503
3504out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003505 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003506
3507out:
3508 mutex_unlock(&wl->mutex);
3509
3510 return ret;
3511}
3512
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003513static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
3514{
3515
3516 struct wl1271 *wl = hw->priv;
3517 u64 mactime = ULLONG_MAX;
3518 int ret;
3519
3520 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
3521
3522 mutex_lock(&wl->mutex);
3523
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003524 if (unlikely(wl->state == WL1271_STATE_OFF))
3525 goto out;
3526
Ido Yariva6208652011-03-01 15:14:41 +02003527 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003528 if (ret < 0)
3529 goto out;
3530
3531 ret = wl1271_acx_tsf_info(wl, &mactime);
3532 if (ret < 0)
3533 goto out_sleep;
3534
3535out_sleep:
3536 wl1271_ps_elp_sleep(wl);
3537
3538out:
3539 mutex_unlock(&wl->mutex);
3540 return mactime;
3541}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003542
John W. Linvilleece550d2010-07-28 16:41:06 -04003543static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
3544 struct survey_info *survey)
3545{
3546 struct wl1271 *wl = hw->priv;
3547 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003548
John W. Linvilleece550d2010-07-28 16:41:06 -04003549 if (idx != 0)
3550 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003551
John W. Linvilleece550d2010-07-28 16:41:06 -04003552 survey->channel = conf->channel;
3553 survey->filled = SURVEY_INFO_NOISE_DBM;
3554 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003555
John W. Linvilleece550d2010-07-28 16:41:06 -04003556 return 0;
3557}
3558
Arik Nemtsov409622e2011-02-23 00:22:29 +02003559static int wl1271_allocate_sta(struct wl1271 *wl,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003560 struct ieee80211_sta *sta,
3561 u8 *hlid)
3562{
3563 struct wl1271_station *wl_sta;
3564 int id;
3565
3566 id = find_first_zero_bit(wl->ap_hlid_map, AP_MAX_STATIONS);
3567 if (id >= AP_MAX_STATIONS) {
3568 wl1271_warning("could not allocate HLID - too much stations");
3569 return -EBUSY;
3570 }
3571
3572 wl_sta = (struct wl1271_station *)sta->drv_priv;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003573 __set_bit(id, wl->ap_hlid_map);
3574 wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
3575 *hlid = wl_sta->hlid;
Arik Nemtsovb622d992011-02-23 00:22:31 +02003576 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003577 return 0;
3578}
3579
Arik Nemtsov409622e2011-02-23 00:22:29 +02003580static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003581{
3582 int id = hlid - WL1271_AP_STA_HLID_START;
3583
Arik Nemtsov409622e2011-02-23 00:22:29 +02003584 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3585 return;
3586
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003587 __clear_bit(id, wl->ap_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003588 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02003589 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02003590 __clear_bit(hlid, &wl->ap_ps_map);
3591 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003592}
3593
Arik Nemtsov3618f302011-06-26 10:36:03 +03003594bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
3595{
3596 int id = hlid - WL1271_AP_STA_HLID_START;
3597 return test_bit(id, wl->ap_hlid_map);
3598}
3599
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003600static int wl1271_op_sta_add(struct ieee80211_hw *hw,
3601 struct ieee80211_vif *vif,
3602 struct ieee80211_sta *sta)
3603{
3604 struct wl1271 *wl = hw->priv;
3605 int ret = 0;
3606 u8 hlid;
3607
3608 mutex_lock(&wl->mutex);
3609
3610 if (unlikely(wl->state == WL1271_STATE_OFF))
3611 goto out;
3612
3613 if (wl->bss_type != BSS_TYPE_AP_BSS)
3614 goto out;
3615
3616 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
3617
Arik Nemtsov409622e2011-02-23 00:22:29 +02003618 ret = wl1271_allocate_sta(wl, sta, &hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003619 if (ret < 0)
3620 goto out;
3621
Ido Yariva6208652011-03-01 15:14:41 +02003622 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003623 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02003624 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003625
Eliad Pellerc690ec82011-08-14 13:17:07 +03003626 ret = wl12xx_cmd_add_peer(wl, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003627 if (ret < 0)
3628 goto out_sleep;
3629
3630out_sleep:
3631 wl1271_ps_elp_sleep(wl);
3632
Arik Nemtsov409622e2011-02-23 00:22:29 +02003633out_free_sta:
3634 if (ret < 0)
3635 wl1271_free_sta(wl, hlid);
3636
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003637out:
3638 mutex_unlock(&wl->mutex);
3639 return ret;
3640}
3641
3642static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
3643 struct ieee80211_vif *vif,
3644 struct ieee80211_sta *sta)
3645{
3646 struct wl1271 *wl = hw->priv;
3647 struct wl1271_station *wl_sta;
3648 int ret = 0, id;
3649
3650 mutex_lock(&wl->mutex);
3651
3652 if (unlikely(wl->state == WL1271_STATE_OFF))
3653 goto out;
3654
3655 if (wl->bss_type != BSS_TYPE_AP_BSS)
3656 goto out;
3657
3658 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
3659
3660 wl_sta = (struct wl1271_station *)sta->drv_priv;
3661 id = wl_sta->hlid - WL1271_AP_STA_HLID_START;
3662 if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
3663 goto out;
3664
Ido Yariva6208652011-03-01 15:14:41 +02003665 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003666 if (ret < 0)
3667 goto out;
3668
Eliad Pellerc690ec82011-08-14 13:17:07 +03003669 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003670 if (ret < 0)
3671 goto out_sleep;
3672
Arik Nemtsov409622e2011-02-23 00:22:29 +02003673 wl1271_free_sta(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02003674
3675out_sleep:
3676 wl1271_ps_elp_sleep(wl);
3677
3678out:
3679 mutex_unlock(&wl->mutex);
3680 return ret;
3681}
3682
Luciano Coelho4623ec72011-03-21 19:26:41 +02003683static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
3684 struct ieee80211_vif *vif,
3685 enum ieee80211_ampdu_mlme_action action,
3686 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
3687 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003688{
3689 struct wl1271 *wl = hw->priv;
3690 int ret;
3691
3692 mutex_lock(&wl->mutex);
3693
3694 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3695 ret = -EAGAIN;
3696 goto out;
3697 }
3698
Ido Yariva6208652011-03-01 15:14:41 +02003699 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003700 if (ret < 0)
3701 goto out;
3702
Shahar Levi70559a02011-05-22 16:10:22 +03003703 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
3704 tid, action);
3705
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003706 switch (action) {
3707 case IEEE80211_AMPDU_RX_START:
Shahar Levi70559a02011-05-22 16:10:22 +03003708 if ((wl->ba_support) && (wl->ba_allowed)) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01003709 ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
3710 true);
3711 if (!ret)
3712 wl->ba_rx_bitmap |= BIT(tid);
3713 } else {
3714 ret = -ENOTSUPP;
3715 }
3716 break;
3717
3718 case IEEE80211_AMPDU_RX_STOP:
3719 ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false);
3720 if (!ret)
3721 wl->ba_rx_bitmap &= ~BIT(tid);
3722 break;
3723
3724 /*
3725 * The BA initiator session management in FW independently.
3726 * Falling break here on purpose for all TX APDU commands.
3727 */
3728 case IEEE80211_AMPDU_TX_START:
3729 case IEEE80211_AMPDU_TX_STOP:
3730 case IEEE80211_AMPDU_TX_OPERATIONAL:
3731 ret = -EINVAL;
3732 break;
3733
3734 default:
3735 wl1271_error("Incorrect ampdu action id=%x\n", action);
3736 ret = -EINVAL;
3737 }
3738
3739 wl1271_ps_elp_sleep(wl);
3740
3741out:
3742 mutex_unlock(&wl->mutex);
3743
3744 return ret;
3745}
3746
Arik Nemtsov33437892011-04-26 23:35:39 +03003747static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
3748{
3749 struct wl1271 *wl = hw->priv;
3750 bool ret = false;
3751
3752 mutex_lock(&wl->mutex);
3753
3754 if (unlikely(wl->state == WL1271_STATE_OFF))
3755 goto out;
3756
3757 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03003758 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03003759
3760 /* the above is appropriate for STA mode for PS purposes */
3761 WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
3762
3763out:
3764 mutex_unlock(&wl->mutex);
3765
3766 return ret;
3767}
3768
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003769/* can't be const, mac80211 writes to this */
3770static struct ieee80211_rate wl1271_rates[] = {
3771 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003772 .hw_value = CONF_HW_BIT_RATE_1MBPS,
3773 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003774 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003775 .hw_value = CONF_HW_BIT_RATE_2MBPS,
3776 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003777 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3778 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003779 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
3780 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003781 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3782 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003783 .hw_value = CONF_HW_BIT_RATE_11MBPS,
3784 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003785 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
3786 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003787 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3788 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003789 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003790 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3791 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003792 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003793 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3794 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003795 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003796 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3797 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003798 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003799 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3800 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003801 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003802 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3803 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003804 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003805 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3806 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003807 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03003808 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3809 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003810};
3811
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003812/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003813static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02003814 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003815 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003816 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
3817 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
3818 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003819 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003820 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
3821 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
3822 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02003823 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003824 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
3825 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
3826 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01003827 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003828};
3829
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003830/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003831static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003832 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003833 7, /* CONF_HW_RXTX_RATE_MCS7 */
3834 6, /* CONF_HW_RXTX_RATE_MCS6 */
3835 5, /* CONF_HW_RXTX_RATE_MCS5 */
3836 4, /* CONF_HW_RXTX_RATE_MCS4 */
3837 3, /* CONF_HW_RXTX_RATE_MCS3 */
3838 2, /* CONF_HW_RXTX_RATE_MCS2 */
3839 1, /* CONF_HW_RXTX_RATE_MCS1 */
3840 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003841
3842 11, /* CONF_HW_RXTX_RATE_54 */
3843 10, /* CONF_HW_RXTX_RATE_48 */
3844 9, /* CONF_HW_RXTX_RATE_36 */
3845 8, /* CONF_HW_RXTX_RATE_24 */
3846
3847 /* TI-specific rate */
3848 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3849
3850 7, /* CONF_HW_RXTX_RATE_18 */
3851 6, /* CONF_HW_RXTX_RATE_12 */
3852 3, /* CONF_HW_RXTX_RATE_11 */
3853 5, /* CONF_HW_RXTX_RATE_9 */
3854 4, /* CONF_HW_RXTX_RATE_6 */
3855 2, /* CONF_HW_RXTX_RATE_5_5 */
3856 1, /* CONF_HW_RXTX_RATE_2 */
3857 0 /* CONF_HW_RXTX_RATE_1 */
3858};
3859
Shahar Levie8b03a22010-10-13 16:09:39 +02003860/* 11n STA capabilities */
3861#define HW_RX_HIGHEST_RATE 72
3862
Shahar Levi00d20102010-11-08 11:20:10 +00003863#ifdef CONFIG_WL12XX_HT
3864#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02003865 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
3866 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02003867 .ht_supported = true, \
3868 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
3869 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
3870 .mcs = { \
3871 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
3872 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
3873 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
3874 }, \
3875}
Shahar Levi18357852010-10-13 16:09:41 +02003876#else
Shahar Levi00d20102010-11-08 11:20:10 +00003877#define WL12XX_HT_CAP { \
Shahar Levi18357852010-10-13 16:09:41 +02003878 .ht_supported = false, \
3879}
3880#endif
Shahar Levie8b03a22010-10-13 16:09:39 +02003881
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003882/* can't be const, mac80211 writes to this */
3883static struct ieee80211_supported_band wl1271_band_2ghz = {
3884 .channels = wl1271_channels,
3885 .n_channels = ARRAY_SIZE(wl1271_channels),
3886 .bitrates = wl1271_rates,
3887 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00003888 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003889};
3890
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003891/* 5 GHz data rates for WL1273 */
3892static struct ieee80211_rate wl1271_rates_5ghz[] = {
3893 { .bitrate = 60,
3894 .hw_value = CONF_HW_BIT_RATE_6MBPS,
3895 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
3896 { .bitrate = 90,
3897 .hw_value = CONF_HW_BIT_RATE_9MBPS,
3898 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
3899 { .bitrate = 120,
3900 .hw_value = CONF_HW_BIT_RATE_12MBPS,
3901 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
3902 { .bitrate = 180,
3903 .hw_value = CONF_HW_BIT_RATE_18MBPS,
3904 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
3905 { .bitrate = 240,
3906 .hw_value = CONF_HW_BIT_RATE_24MBPS,
3907 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
3908 { .bitrate = 360,
3909 .hw_value = CONF_HW_BIT_RATE_36MBPS,
3910 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
3911 { .bitrate = 480,
3912 .hw_value = CONF_HW_BIT_RATE_48MBPS,
3913 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
3914 { .bitrate = 540,
3915 .hw_value = CONF_HW_BIT_RATE_54MBPS,
3916 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
3917};
3918
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01003919/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003920static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03003921 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
3922 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
3923 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
3924 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
3925 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
3926 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
3927 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
3928 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
3929 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
3930 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
3931 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
3932 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
3933 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
3934 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
3935 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
3936 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
3937 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
3938 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
3939 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
3940 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
3941 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
3942 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
3943 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
3944 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
3945 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
3946 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
3947 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
3948 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
3949 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
3950 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
3951 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
3952 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
3953 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
3954 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003955};
3956
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003957/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02003958static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003959 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02003960 7, /* CONF_HW_RXTX_RATE_MCS7 */
3961 6, /* CONF_HW_RXTX_RATE_MCS6 */
3962 5, /* CONF_HW_RXTX_RATE_MCS5 */
3963 4, /* CONF_HW_RXTX_RATE_MCS4 */
3964 3, /* CONF_HW_RXTX_RATE_MCS3 */
3965 2, /* CONF_HW_RXTX_RATE_MCS2 */
3966 1, /* CONF_HW_RXTX_RATE_MCS1 */
3967 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003968
3969 7, /* CONF_HW_RXTX_RATE_54 */
3970 6, /* CONF_HW_RXTX_RATE_48 */
3971 5, /* CONF_HW_RXTX_RATE_36 */
3972 4, /* CONF_HW_RXTX_RATE_24 */
3973
3974 /* TI-specific rate */
3975 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
3976
3977 3, /* CONF_HW_RXTX_RATE_18 */
3978 2, /* CONF_HW_RXTX_RATE_12 */
3979 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
3980 1, /* CONF_HW_RXTX_RATE_9 */
3981 0, /* CONF_HW_RXTX_RATE_6 */
3982 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
3983 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
3984 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
3985};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003986
3987static struct ieee80211_supported_band wl1271_band_5ghz = {
3988 .channels = wl1271_channels_5ghz,
3989 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
3990 .bitrates = wl1271_rates_5ghz,
3991 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00003992 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03003993};
3994
Tobias Klausera0ea9492010-05-20 10:38:11 +02003995static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02003996 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
3997 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
3998};
3999
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004000static const struct ieee80211_ops wl1271_ops = {
4001 .start = wl1271_op_start,
4002 .stop = wl1271_op_stop,
4003 .add_interface = wl1271_op_add_interface,
4004 .remove_interface = wl1271_op_remove_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004005#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004006 .suspend = wl1271_op_suspend,
4007 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004008#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004009 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004010 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004011 .configure_filter = wl1271_op_configure_filter,
4012 .tx = wl1271_op_tx,
4013 .set_key = wl1271_op_set_key,
4014 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004015 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004016 .sched_scan_start = wl1271_op_sched_scan_start,
4017 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004018 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004019 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004020 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004021 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004022 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004023 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004024 .sta_add = wl1271_op_sta_add,
4025 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004026 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004027 .tx_frames_pending = wl1271_tx_frames_pending,
Kalle Valoc8c90872010-02-18 13:25:53 +02004028 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004029};
4030
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004031
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004032u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004033{
4034 u8 idx;
4035
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004036 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004037
4038 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4039 wl1271_error("Illegal RX rate from HW: %d", rate);
4040 return 0;
4041 }
4042
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004043 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004044 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4045 wl1271_error("Unsupported RX rate from HW: %d", rate);
4046 return 0;
4047 }
4048
4049 return idx;
4050}
4051
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004052static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4053 struct device_attribute *attr,
4054 char *buf)
4055{
4056 struct wl1271 *wl = dev_get_drvdata(dev);
4057 ssize_t len;
4058
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004059 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004060
4061 mutex_lock(&wl->mutex);
4062 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4063 wl->sg_enabled);
4064 mutex_unlock(&wl->mutex);
4065
4066 return len;
4067
4068}
4069
4070static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4071 struct device_attribute *attr,
4072 const char *buf, size_t count)
4073{
4074 struct wl1271 *wl = dev_get_drvdata(dev);
4075 unsigned long res;
4076 int ret;
4077
Luciano Coelho6277ed62011-04-01 17:49:54 +03004078 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004079 if (ret < 0) {
4080 wl1271_warning("incorrect value written to bt_coex_mode");
4081 return count;
4082 }
4083
4084 mutex_lock(&wl->mutex);
4085
4086 res = !!res;
4087
4088 if (res == wl->sg_enabled)
4089 goto out;
4090
4091 wl->sg_enabled = res;
4092
4093 if (wl->state == WL1271_STATE_OFF)
4094 goto out;
4095
Ido Yariva6208652011-03-01 15:14:41 +02004096 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004097 if (ret < 0)
4098 goto out;
4099
4100 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4101 wl1271_ps_elp_sleep(wl);
4102
4103 out:
4104 mutex_unlock(&wl->mutex);
4105 return count;
4106}
4107
4108static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4109 wl1271_sysfs_show_bt_coex_state,
4110 wl1271_sysfs_store_bt_coex_state);
4111
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004112static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4113 struct device_attribute *attr,
4114 char *buf)
4115{
4116 struct wl1271 *wl = dev_get_drvdata(dev);
4117 ssize_t len;
4118
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004119 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004120
4121 mutex_lock(&wl->mutex);
4122 if (wl->hw_pg_ver >= 0)
4123 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4124 else
4125 len = snprintf(buf, len, "n/a\n");
4126 mutex_unlock(&wl->mutex);
4127
4128 return len;
4129}
4130
Gery Kahn6f07b722011-07-18 14:21:49 +03004131static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004132 wl1271_sysfs_show_hw_pg_ver, NULL);
4133
Ido Yariv95dac04f2011-06-06 14:57:06 +03004134static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4135 struct bin_attribute *bin_attr,
4136 char *buffer, loff_t pos, size_t count)
4137{
4138 struct device *dev = container_of(kobj, struct device, kobj);
4139 struct wl1271 *wl = dev_get_drvdata(dev);
4140 ssize_t len;
4141 int ret;
4142
4143 ret = mutex_lock_interruptible(&wl->mutex);
4144 if (ret < 0)
4145 return -ERESTARTSYS;
4146
4147 /* Let only one thread read the log at a time, blocking others */
4148 while (wl->fwlog_size == 0) {
4149 DEFINE_WAIT(wait);
4150
4151 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4152 &wait,
4153 TASK_INTERRUPTIBLE);
4154
4155 if (wl->fwlog_size != 0) {
4156 finish_wait(&wl->fwlog_waitq, &wait);
4157 break;
4158 }
4159
4160 mutex_unlock(&wl->mutex);
4161
4162 schedule();
4163 finish_wait(&wl->fwlog_waitq, &wait);
4164
4165 if (signal_pending(current))
4166 return -ERESTARTSYS;
4167
4168 ret = mutex_lock_interruptible(&wl->mutex);
4169 if (ret < 0)
4170 return -ERESTARTSYS;
4171 }
4172
4173 /* Check if the fwlog is still valid */
4174 if (wl->fwlog_size < 0) {
4175 mutex_unlock(&wl->mutex);
4176 return 0;
4177 }
4178
4179 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4180 len = min(count, (size_t)wl->fwlog_size);
4181 wl->fwlog_size -= len;
4182 memcpy(buffer, wl->fwlog, len);
4183
4184 /* Make room for new messages */
4185 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4186
4187 mutex_unlock(&wl->mutex);
4188
4189 return len;
4190}
4191
4192static struct bin_attribute fwlog_attr = {
4193 .attr = {.name = "fwlog", .mode = S_IRUSR},
4194 .read = wl1271_sysfs_read_fwlog,
4195};
4196
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004197int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004198{
4199 int ret;
4200
4201 if (wl->mac80211_registered)
4202 return 0;
4203
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004204 ret = wl1271_fetch_nvs(wl);
4205 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004206 /* NOTE: The wl->nvs->nvs element must be first, in
4207 * order to simplify the casting, we assume it is at
4208 * the beginning of the wl->nvs structure.
4209 */
4210 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004211
4212 wl->mac_addr[0] = nvs_ptr[11];
4213 wl->mac_addr[1] = nvs_ptr[10];
4214 wl->mac_addr[2] = nvs_ptr[6];
4215 wl->mac_addr[3] = nvs_ptr[5];
4216 wl->mac_addr[4] = nvs_ptr[4];
4217 wl->mac_addr[5] = nvs_ptr[3];
4218 }
4219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004220 SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
4221
4222 ret = ieee80211_register_hw(wl->hw);
4223 if (ret < 0) {
4224 wl1271_error("unable to register mac80211 hw: %d", ret);
4225 return ret;
4226 }
4227
4228 wl->mac80211_registered = true;
4229
Eliad Pellerd60080a2010-11-24 12:53:16 +02004230 wl1271_debugfs_init(wl);
4231
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004232 register_netdevice_notifier(&wl1271_dev_notifier);
4233
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004234 wl1271_notice("loaded");
4235
4236 return 0;
4237}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004238EXPORT_SYMBOL_GPL(wl1271_register_hw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004239
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004240void wl1271_unregister_hw(struct wl1271 *wl)
4241{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004242 if (wl->state == WL1271_STATE_PLT)
4243 __wl1271_plt_stop(wl);
4244
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004245 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004246 ieee80211_unregister_hw(wl->hw);
4247 wl->mac80211_registered = false;
4248
4249}
4250EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
4251
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004252int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004253{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004254 static const u32 cipher_suites[] = {
4255 WLAN_CIPHER_SUITE_WEP40,
4256 WLAN_CIPHER_SUITE_WEP104,
4257 WLAN_CIPHER_SUITE_TKIP,
4258 WLAN_CIPHER_SUITE_CCMP,
4259 WL1271_CIPHER_SUITE_GEM,
4260 };
4261
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004262 /* The tx descriptor buffer and the TKIP space. */
4263 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4264 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004265
4266 /* unit us */
4267 /* FIXME: find a proper value */
4268 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03004269 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004270
4271 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen03442a32009-11-23 23:22:14 +02004272 IEEE80211_HW_BEACON_FILTER |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02004273 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02004274 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02004275 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03004276 IEEE80211_HW_CONNECTION_MONITOR |
Eliad Peller62c07402011-02-02 11:20:05 +02004277 IEEE80211_HW_SUPPORTS_CQM_RSSI |
Luciano Coelho25eaea302011-05-02 12:37:33 +03004278 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03004279 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsovba7c0822011-02-23 00:22:28 +02004280 IEEE80211_HW_AP_LINK_PS;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004281
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004282 wl->hw->wiphy->cipher_suites = cipher_suites;
4283 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
4284
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02004285 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Arik Nemtsov038d9252010-10-16 21:53:24 +02004286 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004287 wl->hw->wiphy->max_scan_ssids = 1;
Guy Eilamea559b42010-12-09 16:54:59 +02004288 /*
4289 * Maximum length of elements in scanning probe request templates
4290 * should be the maximum length possible for a template, without
4291 * the IEEE80211 header of the template
4292 */
Eliad Peller154037d2011-08-14 13:17:12 +03004293 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02004294 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004295
Luciano Coelho4a31c112011-03-21 23:16:14 +02004296 /* make sure all our channels fit in the scanned_ch bitmask */
4297 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
4298 ARRAY_SIZE(wl1271_channels_5ghz) >
4299 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01004300 /*
4301 * We keep local copies of the band structs because we need to
4302 * modify them on a per-device basis.
4303 */
4304 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
4305 sizeof(wl1271_band_2ghz));
4306 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
4307 sizeof(wl1271_band_5ghz));
4308
4309 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
4310 &wl->bands[IEEE80211_BAND_2GHZ];
4311 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
4312 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004313
Kalle Valo12bd8942010-03-18 12:26:33 +02004314 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02004315 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02004316
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01004317 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
4318
Teemu Paasikivi8197b712010-02-22 08:38:23 +02004319 SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004320
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004321 wl->hw->sta_data_size = sizeof(struct wl1271_station);
4322
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01004323 wl->hw->max_rx_aggregation_subframes = 8;
4324
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004325 return 0;
4326}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004327EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004328
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004329#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004330
Teemu Paasikivi2d5e82b2010-02-22 08:38:21 +02004331struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004332{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004333 struct ieee80211_hw *hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004334 struct platform_device *plat_dev = NULL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004335 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004336 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004337 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004338
4339 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
4340 if (!hw) {
4341 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004342 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004343 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004344 }
4345
Julia Lawall929ebd32010-05-15 23:16:39 +02004346 plat_dev = kmemdup(&wl1271_device, sizeof(wl1271_device), GFP_KERNEL);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004347 if (!plat_dev) {
4348 wl1271_error("could not allocate platform_device");
4349 ret = -ENOMEM;
4350 goto err_plat_alloc;
4351 }
4352
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004353 wl = hw->priv;
4354 memset(wl, 0, sizeof(*wl));
4355
Juuso Oikarinen01c09162009-10-13 12:47:55 +03004356 INIT_LIST_HEAD(&wl->list);
4357
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004358 wl->hw = hw;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004359 wl->plat_dev = plat_dev;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004360
Juuso Oikarinen6742f552010-12-13 09:52:37 +02004361 for (i = 0; i < NUM_TX_QUEUES; i++)
4362 skb_queue_head_init(&wl->tx_queue[i]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004363
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004364 for (i = 0; i < NUM_TX_QUEUES; i++)
4365 for (j = 0; j < AP_MAX_LINKS; j++)
4366 skb_queue_head_init(&wl->links[j].tx_queue[i]);
4367
Ido Yariva6208652011-03-01 15:14:41 +02004368 skb_queue_head_init(&wl->deferred_rx_queue);
4369 skb_queue_head_init(&wl->deferred_tx_queue);
4370
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03004371 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03004372 INIT_DELAYED_WORK(&wl->pspoll_work, wl1271_pspoll_work);
Ido Yariva6208652011-03-01 15:14:41 +02004373 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02004374 INIT_WORK(&wl->tx_work, wl1271_tx_work);
4375 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
4376 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03004377 INIT_WORK(&wl->rx_streaming_enable_work,
4378 wl1271_rx_streaming_enable_work);
4379 INIT_WORK(&wl->rx_streaming_disable_work,
4380 wl1271_rx_streaming_disable_work);
4381
Eliad Peller92ef8962011-06-07 12:50:46 +03004382 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
4383 if (!wl->freezable_wq) {
4384 ret = -ENOMEM;
4385 goto err_hw;
4386 }
4387
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004388 wl->channel = WL1271_DEFAULT_CHANNEL;
Juuso Oikarinen60e84c22010-03-26 12:53:25 +02004389 wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004390 wl->default_key = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004391 wl->rx_counter = 0;
Juuso Oikarinen19ad0712009-11-02 20:22:11 +02004392 wl->psm_entry_retry = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004393 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinena6fe2312009-12-11 15:40:58 +02004394 wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03004395 wl->basic_rate = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004396 wl->rate_set = CONF_TX_RATE_MASK_BASIC;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03004397 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03004398 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02004399 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004400 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004401 wl->hw_pg_ver = -1;
Arik Nemtsov166d5042010-10-16 21:44:57 +02004402 wl->bss_type = MAX_BSS_TYPE;
4403 wl->set_bss_type = MAX_BSS_TYPE;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004404 wl->last_tx_hlid = 0;
Arik Nemtsovb622d992011-02-23 00:22:31 +02004405 wl->ap_ps_map = 0;
4406 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02004407 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02004408 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03004409 wl->sched_scanning = false;
Oz Krakowskib992c682011-06-26 10:36:02 +03004410 wl->tx_security_seq = 0;
4411 wl->tx_security_last_seq_lsb = 0;
Eliad Peller7f0979882011-08-14 13:17:06 +03004412 wl->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004413 wl->system_hlid = WL12XX_SYSTEM_HLID;
Eliad Peller7f0979882011-08-14 13:17:06 +03004414 wl->sta_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller04e80792011-08-14 13:17:09 +03004415 wl->dev_role_id = WL12XX_INVALID_ROLE_ID;
4416 wl->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Peller77ddaa12011-05-15 11:10:29 +03004417 setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
4418 (unsigned long) wl);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004419 wl->fwlog_size = 0;
4420 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004421
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03004422 /* The system link is always allocated */
4423 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
4424
Ido Yariv25eeb9e2010-10-12 16:20:06 +02004425 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03004426 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427 wl->tx_frames[i] = NULL;
4428
4429 spin_lock_init(&wl->wl_lock);
4430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 wl->state = WL1271_STATE_OFF;
4432 mutex_init(&wl->mutex);
4433
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004434 /* Apply default driver configuration. */
4435 wl1271_conf_init(wl);
4436
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004437 order = get_order(WL1271_AGGR_BUFFER_SIZE);
4438 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
4439 if (!wl->aggr_buf) {
4440 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03004441 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004442 }
4443
Ido Yariv990f5de2011-03-31 10:06:59 +02004444 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
4445 if (!wl->dummy_packet) {
4446 ret = -ENOMEM;
4447 goto err_aggr;
4448 }
4449
Ido Yariv95dac04f2011-06-06 14:57:06 +03004450 /* Allocate one page for the FW log */
4451 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
4452 if (!wl->fwlog) {
4453 ret = -ENOMEM;
4454 goto err_dummy_packet;
4455 }
4456
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004457 /* Register platform device */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004458 ret = platform_device_register(wl->plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004459 if (ret) {
4460 wl1271_error("couldn't register platform device");
Ido Yariv95dac04f2011-06-06 14:57:06 +03004461 goto err_fwlog;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004462 }
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004463 dev_set_drvdata(&wl->plat_dev->dev, wl);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004464
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004465 /* Create sysfs file to control bt coex state */
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004466 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004467 if (ret < 0) {
4468 wl1271_error("failed to create sysfs file bt_coex_state");
4469 goto err_platform;
4470 }
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004471
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004472 /* Create sysfs file to get HW PG version */
4473 ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4474 if (ret < 0) {
4475 wl1271_error("failed to create sysfs file hw_pg_ver");
4476 goto err_bt_coex_state;
4477 }
4478
Ido Yariv95dac04f2011-06-06 14:57:06 +03004479 /* Create sysfs file for the FW log */
4480 ret = device_create_bin_file(&wl->plat_dev->dev, &fwlog_attr);
4481 if (ret < 0) {
4482 wl1271_error("failed to create sysfs file fwlog");
4483 goto err_hw_pg_ver;
4484 }
4485
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004486 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004487
Ido Yariv95dac04f2011-06-06 14:57:06 +03004488err_hw_pg_ver:
4489 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4490
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004491err_bt_coex_state:
4492 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
4493
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004494err_platform:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004495 platform_device_unregister(wl->plat_dev);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004496
Ido Yariv95dac04f2011-06-06 14:57:06 +03004497err_fwlog:
4498 free_page((unsigned long)wl->fwlog);
4499
Ido Yariv990f5de2011-03-31 10:06:59 +02004500err_dummy_packet:
4501 dev_kfree_skb(wl->dummy_packet);
4502
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004503err_aggr:
4504 free_pages((unsigned long)wl->aggr_buf, order);
4505
Eliad Peller92ef8962011-06-07 12:50:46 +03004506err_wq:
4507 destroy_workqueue(wl->freezable_wq);
4508
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004509err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004510 wl1271_debugfs_exit(wl);
4511 kfree(plat_dev);
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004512
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004513err_plat_alloc:
4514 ieee80211_free_hw(hw);
4515
4516err_hw_alloc:
4517
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02004518 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004519}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004520EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004521
4522int wl1271_free_hw(struct wl1271 *wl)
4523{
Ido Yariv95dac04f2011-06-06 14:57:06 +03004524 /* Unblock any fwlog readers */
4525 mutex_lock(&wl->mutex);
4526 wl->fwlog_size = -1;
4527 wake_up_interruptible_all(&wl->fwlog_waitq);
4528 mutex_unlock(&wl->mutex);
4529
4530 device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03004531
4532 device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
4533
4534 device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004535 platform_device_unregister(wl->plat_dev);
Ido Yariv95dac04f2011-06-06 14:57:06 +03004536 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02004537 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02004538 free_pages((unsigned long)wl->aggr_buf,
4539 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004540 kfree(wl->plat_dev);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004541
4542 wl1271_debugfs_exit(wl);
4543
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004544 vfree(wl->fw);
4545 wl->fw = NULL;
4546 kfree(wl->nvs);
4547 wl->nvs = NULL;
4548
4549 kfree(wl->fw_status);
4550 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03004551 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02004552
4553 ieee80211_free_hw(wl->hw);
4554
4555 return 0;
4556}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004557EXPORT_SYMBOL_GPL(wl1271_free_hw);
4558
Guy Eilam491bbd62011-01-12 10:33:29 +01004559u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02004560EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01004561module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02004562MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
4563
Ido Yariv95dac04f2011-06-06 14:57:06 +03004564module_param_named(fwlog, fwlog_param, charp, 0);
4565MODULE_PARM_DESC(keymap,
4566 "FW logger options: continuous, ondemand, dbgpins or disable");
4567
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004568MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02004569MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02004570MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");