blob: 10c1ecdf9bab23250263c200c3c09716b7bb5b6a [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
3 * This file is part of wl1271
4 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03006 *
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/firmware.h>
27#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
29#include <linux/crc32.h>
30#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030031#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020034#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030035#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030036#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030039#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030040#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000041#include "reg.h"
42#include "io.h"
43#include "event.h"
44#include "tx.h"
45#include "rx.h"
46#include "ps.h"
47#include "init.h"
48#include "debugfs.h"
49#include "cmd.h"
50#include "boot.h"
51#include "testmode.h"
52#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030053
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020054#define WL1271_BOOT_RETRIES 3
55
Juuso Oikarinen8a080482009-10-13 12:47:44 +030056static struct conf_drv_settings default_conf = {
57 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030058 .params = {
59 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
62 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
63 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
65 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
66 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
67 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
69 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
70 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
76 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
78 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
80 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
83 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
84 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
85 /* active scan params */
86 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
88 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
89 /* passive scan params */
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
92 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
93 /* passive scan in dual antenna params */
94 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
96 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
97 /* general params */
98 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
99 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
100 [CONF_SG_BEACON_MISS_PERCENT] = 60,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_RXT] = 1200,
103 [CONF_SG_TXT] = 1000,
104 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
105 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
106 [CONF_SG_HV3_MAX_SERVED] = 6,
107 [CONF_SG_PS_POLL_TIMEOUT] = 10,
108 [CONF_SG_UPSD_TIMEOUT] = 10,
109 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
110 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
111 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
112 /* AP params */
113 [CONF_AP_BEACON_MISS_TX] = 3,
114 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
115 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
116 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
117 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
118 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Eliad Peller26612c42012-01-31 17:54:43 +0200119 /* CTS Diluting params */
120 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
121 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300122 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200123 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .rx = {
126 .rx_msdu_life_time = 512000,
127 .packet_detection_threshold = 0,
128 .ps_poll_timeout = 15,
129 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300130 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200131 .rx_cca_threshold = 0,
132 .irq_blk_threshold = 0xFFFF,
133 .irq_pkt_threshold = 0,
134 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
136 },
137 .tx = {
138 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300140 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300141 .short_retry_limit = 10,
142 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200143 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 },
145 .ac_conf_count = 4,
146 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200147 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300148 .ac = CONF_TX_AC_BE,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = 3,
152 .tx_op_limit = 0,
153 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200154 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300155 .ac = CONF_TX_AC_BK,
156 .cw_min = 15,
157 .cw_max = 63,
158 .aifsn = 7,
159 .tx_op_limit = 0,
160 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200161 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300162 .ac = CONF_TX_AC_VI,
163 .cw_min = 15,
164 .cw_max = 63,
165 .aifsn = CONF_TX_AIFS_PIFS,
166 .tx_op_limit = 3008,
167 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200168 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300169 .ac = CONF_TX_AC_VO,
170 .cw_min = 15,
171 .cw_max = 63,
172 .aifsn = CONF_TX_AIFS_PIFS,
173 .tx_op_limit = 1504,
174 },
175 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300176 .max_tx_retries = 100,
177 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200178 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200180 [CONF_TX_AC_BE] = {
181 .queue_id = CONF_TX_AC_BE,
182 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300183 .tsid = CONF_TX_AC_BE,
184 .ps_scheme = CONF_PS_SCHEME_LEGACY,
185 .ack_policy = CONF_ACK_POLICY_LEGACY,
186 .apsd_conf = {0, 0},
187 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200188 [CONF_TX_AC_BK] = {
189 .queue_id = CONF_TX_AC_BK,
190 .channel_type = CONF_CHANNEL_TYPE_EDCF,
191 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ps_scheme = CONF_PS_SCHEME_LEGACY,
193 .ack_policy = CONF_ACK_POLICY_LEGACY,
194 .apsd_conf = {0, 0},
195 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200196 [CONF_TX_AC_VI] = {
197 .queue_id = CONF_TX_AC_VI,
198 .channel_type = CONF_CHANNEL_TYPE_EDCF,
199 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .ps_scheme = CONF_PS_SCHEME_LEGACY,
201 .ack_policy = CONF_ACK_POLICY_LEGACY,
202 .apsd_conf = {0, 0},
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
205 .queue_id = CONF_TX_AC_VO,
206 .channel_type = CONF_CHANNEL_TYPE_EDCF,
207 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 .ps_scheme = CONF_PS_SCHEME_LEGACY,
209 .ack_policy = CONF_ACK_POLICY_LEGACY,
210 .apsd_conf = {0, 0},
211 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300212 },
213 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200214 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300215 .tx_compl_threshold = 4,
216 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
217 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200218 .tmpl_short_retry_limit = 10,
219 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Eyal Shapiradae728f2012-02-02 12:03:39 +0200224 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
225 .suspend_listen_interval = 3,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300227 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 .bcn_filt_ie = {
229 [0] = {
230 .ie = WLAN_EID_CHANNEL_SWITCH,
231 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300232 },
233 [1] = {
234 .ie = WLAN_EID_HT_INFORMATION,
235 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
236 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200238 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 .bss_lose_timeout = 100,
240 .beacon_rx_timeout = 10000,
241 .broadcast_timeout = 20000,
242 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300243 .ps_poll_threshold = 10,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300244 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200245 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300246 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300247 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200248 .psm_entry_nullfunc_retries = 3,
Eyal Shapiraf1d63a52012-01-31 11:57:21 +0200249 .dynamic_ps_timeout = 100,
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +0200250 .forced_ps = false,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300251 .keep_alive_interval = 55000,
252 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200254 .itrim = {
255 .enable = false,
256 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200257 },
258 .pm_config = {
259 .host_clk_settling_time = 5000,
260 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300261 },
262 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300263 .trigger_pacing = 1,
264 .avg_weight_rssi_beacon = 20,
265 .avg_weight_rssi_data = 10,
266 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100267 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200268 },
269 .scan = {
270 .min_dwell_time_active = 7500,
271 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100272 .min_dwell_time_passive = 100000,
273 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200274 .num_probe_reqs = 2,
Eyal Shapirad647f2d2012-02-02 13:54:28 +0200275 .split_scan_timeout = 50000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200276 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300277 .sched_scan = {
278 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300279 .min_dwell_time_active = 30,
280 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300281 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300282 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300283 .num_probe_reqs = 2,
284 .rssi_threshold = -90,
285 .snr_threshold = 0,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300298 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100299 .tx_ba_win_size = 64,
300 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300301 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100302 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 70,
307 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300308 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200309 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200312 },
313 .mem_wl128x = {
314 .num_stations = 1,
315 .ssid_profiles = 1,
316 .rx_block_num = 40,
317 .tx_min_block_num = 40,
318 .dynamic_memory = 1,
319 .min_req_tx_blocks = 45,
320 .min_req_rx_blocks = 22,
321 .tx_min = 27,
322 },
Shahar Leviff868432011-04-11 15:41:46 +0300323 .fm_coex = {
324 .enable = true,
325 .swallow_period = 5,
326 .n_divider_fref_set_1 = 0xff, /* default */
327 .n_divider_fref_set_2 = 12,
328 .m_divider_fref_set_1 = 148,
329 .m_divider_fref_set_2 = 0xffff, /* default */
330 .coex_pll_stabilization_time = 0xffffffff, /* default */
331 .ldo_stabilization_time = 0xffff, /* default */
332 .fm_disturbed_band_margin = 0xff, /* default */
333 .swallow_clk_diff = 0xff, /* default */
334 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300335 .rx_streaming = {
336 .duration = 150,
337 .queues = 0x1,
338 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300339 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300340 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300341 .fwlog = {
342 .mode = WL12XX_FWLOG_ON_DEMAND,
343 .mem_blocks = 2,
344 .severity = 0,
345 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
346 .output = WL12XX_FWLOG_OUTPUT_HOST,
347 .threshold = 0,
348 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300349 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300350 .rate = {
351 .rate_retry_score = 32000,
352 .per_add = 8192,
353 .per_th1 = 2048,
354 .per_th2 = 4096,
355 .max_per = 8100,
356 .inverse_curiosity_factor = 5,
357 .tx_fail_low_th = 4,
358 .tx_fail_high_th = 10,
359 .per_alpha_shift = 4,
360 .per_add_shift = 13,
361 .per_beta1_shift = 10,
362 .per_beta2_shift = 8,
363 .rate_check_up = 2,
364 .rate_check_down = 12,
365 .rate_retry_policy = {
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00,
369 },
370 },
Eliad Peller94877752011-08-28 15:11:56 +0300371 .hangover = {
372 .recover_time = 0,
373 .hangover_period = 20,
374 .dynamic_mode = 1,
375 .early_termination_mode = 1,
376 .max_period = 20,
377 .min_period = 1,
378 .increase_delta = 1,
379 .decrease_delta = 2,
380 .quiet_time = 4,
381 .increase_time = 1,
382 .window_size = 16,
383 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300384};
385
Ido Yariv95dac04f2011-06-06 14:57:06 +0300386static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300387static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300388
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300389static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200390 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300391 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200392static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200393static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200394
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200395static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300396static LIST_HEAD(wl_list);
397
Eliad Pellerba8447f2011-10-10 10:13:00 +0200398static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
399 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300400{
401 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200402
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300403 if (operstate != IF_OPER_UP)
404 return 0;
405
Eliad Peller8181aec2011-10-10 10:13:04 +0200406 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 return 0;
408
Eliad Peller154da672011-10-05 11:55:53 +0200409 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300410 if (ret < 0)
411 return ret;
412
Eliad Peller0603d892011-10-05 11:55:51 +0200413 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300414
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300415 wl1271_info("Association completed.");
416 return 0;
417}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300418static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
419 void *arg)
420{
421 struct net_device *dev = arg;
422 struct wireless_dev *wdev;
423 struct wiphy *wiphy;
424 struct ieee80211_hw *hw;
425 struct wl1271 *wl;
426 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200427 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300428 int ret = 0;
429
430 /* Check that this notification is for us. */
431 if (what != NETDEV_CHANGE)
432 return NOTIFY_DONE;
433
434 wdev = dev->ieee80211_ptr;
435 if (wdev == NULL)
436 return NOTIFY_DONE;
437
438 wiphy = wdev->wiphy;
439 if (wiphy == NULL)
440 return NOTIFY_DONE;
441
442 hw = wiphy_priv(wiphy);
443 if (hw == NULL)
444 return NOTIFY_DONE;
445
446 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200447 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300448 list_for_each_entry(wl, &wl_list, list) {
449 if (wl == wl_temp)
450 break;
451 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200452 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 if (wl != wl_temp)
454 return NOTIFY_DONE;
455
456 mutex_lock(&wl->mutex);
457
458 if (wl->state == WL1271_STATE_OFF)
459 goto out;
460
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 if (dev->operstate != IF_OPER_UP)
462 goto out;
463 /*
464 * The correct behavior should be just getting the appropriate wlvif
465 * from the given dev, but currently we don't have a mac80211
466 * interface for it.
467 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200468 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200469 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
470
Eliad Pellerba8447f2011-10-10 10:13:00 +0200471 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
472 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300473
Eliad Pellerba8447f2011-10-10 10:13:00 +0200474 ret = wl1271_ps_elp_wakeup(wl);
475 if (ret < 0)
476 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477
Eliad Peller6ab70912011-12-18 20:25:45 +0200478 wl1271_check_operstate(wl, wlvif,
479 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300480
Eliad Pellerba8447f2011-10-10 10:13:00 +0200481 wl1271_ps_elp_sleep(wl);
482 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300483out:
484 mutex_unlock(&wl->mutex);
485
486 return NOTIFY_OK;
487}
488
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100489static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200490 struct regulatory_request *request)
491{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100492 struct ieee80211_supported_band *band;
493 struct ieee80211_channel *ch;
494 int i;
495
496 band = wiphy->bands[IEEE80211_BAND_5GHZ];
497 for (i = 0; i < band->n_channels; i++) {
498 ch = &band->channels[i];
499 if (ch->flags & IEEE80211_CHAN_DISABLED)
500 continue;
501
502 if (ch->flags & IEEE80211_CHAN_RADAR)
503 ch->flags |= IEEE80211_CHAN_NO_IBSS |
504 IEEE80211_CHAN_PASSIVE_SCAN;
505
506 }
507
508 return 0;
509}
510
Eliad Peller9eb599e2011-10-10 10:12:59 +0200511static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
512 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300513{
514 int ret = 0;
515
516 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200517 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300518 if (ret < 0)
519 goto out;
520
521 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200522 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300523 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200524 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300525out:
526 return ret;
527}
528
529/*
530 * this function is being called when the rx_streaming interval
531 * has beed changed or rx_streaming should be disabled
532 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534{
535 int ret = 0;
536 int period = wl->conf.rx_streaming.interval;
537
538 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200539 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 goto out;
541
542 /* reconfigure/disable according to new streaming_period */
543 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200544 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545 (wl->conf.rx_streaming.always ||
546 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200547 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300548 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200549 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200551 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300552 }
553out:
554 return ret;
555}
556
557static void wl1271_rx_streaming_enable_work(struct work_struct *work)
558{
559 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200560 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
561 rx_streaming_enable_work);
562 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300563
564 mutex_lock(&wl->mutex);
565
Eliad Peller0744bdb2011-10-10 10:13:05 +0200566 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200567 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300568 (!wl->conf.rx_streaming.always &&
569 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
570 goto out;
571
572 if (!wl->conf.rx_streaming.interval)
573 goto out;
574
575 ret = wl1271_ps_elp_wakeup(wl);
576 if (ret < 0)
577 goto out;
578
Eliad Peller9eb599e2011-10-10 10:12:59 +0200579 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300580 if (ret < 0)
581 goto out_sleep;
582
583 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200584 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
586
587out_sleep:
588 wl1271_ps_elp_sleep(wl);
589out:
590 mutex_unlock(&wl->mutex);
591}
592
593static void wl1271_rx_streaming_disable_work(struct work_struct *work)
594{
595 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200596 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
597 rx_streaming_disable_work);
598 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300599
600 mutex_lock(&wl->mutex);
601
Eliad Peller0744bdb2011-10-10 10:13:05 +0200602 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300603 goto out;
604
605 ret = wl1271_ps_elp_wakeup(wl);
606 if (ret < 0)
607 goto out;
608
Eliad Peller9eb599e2011-10-10 10:12:59 +0200609 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300610 if (ret)
611 goto out_sleep;
612
613out_sleep:
614 wl1271_ps_elp_sleep(wl);
615out:
616 mutex_unlock(&wl->mutex);
617}
618
619static void wl1271_rx_streaming_timer(unsigned long data)
620{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200621 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
622 struct wl1271 *wl = wlvif->wl;
623 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300624}
625
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300626static void wl1271_conf_init(struct wl1271 *wl)
627{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300628
629 /*
630 * This function applies the default configuration to the driver. This
631 * function is invoked upon driver load (spi probe.)
632 *
633 * The configuration is stored in a run-time structure in order to
634 * facilitate for run-time adjustment of any of the parameters. Making
635 * changes to the configuration structure will apply the new values on
636 * the next interface up (wl1271_op_start.)
637 */
638
639 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300640 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Ido Yariv95dac04f2011-06-06 14:57:06 +0300642 /* Adjust settings according to optional module parameters */
643 if (fwlog_param) {
644 if (!strcmp(fwlog_param, "continuous")) {
645 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
646 } else if (!strcmp(fwlog_param, "ondemand")) {
647 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
648 } else if (!strcmp(fwlog_param, "dbgpins")) {
649 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
650 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
651 } else if (!strcmp(fwlog_param, "disable")) {
652 wl->conf.fwlog.mem_blocks = 0;
653 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
654 } else {
655 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
656 }
657 }
658}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660static int wl1271_plt_init(struct wl1271 *wl)
661{
Eliad Peller188e7f52011-12-06 12:15:06 +0200662 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663
Shahar Levi49d750ca2011-03-06 16:32:09 +0200664 if (wl->chip.id == CHIP_ID_1283_PG20)
665 ret = wl128x_cmd_general_parms(wl);
666 else
667 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200668 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200669 return ret;
670
Shahar Levi49d750ca2011-03-06 16:32:09 +0200671 if (wl->chip.id == CHIP_ID_1283_PG20)
672 ret = wl128x_cmd_radio_parms(wl);
673 else
674 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200675 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200676 return ret;
677
Shahar Levi49d750ca2011-03-06 16:32:09 +0200678 if (wl->chip.id != CHIP_ID_1283_PG20) {
679 ret = wl1271_cmd_ext_radio_parms(wl);
680 if (ret < 0)
681 return ret;
682 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200683 if (ret < 0)
684 return ret;
685
Shahar Levi48a61472011-03-06 16:32:08 +0200686 /* Chip-specific initializations */
687 ret = wl1271_chip_specific_init(wl);
688 if (ret < 0)
689 return ret;
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = wl1271_acx_init_mem_config(wl);
692 if (ret < 0)
693 return ret;
694
Eliad Peller7f0979882011-08-14 13:17:06 +0300695 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600696 if (ret < 0)
697 goto out_free_memmap;
698
Luciano Coelho12419cc2010-02-18 13:25:44 +0200699 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200700 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200702 goto out_free_memmap;
703
704 /* Configure for CAM power saving (ie. always active) */
705 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
706 if (ret < 0)
707 goto out_free_memmap;
708
709 /* configure PM */
710 ret = wl1271_acx_pm_config(wl);
711 if (ret < 0)
712 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713
714 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715
716 out_free_memmap:
717 kfree(wl->target_mem_map);
718 wl->target_mem_map = NULL;
719
720 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721}
722
Eliad Peller6e8cd332011-10-10 10:13:13 +0200723static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
724 struct wl12xx_vif *wlvif,
725 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200726{
Arik Nemtsovda032092011-08-25 12:43:15 +0300727 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728
Arik Nemtsovb622d992011-02-23 00:22:31 +0200729 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300730 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200731
732 /*
733 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300734 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200735 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300736 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738
Arik Nemtsovda032092011-08-25 12:43:15 +0300739 /*
740 * Start high-level PS if the STA is asleep with enough blocks in FW.
741 * Make an exception if this is the only connected station. In this
742 * case FW-memory congestion is not a problem.
743 */
744 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200745 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200746}
747
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300748static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200749 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300750 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200751{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200752 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200753 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300754 u8 hlid, cnt;
755
756 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200757
758 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
759 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
760 wl1271_debug(DEBUG_PSM,
761 "link ps prev 0x%x cur 0x%x changed 0x%x",
762 wl->ap_fw_ps_map, cur_fw_ps_map,
763 wl->ap_fw_ps_map ^ cur_fw_ps_map);
764
765 wl->ap_fw_ps_map = cur_fw_ps_map;
766 }
767
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200768 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
769 lnk = &wl->links[hlid];
770 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200771
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200772 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
773 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
776 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777 }
778}
779
Eliad Peller4d56ad92011-08-14 13:17:05 +0300780static void wl12xx_fw_status(struct wl1271 *wl,
781 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200784 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200785 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300786 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300787 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Eliad Peller4d56ad92011-08-14 13:17:05 +0300789 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
792 "drv_rx_counter = %d, tx_results_counter = %d)",
793 status->intr,
794 status->fw_rx_counter,
795 status->drv_rx_counter,
796 status->tx_results_counter);
797
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300798 for (i = 0; i < NUM_TX_QUEUES; i++) {
799 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300800 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300801 (status->tx_released_pkts[i] -
802 wl->tx_pkts_freed[i]) & 0xff;
803
804 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
805 }
806
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300807 /* prevent wrap-around in total blocks counter */
808 if (likely(wl->tx_blocks_freed <=
809 le32_to_cpu(status->total_released_blks)))
810 freed_blocks = le32_to_cpu(status->total_released_blks) -
811 wl->tx_blocks_freed;
812 else
813 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
814 le32_to_cpu(status->total_released_blks);
815
Eliad Peller4d56ad92011-08-14 13:17:05 +0300816 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200817
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300818 wl->tx_allocated_blocks -= freed_blocks;
819
Eliad Peller4d56ad92011-08-14 13:17:05 +0300820 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200821
Eliad Peller4d56ad92011-08-14 13:17:05 +0300822 /*
823 * The FW might change the total number of TX memblocks before
824 * we get a notification about blocks being released. Thus, the
825 * available blocks calculation might yield a temporary result
826 * which is lower than the actual available blocks. Keeping in
827 * mind that only blocks that were allocated can be moved from
828 * TX to RX, tx_blocks_available should never decrease here.
829 */
830 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
831 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
Ido Yariva5225502010-10-12 14:49:10 +0200833 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200834 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200835 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
Eliad Peller4d56ad92011-08-14 13:17:05 +0300837 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200838 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200839 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200840 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200843 getnstimeofday(&ts);
844 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
845 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846}
847
Ido Yariva6208652011-03-01 15:14:41 +0200848static void wl1271_flush_deferred_work(struct wl1271 *wl)
849{
850 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200851
Ido Yariva6208652011-03-01 15:14:41 +0200852 /* Pass all received frames to the network stack */
853 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
854 ieee80211_rx_ni(wl->hw, skb);
855
856 /* Return sent skbs to the network stack */
857 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300858 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200859}
860
861static void wl1271_netstack_work(struct work_struct *work)
862{
863 struct wl1271 *wl =
864 container_of(work, struct wl1271, netstack_work);
865
866 do {
867 wl1271_flush_deferred_work(wl);
868 } while (skb_queue_len(&wl->deferred_rx_queue));
869}
870
871#define WL1271_IRQ_MAX_LOOPS 256
872
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300873static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300875 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300876 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200877 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200878 struct wl1271 *wl = (struct wl1271 *)cookie;
879 bool done = false;
880 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200881 unsigned long flags;
882
883 /* TX might be handled here, avoid redundant work */
884 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
885 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886
Ido Yariv341b7cd2011-03-31 10:07:01 +0200887 /*
888 * In case edge triggered interrupt must be used, we cannot iterate
889 * more than once without introducing race conditions with the hardirq.
890 */
891 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
892 loopcount = 1;
893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 mutex_lock(&wl->mutex);
895
896 wl1271_debug(DEBUG_IRQ, "IRQ work");
897
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200898 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 goto out;
900
Ido Yariva6208652011-03-01 15:14:41 +0200901 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 if (ret < 0)
903 goto out;
904
Ido Yariva6208652011-03-01 15:14:41 +0200905 while (!done && loopcount--) {
906 /*
907 * In order to avoid a race with the hardirq, clear the flag
908 * before acknowledging the chip. Since the mutex is held,
909 * wl1271_ps_elp_wakeup cannot be called concurrently.
910 */
911 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
912 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Eliad Peller4d56ad92011-08-14 13:17:05 +0300914 wl12xx_fw_status(wl, wl->fw_status);
915 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200916 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200917 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200918 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200919 continue;
920 }
921
Eliad Pellerccc83b02010-10-27 14:09:57 +0200922 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
923 wl1271_error("watchdog interrupt received! "
924 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300925 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200926
927 /* restarting the chip. ignore any other interrupt. */
928 goto out;
929 }
930
Ido Yariva6208652011-03-01 15:14:41 +0200931 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200932 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
933
Eliad Peller4d56ad92011-08-14 13:17:05 +0300934 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200935
Ido Yariva5225502010-10-12 14:49:10 +0200936 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200938 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300939 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200941 /*
942 * In order to avoid starvation of the TX path,
943 * call the work function directly.
944 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200945 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200946 } else {
947 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200948 }
949
Ido Yariv8aad2462011-03-01 15:14:38 +0200950 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300951 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200952 (wl->tx_results_count & 0xff))
953 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200954
955 /* Make sure the deferred queues don't get too long */
956 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
957 skb_queue_len(&wl->deferred_rx_queue);
958 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
959 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 }
961
962 if (intr & WL1271_ACX_INTR_EVENT_A) {
963 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
964 wl1271_event_handle(wl, 0);
965 }
966
967 if (intr & WL1271_ACX_INTR_EVENT_B) {
968 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
969 wl1271_event_handle(wl, 1);
970 }
971
972 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
973 wl1271_debug(DEBUG_IRQ,
974 "WL1271_ACX_INTR_INIT_COMPLETE");
975
976 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
977 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 }
979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl1271_ps_elp_sleep(wl);
981
982out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
984 /* In case TX was not handled here, queue TX work */
985 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
986 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300987 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200988 ieee80211_queue_work(wl->hw, &wl->tx_work);
989 spin_unlock_irqrestore(&wl->wl_lock, flags);
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200992
993 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994}
995
Eliad Peller4549d092012-02-06 13:07:52 +0200996struct vif_counter_data {
997 u8 counter;
998
999 struct ieee80211_vif *cur_vif;
1000 bool cur_vif_running;
1001};
1002
1003static void wl12xx_vif_count_iter(void *data, u8 *mac,
1004 struct ieee80211_vif *vif)
1005{
1006 struct vif_counter_data *counter = data;
1007
1008 counter->counter++;
1009 if (counter->cur_vif == vif)
1010 counter->cur_vif_running = true;
1011}
1012
1013/* caller must not hold wl->mutex, as it might deadlock */
1014static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
1015 struct ieee80211_vif *cur_vif,
1016 struct vif_counter_data *data)
1017{
1018 memset(data, 0, sizeof(*data));
1019 data->cur_vif = cur_vif;
1020
1021 ieee80211_iterate_active_interfaces(hw,
1022 wl12xx_vif_count_iter, data);
1023}
1024
Eliad Peller3fcdab72012-02-06 12:47:54 +02001025static int wl12xx_fetch_firmware(struct wl1271 *wl, bool plt)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026{
1027 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001028 const char *fw_name;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001029 enum wl12xx_fw_type fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001030 int ret;
1031
Eliad Peller3fcdab72012-02-06 12:47:54 +02001032 if (plt) {
1033 fw_type = WL12XX_FW_TYPE_PLT;
1034 if (wl->chip.id == CHIP_ID_1283_PG20)
1035 fw_name = WL128X_PLT_FW_NAME;
1036 else
1037 fw_name = WL127X_PLT_FW_NAME;
1038 } else {
Eliad Peller4549d092012-02-06 13:07:52 +02001039 /*
1040 * we can't call wl12xx_get_vif_count() here because
1041 * wl->mutex is taken, so use the cached last_vif_count value
1042 */
1043 if (wl->last_vif_count > 1) {
1044 fw_type = WL12XX_FW_TYPE_MULTI;
1045 if (wl->chip.id == CHIP_ID_1283_PG20)
1046 fw_name = WL128X_FW_NAME_MULTI;
1047 else
1048 fw_name = WL127X_FW_NAME_MULTI;
1049 } else {
1050 fw_type = WL12XX_FW_TYPE_NORMAL;
1051 if (wl->chip.id == CHIP_ID_1283_PG20)
1052 fw_name = WL128X_FW_NAME_SINGLE;
1053 else
1054 fw_name = WL127X_FW_NAME_SINGLE;
1055 }
Eliad Peller3fcdab72012-02-06 12:47:54 +02001056 }
1057
1058 if (wl->fw_type == fw_type)
1059 return 0;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001060
1061 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1062
Felipe Balbia390e852011-10-06 10:07:44 +03001063 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064
1065 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001066 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001067 return ret;
1068 }
1069
1070 if (fw->size % 4) {
1071 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1072 fw->size);
1073 ret = -EILSEQ;
1074 goto out;
1075 }
1076
Arik Nemtsov166d5042010-10-16 21:44:57 +02001077 vfree(wl->fw);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001078 wl->fw_type = WL12XX_FW_TYPE_NONE;
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;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001090 wl->fw_type = fw_type;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001091out:
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
Felipe Balbia390e852011-10-06 10:07:44 +03001102 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001103
1104 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001105 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1106 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001107 return ret;
1108 }
1109
Shahar Levibc765bf2011-03-06 16:32:10 +02001110 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001111
1112 if (!wl->nvs) {
1113 wl1271_error("could not allocate memory for the nvs file");
1114 ret = -ENOMEM;
1115 goto out;
1116 }
1117
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001118 wl->nvs_len = fw->size;
1119
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001120out:
1121 release_firmware(fw);
1122
1123 return ret;
1124}
1125
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001126void wl12xx_queue_recovery_work(struct wl1271 *wl)
1127{
1128 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1129 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1130}
1131
Ido Yariv95dac04f2011-06-06 14:57:06 +03001132size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1133{
1134 size_t len = 0;
1135
1136 /* The FW log is a length-value list, find where the log end */
1137 while (len < maxlen) {
1138 if (memblock[len] == 0)
1139 break;
1140 if (len + memblock[len] + 1 > maxlen)
1141 break;
1142 len += memblock[len] + 1;
1143 }
1144
1145 /* Make sure we have enough room */
1146 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1147
1148 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1149 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1150 wl->fwlog_size += len;
1151
1152 return len;
1153}
1154
1155static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1156{
1157 u32 addr;
1158 u32 first_addr;
1159 u8 *block;
1160
1161 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1162 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1163 (wl->conf.fwlog.mem_blocks == 0))
1164 return;
1165
1166 wl1271_info("Reading FW panic log");
1167
1168 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1169 if (!block)
1170 return;
1171
1172 /*
1173 * Make sure the chip is awake and the logger isn't active.
1174 * This might fail if the firmware hanged.
1175 */
1176 if (!wl1271_ps_elp_wakeup(wl))
1177 wl12xx_cmd_stop_fwlog(wl);
1178
1179 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001180 wl12xx_fw_status(wl, wl->fw_status);
1181 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001182 if (!first_addr)
1183 goto out;
1184
1185 /* Traverse the memory blocks linked list */
1186 addr = first_addr;
1187 do {
1188 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1189 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1190 false);
1191
1192 /*
1193 * Memory blocks are linked to one another. The first 4 bytes
1194 * of each memory block hold the hardware address of the next
1195 * one. The last memory block points to the first one.
1196 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001197 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001198 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1199 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1200 break;
1201 } while (addr && (addr != first_addr));
1202
1203 wake_up_interruptible(&wl->fwlog_waitq);
1204
1205out:
1206 kfree(block);
1207}
1208
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209static void wl1271_recovery_work(struct work_struct *work)
1210{
1211 struct wl1271 *wl =
1212 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001213 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001214 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001215
1216 mutex_lock(&wl->mutex);
1217
Eliad Peller3fcdab72012-02-06 12:47:54 +02001218 if (wl->state != WL1271_STATE_ON || wl->plt)
Eliad Pellerf0277432011-10-10 10:13:14 +02001219 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001220
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001221 /* Avoid a recursive recovery */
1222 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1223
Ido Yariv95dac04f2011-06-06 14:57:06 +03001224 wl12xx_read_fwlog_panic(wl);
1225
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001226 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1227 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001228
Eliad Peller2a5bff02011-08-25 18:10:59 +03001229 BUG_ON(bug_on_recovery);
1230
Oz Krakowskib992c682011-06-26 10:36:02 +03001231 /*
1232 * Advance security sequence number to overcome potential progress
1233 * in the firmware during recovery. This doens't hurt if the network is
1234 * not encrypted.
1235 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001236 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001237 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001238 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001239 wlvif->tx_security_seq +=
1240 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1241 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001242
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001243 /* Prevent spurious TX during FW restart */
1244 ieee80211_stop_queues(wl->hw);
1245
Luciano Coelho33c2c062011-05-10 14:46:02 +03001246 if (wl->sched_scanning) {
1247 ieee80211_sched_scan_stopped(wl->hw);
1248 wl->sched_scanning = false;
1249 }
1250
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001251 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001252 while (!list_empty(&wl->wlvif_list)) {
1253 wlvif = list_first_entry(&wl->wlvif_list,
1254 struct wl12xx_vif, list);
1255 vif = wl12xx_wlvif_to_vif(wlvif);
1256 __wl1271_op_remove_interface(wl, vif, false);
1257 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001258 mutex_unlock(&wl->mutex);
1259 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001260
1261 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1262
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001263 ieee80211_restart_hw(wl->hw);
1264
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001265 /*
1266 * Its safe to enable TX now - the queues are stopped after a request
1267 * to restart the HW.
1268 */
1269 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001270 return;
1271out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001272 mutex_unlock(&wl->mutex);
1273}
1274
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001275static void wl1271_fw_wakeup(struct wl1271 *wl)
1276{
1277 u32 elp_reg;
1278
1279 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001280 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281}
1282
1283static int wl1271_setup(struct wl1271 *wl)
1284{
1285 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1286 if (!wl->fw_status)
1287 return -ENOMEM;
1288
1289 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1290 if (!wl->tx_res_if) {
1291 kfree(wl->fw_status);
1292 return -ENOMEM;
1293 }
1294
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001295 return 0;
1296}
1297
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001298static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001299{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001300 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001302 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001303 ret = wl1271_power_on(wl);
1304 if (ret < 0)
1305 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001306 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001307 wl1271_io_reset(wl);
1308 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001310 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311
1312 /* ELP module wake up */
1313 wl1271_fw_wakeup(wl);
1314
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001315out:
1316 return ret;
1317}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318
Eliad Peller3fcdab72012-02-06 12:47:54 +02001319static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt)
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001320{
1321 int ret = 0;
1322
1323 ret = wl12xx_set_power_on(wl);
1324 if (ret < 0)
1325 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001326
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001327 /*
1328 * For wl127x based devices we could use the default block
1329 * size (512 bytes), but due to a bug in the sdio driver, we
1330 * need to set it explicitly after the chip is powered on. To
1331 * simplify the code and since the performance impact is
1332 * negligible, we use the same block size for all different
1333 * chip types.
1334 */
1335 if (!wl1271_set_block_size(wl))
1336 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001337
1338 switch (wl->chip.id) {
1339 case CHIP_ID_1271_PG10:
1340 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1341 wl->chip.id);
1342
1343 ret = wl1271_setup(wl);
1344 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001346 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001347 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001348
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001349 case CHIP_ID_1271_PG20:
1350 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1351 wl->chip.id);
1352
1353 ret = wl1271_setup(wl);
1354 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001355 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001356 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001358
Shahar Levi0830cee2011-03-06 16:32:20 +02001359 case CHIP_ID_1283_PG20:
1360 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1361 wl->chip.id);
1362
1363 ret = wl1271_setup(wl);
1364 if (ret < 0)
1365 goto out;
1366 break;
1367 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001369 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001370 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001372 }
1373
Eliad Peller3fcdab72012-02-06 12:47:54 +02001374 ret = wl12xx_fetch_firmware(wl, plt);
1375 if (ret < 0)
1376 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001377
1378 /* No NVS from netlink, try to get it from the filesystem */
1379 if (wl->nvs == NULL) {
1380 ret = wl1271_fetch_nvs(wl);
1381 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001382 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001383 }
1384
1385out:
1386 return ret;
1387}
1388
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389int wl1271_plt_start(struct wl1271 *wl)
1390{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001391 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001392 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393 int ret;
1394
1395 mutex_lock(&wl->mutex);
1396
1397 wl1271_notice("power up");
1398
1399 if (wl->state != WL1271_STATE_OFF) {
1400 wl1271_error("cannot go into PLT state because not "
1401 "in off state: %d", wl->state);
1402 ret = -EBUSY;
1403 goto out;
1404 }
1405
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001406 while (retries) {
1407 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001408 ret = wl12xx_chip_wakeup(wl, true);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001409 if (ret < 0)
1410 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001411
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001412 ret = wl1271_boot(wl);
1413 if (ret < 0)
1414 goto power_off;
1415
1416 ret = wl1271_plt_init(wl);
1417 if (ret < 0)
1418 goto irq_disable;
1419
Eliad Peller3fcdab72012-02-06 12:47:54 +02001420 wl->plt = true;
1421 wl->state = WL1271_STATE_ON;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001422 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001423 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001424
Gery Kahn6f07b722011-07-18 14:21:49 +03001425 /* update hw/fw version info in wiphy struct */
1426 wiphy->hw_version = wl->chip.id;
1427 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1428 sizeof(wiphy->fw_version));
1429
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430 goto out;
1431
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001432irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001433 mutex_unlock(&wl->mutex);
1434 /* Unlocking the mutex in the middle of handling is
1435 inherently unsafe. In this case we deem it safe to do,
1436 because we need to let any possibly pending IRQ out of
1437 the system (and while we are WL1271_STATE_OFF the IRQ
1438 work function will not do anything.) Also, any other
1439 possible concurrent operations will fail due to the
1440 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001441 wl1271_disable_interrupts(wl);
1442 wl1271_flush_deferred_work(wl);
1443 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001444 mutex_lock(&wl->mutex);
1445power_off:
1446 wl1271_power_off(wl);
1447 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001448
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001449 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1450 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451out:
1452 mutex_unlock(&wl->mutex);
1453
1454 return ret;
1455}
1456
Ido Yarivf3df1332012-01-11 09:42:39 +02001457int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458{
1459 int ret = 0;
1460
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001461 wl1271_notice("power down");
1462
Ido Yariv46b0cc92012-01-11 09:42:41 +02001463 /*
1464 * Interrupts must be disabled before setting the state to OFF.
1465 * Otherwise, the interrupt handler might be called and exit without
1466 * reading the interrupt status.
1467 */
1468 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001469 mutex_lock(&wl->mutex);
Eliad Peller3fcdab72012-02-06 12:47:54 +02001470 if (!wl->plt) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001471 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001472
1473 /*
1474 * This will not necessarily enable interrupts as interrupts
1475 * may have been disabled when op_stop was called. It will,
1476 * however, balance the above call to disable_interrupts().
1477 */
1478 wl1271_enable_interrupts(wl);
1479
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001480 wl1271_error("cannot power down because not in PLT "
1481 "state: %d", wl->state);
1482 ret = -EBUSY;
1483 goto out;
1484 }
1485
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001486 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001487
Ido Yariva6208652011-03-01 15:14:41 +02001488 wl1271_flush_deferred_work(wl);
1489 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001490 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001491 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001492
1493 mutex_lock(&wl->mutex);
1494 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001495 wl->flags = 0;
1496 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02001497 wl->plt = false;
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001498 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001499 mutex_unlock(&wl->mutex);
1500
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001501out:
1502 return ret;
1503}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001504
Johannes Berg7bb45682011-02-24 14:42:06 +01001505static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001506{
1507 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001508 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1509 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001510 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001511 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001512 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001513 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001514
Eliad Peller0f168012011-10-11 13:52:25 +02001515 if (vif)
1516 wlvif = wl12xx_vif_to_data(vif);
1517
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001518 mapping = skb_get_queue_mapping(skb);
1519 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001520
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001521 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001522
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001523 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001524
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001525 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001526 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001527 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001528 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001529 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001530 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001531 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001532
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001533 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1534 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1535
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001536 wl->tx_queue_count[q]++;
1537
1538 /*
1539 * The workqueue is slow to process the tx_queue and we need stop
1540 * the queue here, otherwise the queue will get too long.
1541 */
1542 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1543 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1544 ieee80211_stop_queue(wl->hw, mapping);
1545 set_bit(q, &wl->stopped_queues_map);
1546 }
1547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001548 /*
1549 * The chip specific setup must run before the first TX packet -
1550 * before that, the tx_work will not be initialized!
1551 */
1552
Ido Yarivb07d4032011-03-01 15:14:43 +02001553 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1554 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001555 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001556
Arik Nemtsov04216da2011-08-14 13:17:38 +03001557out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001558 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001559}
1560
Shahar Leviae47c452011-03-06 16:32:14 +02001561int wl1271_tx_dummy_packet(struct wl1271 *wl)
1562{
Ido Yariv990f5de2011-03-31 10:06:59 +02001563 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001564 int q;
1565
1566 /* no need to queue a new dummy packet if one is already pending */
1567 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1568 return 0;
1569
1570 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001571
Ido Yariv990f5de2011-03-31 10:06:59 +02001572 spin_lock_irqsave(&wl->wl_lock, flags);
1573 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001574 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001575 spin_unlock_irqrestore(&wl->wl_lock, flags);
1576
1577 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1578 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001579 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001580
1581 /*
1582 * If the FW TX is busy, TX work will be scheduled by the threaded
1583 * interrupt handler function
1584 */
1585 return 0;
1586}
1587
1588/*
1589 * The size of the dummy packet should be at least 1400 bytes. However, in
1590 * order to minimize the number of bus transactions, aligning it to 512 bytes
1591 * boundaries could be beneficial, performance wise
1592 */
1593#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1594
Luciano Coelhocf27d862011-04-01 21:08:23 +03001595static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001596{
1597 struct sk_buff *skb;
1598 struct ieee80211_hdr_3addr *hdr;
1599 unsigned int dummy_packet_size;
1600
1601 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1602 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1603
1604 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001605 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001606 wl1271_warning("Failed to allocate a dummy packet skb");
1607 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001608 }
1609
1610 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1611
1612 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1613 memset(hdr, 0, sizeof(*hdr));
1614 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001615 IEEE80211_STYPE_NULLFUNC |
1616 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001617
Ido Yariv990f5de2011-03-31 10:06:59 +02001618 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001619
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001620 /* Dummy packets require the TID to be management */
1621 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001622
1623 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001624 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001625 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001626
Ido Yariv990f5de2011-03-31 10:06:59 +02001627 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001628}
1629
Ido Yariv990f5de2011-03-31 10:06:59 +02001630
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001631static struct notifier_block wl1271_dev_notifier = {
1632 .notifier_call = wl1271_dev_notify,
1633};
1634
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001635#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001636static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1637 struct wl12xx_vif *wlvif)
1638{
1639 int ret = 0;
1640
1641 mutex_lock(&wl->mutex);
1642
1643 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1644 goto out_unlock;
1645
1646 ret = wl1271_ps_elp_wakeup(wl);
1647 if (ret < 0)
1648 goto out_unlock;
1649
1650 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1651 wl->conf.conn.suspend_wake_up_event,
1652 wl->conf.conn.suspend_listen_interval);
1653
1654 if (ret < 0)
1655 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1656
1657
1658 wl1271_ps_elp_sleep(wl);
1659
1660out_unlock:
1661 mutex_unlock(&wl->mutex);
1662 return ret;
1663
1664}
Eliad Peller94390642011-05-13 11:57:13 +03001665
Eliad Peller0603d892011-10-05 11:55:51 +02001666static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1667 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001668{
Eliad Pellere85d1622011-06-27 13:06:43 +03001669 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001670
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001671 mutex_lock(&wl->mutex);
1672
Eliad Peller53d40d02011-10-10 10:13:02 +02001673 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001674 goto out_unlock;
1675
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001676 ret = wl1271_ps_elp_wakeup(wl);
1677 if (ret < 0)
1678 goto out_unlock;
1679
Eliad Peller0603d892011-10-05 11:55:51 +02001680 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001681
1682 wl1271_ps_elp_sleep(wl);
1683out_unlock:
1684 mutex_unlock(&wl->mutex);
1685 return ret;
1686
1687}
1688
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001689static int wl1271_configure_suspend(struct wl1271 *wl,
1690 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001691{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001692 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1693 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001694 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001695 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001696 return 0;
1697}
1698
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001699static void wl1271_configure_resume(struct wl1271 *wl,
1700 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001701{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001702 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001703 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001704 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001705
Eyal Shapiradae728f2012-02-02 12:03:39 +02001706 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001707 return;
1708
1709 mutex_lock(&wl->mutex);
1710 ret = wl1271_ps_elp_wakeup(wl);
1711 if (ret < 0)
1712 goto out;
1713
Eyal Shapiradae728f2012-02-02 12:03:39 +02001714 if (is_sta) {
1715 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1716 wl->conf.conn.wake_up_event,
1717 wl->conf.conn.listen_interval);
1718
1719 if (ret < 0)
1720 wl1271_error("resume: wake up conditions failed: %d",
1721 ret);
1722
1723 } else if (is_ap) {
1724 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1725 }
Eliad Peller94390642011-05-13 11:57:13 +03001726
1727 wl1271_ps_elp_sleep(wl);
1728out:
1729 mutex_unlock(&wl->mutex);
1730}
1731
Eliad Peller402e48612011-05-13 11:57:09 +03001732static int wl1271_op_suspend(struct ieee80211_hw *hw,
1733 struct cfg80211_wowlan *wow)
1734{
1735 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001736 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 int ret;
1738
Eliad Peller402e48612011-05-13 11:57:09 +03001739 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001740 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741
Eliad Peller4a859df2011-06-06 12:21:52 +03001742 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001743 wl12xx_for_each_wlvif(wl, wlvif) {
1744 ret = wl1271_configure_suspend(wl, wlvif);
1745 if (ret < 0) {
1746 wl1271_warning("couldn't prepare device to suspend");
1747 return ret;
1748 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001749 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001750 /* flush any remaining work */
1751 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001752
1753 /*
1754 * disable and re-enable interrupts in order to flush
1755 * the threaded_irq
1756 */
1757 wl1271_disable_interrupts(wl);
1758
1759 /*
1760 * set suspended flag to avoid triggering a new threaded_irq
1761 * work. no need for spinlock as interrupts are disabled.
1762 */
1763 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1764
1765 wl1271_enable_interrupts(wl);
1766 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001767 flush_delayed_work(&wl->elp_work);
1768
Eliad Peller402e48612011-05-13 11:57:09 +03001769 return 0;
1770}
1771
1772static int wl1271_op_resume(struct ieee80211_hw *hw)
1773{
1774 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001775 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001776 unsigned long flags;
1777 bool run_irq_work = false;
1778
Eliad Peller402e48612011-05-13 11:57:09 +03001779 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1780 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001781 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001782
1783 /*
1784 * re-enable irq_work enqueuing, and call irq_work directly if
1785 * there is a pending work.
1786 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001787 spin_lock_irqsave(&wl->wl_lock, flags);
1788 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1789 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1790 run_irq_work = true;
1791 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001792
Eliad Peller4a859df2011-06-06 12:21:52 +03001793 if (run_irq_work) {
1794 wl1271_debug(DEBUG_MAC80211,
1795 "run postponed irq_work directly");
1796 wl1271_irq(0, wl);
1797 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001798 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001799 wl12xx_for_each_wlvif(wl, wlvif) {
1800 wl1271_configure_resume(wl, wlvif);
1801 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001802 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001803
Eliad Peller402e48612011-05-13 11:57:09 +03001804 return 0;
1805}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001806#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001807
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001808static int wl1271_op_start(struct ieee80211_hw *hw)
1809{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001810 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1811
1812 /*
1813 * We have to delay the booting of the hardware because
1814 * we need to know the local MAC address before downloading and
1815 * initializing the firmware. The MAC address cannot be changed
1816 * after boot, and without the proper MAC address, the firmware
1817 * will not function properly.
1818 *
1819 * The MAC address is first known when the corresponding interface
1820 * is added. That is where we will initialize the hardware.
1821 */
1822
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001823 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001824}
1825
1826static void wl1271_op_stop(struct ieee80211_hw *hw)
1827{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001828 struct wl1271 *wl = hw->priv;
1829 int i;
1830
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001831 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001832
Ido Yariv46b0cc92012-01-11 09:42:41 +02001833 /*
1834 * Interrupts must be disabled before setting the state to OFF.
1835 * Otherwise, the interrupt handler might be called and exit without
1836 * reading the interrupt status.
1837 */
1838 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001839 mutex_lock(&wl->mutex);
1840 if (wl->state == WL1271_STATE_OFF) {
1841 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001842
1843 /*
1844 * This will not necessarily enable interrupts as interrupts
1845 * may have been disabled when op_stop was called. It will,
1846 * however, balance the above call to disable_interrupts().
1847 */
1848 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001849 return;
1850 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001851
Eliad Pellerbaf62772011-10-10 10:12:52 +02001852 /*
1853 * this must be before the cancel_work calls below, so that the work
1854 * functions don't perform further work.
1855 */
1856 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001857 mutex_unlock(&wl->mutex);
1858
1859 mutex_lock(&wl_list_mutex);
1860 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001861 mutex_unlock(&wl_list_mutex);
1862
Eliad Pellerbaf62772011-10-10 10:12:52 +02001863 wl1271_flush_deferred_work(wl);
1864 cancel_delayed_work_sync(&wl->scan_complete_work);
1865 cancel_work_sync(&wl->netstack_work);
1866 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001867 cancel_delayed_work_sync(&wl->elp_work);
1868
1869 /* let's notify MAC80211 about the remaining pending TX frames */
1870 wl12xx_tx_reset(wl, true);
1871 mutex_lock(&wl->mutex);
1872
1873 wl1271_power_off(wl);
1874
1875 wl->band = IEEE80211_BAND_2GHZ;
1876
1877 wl->rx_counter = 0;
1878 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1879 wl->tx_blocks_available = 0;
1880 wl->tx_allocated_blocks = 0;
1881 wl->tx_results_count = 0;
1882 wl->tx_packets_count = 0;
1883 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001884 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1885 wl->ap_fw_ps_map = 0;
1886 wl->ap_ps_map = 0;
1887 wl->sched_scanning = false;
1888 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1889 memset(wl->links_map, 0, sizeof(wl->links_map));
1890 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1891 wl->active_sta_count = 0;
1892
1893 /* The system link is always allocated */
1894 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1895
1896 /*
1897 * this is performed after the cancel_work calls and the associated
1898 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1899 * get executed before all these vars have been reset.
1900 */
1901 wl->flags = 0;
1902
1903 wl->tx_blocks_freed = 0;
1904
1905 for (i = 0; i < NUM_TX_QUEUES; i++) {
1906 wl->tx_pkts_freed[i] = 0;
1907 wl->tx_allocated_pkts[i] = 0;
1908 }
1909
1910 wl1271_debugfs_reset(wl);
1911
1912 kfree(wl->fw_status);
1913 wl->fw_status = NULL;
1914 kfree(wl->tx_res_if);
1915 wl->tx_res_if = NULL;
1916 kfree(wl->target_mem_map);
1917 wl->target_mem_map = NULL;
1918
1919 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001920}
1921
Eliad Pellere5a359f2011-10-10 10:13:15 +02001922static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1923{
1924 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1925 WL12XX_MAX_RATE_POLICIES);
1926 if (policy >= WL12XX_MAX_RATE_POLICIES)
1927 return -EBUSY;
1928
1929 __set_bit(policy, wl->rate_policies_map);
1930 *idx = policy;
1931 return 0;
1932}
1933
1934static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1935{
1936 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1937 return;
1938
1939 __clear_bit(*idx, wl->rate_policies_map);
1940 *idx = WL12XX_MAX_RATE_POLICIES;
1941}
1942
Eliad Peller536129c2011-10-05 11:55:45 +02001943static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001944{
Eliad Peller536129c2011-10-05 11:55:45 +02001945 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001946 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001947 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001948 return WL1271_ROLE_P2P_GO;
1949 else
1950 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001951
1952 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001953 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001954 return WL1271_ROLE_P2P_CL;
1955 else
1956 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001957
Eliad Peller227e81e2011-08-14 13:17:26 +03001958 case BSS_TYPE_IBSS:
1959 return WL1271_ROLE_IBSS;
1960
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001961 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001962 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001963 }
1964 return WL12XX_INVALID_ROLE_TYPE;
1965}
1966
Eliad Peller83587502011-10-10 10:12:53 +02001967static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001968{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001969 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001970 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001971
Eliad Peller48e93e42011-10-10 10:12:58 +02001972 /* clear everything but the persistent data */
1973 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001974
1975 switch (ieee80211_vif_type_p2p(vif)) {
1976 case NL80211_IFTYPE_P2P_CLIENT:
1977 wlvif->p2p = 1;
1978 /* fall-through */
1979 case NL80211_IFTYPE_STATION:
1980 wlvif->bss_type = BSS_TYPE_STA_BSS;
1981 break;
1982 case NL80211_IFTYPE_ADHOC:
1983 wlvif->bss_type = BSS_TYPE_IBSS;
1984 break;
1985 case NL80211_IFTYPE_P2P_GO:
1986 wlvif->p2p = 1;
1987 /* fall-through */
1988 case NL80211_IFTYPE_AP:
1989 wlvif->bss_type = BSS_TYPE_AP_BSS;
1990 break;
1991 default:
1992 wlvif->bss_type = MAX_BSS_TYPE;
1993 return -EOPNOTSUPP;
1994 }
1995
Eliad Peller0603d892011-10-05 11:55:51 +02001996 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001997 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001998 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001999
Eliad Pellere936bbe2011-10-05 11:55:56 +02002000 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2001 wlvif->bss_type == BSS_TYPE_IBSS) {
2002 /* init sta/ibss data */
2003 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002004 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2005 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2006 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002007 } else {
2008 /* init ap data */
2009 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2010 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002011 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2012 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2013 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2014 wl12xx_allocate_rate_policy(wl,
2015 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002016 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002017
Eliad Peller83587502011-10-10 10:12:53 +02002018 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
2019 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002020 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002021 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002022 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02002023 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
2024
Eliad Peller1b92f152011-10-10 10:13:09 +02002025 /*
2026 * mac80211 configures some values globally, while we treat them
2027 * per-interface. thus, on init, we have to copy them from wl
2028 */
2029 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02002030 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02002031 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02002032
Eliad Peller9eb599e2011-10-10 10:12:59 +02002033 INIT_WORK(&wlvif->rx_streaming_enable_work,
2034 wl1271_rx_streaming_enable_work);
2035 INIT_WORK(&wlvif->rx_streaming_disable_work,
2036 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02002037 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02002038
Eliad Peller9eb599e2011-10-10 10:12:59 +02002039 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2040 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002041 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002042}
2043
Eliad Peller1d095472011-10-10 10:12:49 +02002044static bool wl12xx_init_fw(struct wl1271 *wl)
2045{
2046 int retries = WL1271_BOOT_RETRIES;
2047 bool booted = false;
2048 struct wiphy *wiphy = wl->hw->wiphy;
2049 int ret;
2050
2051 while (retries) {
2052 retries--;
Eliad Peller3fcdab72012-02-06 12:47:54 +02002053 ret = wl12xx_chip_wakeup(wl, false);
Eliad Peller1d095472011-10-10 10:12:49 +02002054 if (ret < 0)
2055 goto power_off;
2056
2057 ret = wl1271_boot(wl);
2058 if (ret < 0)
2059 goto power_off;
2060
2061 ret = wl1271_hw_init(wl);
2062 if (ret < 0)
2063 goto irq_disable;
2064
2065 booted = true;
2066 break;
2067
2068irq_disable:
2069 mutex_unlock(&wl->mutex);
2070 /* Unlocking the mutex in the middle of handling is
2071 inherently unsafe. In this case we deem it safe to do,
2072 because we need to let any possibly pending IRQ out of
2073 the system (and while we are WL1271_STATE_OFF the IRQ
2074 work function will not do anything.) Also, any other
2075 possible concurrent operations will fail due to the
2076 current state, hence the wl1271 struct should be safe. */
2077 wl1271_disable_interrupts(wl);
2078 wl1271_flush_deferred_work(wl);
2079 cancel_work_sync(&wl->netstack_work);
2080 mutex_lock(&wl->mutex);
2081power_off:
2082 wl1271_power_off(wl);
2083 }
2084
2085 if (!booted) {
2086 wl1271_error("firmware boot failed despite %d retries",
2087 WL1271_BOOT_RETRIES);
2088 goto out;
2089 }
2090
2091 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2092
2093 /* update hw/fw version info in wiphy struct */
2094 wiphy->hw_version = wl->chip.id;
2095 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2096 sizeof(wiphy->fw_version));
2097
2098 /*
2099 * Now we know if 11a is supported (info from the NVS), so disable
2100 * 11a channels if not supported
2101 */
2102 if (!wl->enable_11a)
2103 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2104
2105 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2106 wl->enable_11a ? "" : "not ");
2107
2108 wl->state = WL1271_STATE_ON;
2109out:
2110 return booted;
2111}
2112
Eliad Peller92e712d2011-12-18 20:25:43 +02002113static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2114{
2115 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2116}
2117
Eliad Peller4549d092012-02-06 13:07:52 +02002118/*
2119 * Check whether a fw switch (i.e. moving from one loaded
2120 * fw to another) is needed. This function is also responsible
2121 * for updating wl->last_vif_count, so it must be called before
2122 * loading a non-plt fw (so the correct fw (single-role/multi-role)
2123 * will be used).
2124 */
2125static bool wl12xx_need_fw_change(struct wl1271 *wl,
2126 struct vif_counter_data vif_counter_data,
2127 bool add)
2128{
2129 enum wl12xx_fw_type current_fw = wl->fw_type;
2130 u8 vif_count = vif_counter_data.counter;
2131
2132 if (test_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags))
2133 return false;
2134
2135 /* increase the vif count if this is a new vif */
2136 if (add && !vif_counter_data.cur_vif_running)
2137 vif_count++;
2138
2139 wl->last_vif_count = vif_count;
2140
2141 /* no need for fw change if the device is OFF */
2142 if (wl->state == WL1271_STATE_OFF)
2143 return false;
2144
2145 if (vif_count > 1 && current_fw == WL12XX_FW_TYPE_NORMAL)
2146 return true;
2147 if (vif_count <= 1 && current_fw == WL12XX_FW_TYPE_MULTI)
2148 return true;
2149
2150 return false;
2151}
2152
Eliad Peller3dee4392012-02-06 12:47:56 +02002153/*
2154 * Enter "forced psm". Make sure the sta is in psm against the ap,
2155 * to make the fw switch a bit more disconnection-persistent.
2156 */
2157static void wl12xx_force_active_psm(struct wl1271 *wl)
2158{
2159 struct wl12xx_vif *wlvif;
2160
2161 wl12xx_for_each_wlvif_sta(wl, wlvif) {
2162 wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE);
2163 }
2164}
2165
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002166static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2167 struct ieee80211_vif *vif)
2168{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002169 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002170 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller4549d092012-02-06 13:07:52 +02002171 struct vif_counter_data vif_count;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002173 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002174 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002175
Johannes Bergea086352012-01-19 09:29:58 +01002176 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2177 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002178
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002179 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002180 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Eliad Peller4549d092012-02-06 13:07:52 +02002182 wl12xx_get_vif_count(hw, vif, &vif_count);
2183
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002184 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002185 ret = wl1271_ps_elp_wakeup(wl);
2186 if (ret < 0)
2187 goto out_unlock;
2188
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002189 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002190 wl1271_debug(DEBUG_MAC80211,
2191 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002192 ret = -EBUSY;
2193 goto out;
2194 }
2195
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002196 /*
2197 * in some very corner case HW recovery scenarios its possible to
2198 * get here before __wl1271_op_remove_interface is complete, so
2199 * opt out if that is the case.
2200 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002201 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2202 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002203 ret = -EBUSY;
2204 goto out;
2205 }
2206
Eliad Peller3fcdab72012-02-06 12:47:54 +02002207
Eliad Peller83587502011-10-10 10:12:53 +02002208 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002209 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002210 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002211
Eliad Peller252efa42011-10-05 11:56:00 +02002212 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002213 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002214 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2215 ret = -EINVAL;
2216 goto out;
2217 }
Eliad Peller1d095472011-10-10 10:12:49 +02002218
Eliad Peller4549d092012-02-06 13:07:52 +02002219 if (wl12xx_need_fw_change(wl, vif_count, true)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002220 wl12xx_force_active_psm(wl);
Eliad Peller4549d092012-02-06 13:07:52 +02002221 mutex_unlock(&wl->mutex);
2222 wl1271_recovery_work(&wl->recovery_work);
2223 return 0;
2224 }
2225
Eliad Peller784f6942011-10-05 11:55:39 +02002226 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002227 * TODO: after the nvs issue will be solved, move this block
2228 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002229 */
Eliad Peller1d095472011-10-10 10:12:49 +02002230 if (wl->state == WL1271_STATE_OFF) {
2231 /*
2232 * we still need this in order to configure the fw
2233 * while uploading the nvs
2234 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002235 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002236
Eliad Peller1d095472011-10-10 10:12:49 +02002237 booted = wl12xx_init_fw(wl);
2238 if (!booted) {
2239 ret = -EINVAL;
2240 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002241 }
Eliad Peller1d095472011-10-10 10:12:49 +02002242 }
Eliad Peller04e80792011-08-14 13:17:09 +03002243
Eliad Peller1d095472011-10-10 10:12:49 +02002244 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2245 wlvif->bss_type == BSS_TYPE_IBSS) {
2246 /*
2247 * The device role is a special role used for
2248 * rx and tx frames prior to association (as
2249 * the STA role can get packets only from
2250 * its associated bssid)
2251 */
Eliad Peller784f6942011-10-05 11:55:39 +02002252 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002253 WL1271_ROLE_DEVICE,
2254 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002255 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002256 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002257 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002258
Eliad Peller1d095472011-10-10 10:12:49 +02002259 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2260 role_type, &wlvif->role_id);
2261 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002262 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002263
2264 ret = wl1271_init_vif_specific(wl, vif);
2265 if (ret < 0)
2266 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002267
2268 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002269 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002270 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002271
2272 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2273 wl->ap_count++;
2274 else
2275 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002276out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002277 wl1271_ps_elp_sleep(wl);
2278out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002279 mutex_unlock(&wl->mutex);
2280
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002281 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002282 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002283 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002284 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002286 return ret;
2287}
2288
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002289static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002290 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002291 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002292{
Eliad Peller536129c2011-10-05 11:55:45 +02002293 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002294 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002296 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297
Eliad Peller10c8cd02011-10-10 10:13:06 +02002298 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2299 return;
2300
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002301 wl->vif = NULL;
2302
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002303 /* because of hardware recovery, we may get here twice */
2304 if (wl->state != WL1271_STATE_ON)
2305 return;
2306
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002307 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002308
Eliad Pellerbaf62772011-10-10 10:12:52 +02002309 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2310 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002311 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002312 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002313 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002314 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002315 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002316 }
2317
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002318 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2319 /* disable active roles */
2320 ret = wl1271_ps_elp_wakeup(wl);
2321 if (ret < 0)
2322 goto deinit;
2323
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002324 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2325 wlvif->bss_type == BSS_TYPE_IBSS) {
2326 if (wl12xx_dev_role_started(wlvif))
2327 wl12xx_stop_dev(wl, wlvif);
2328
Eliad Peller7edebf52011-10-05 11:55:52 +02002329 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002330 if (ret < 0)
2331 goto deinit;
2332 }
2333
Eliad Peller0603d892011-10-05 11:55:51 +02002334 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002335 if (ret < 0)
2336 goto deinit;
2337
2338 wl1271_ps_elp_sleep(wl);
2339 }
2340deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002341 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002342 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002343
2344 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2345 wlvif->bss_type == BSS_TYPE_IBSS) {
2346 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2347 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2348 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2349 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2350 } else {
2351 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2352 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2353 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2354 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2355 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2356 wl12xx_free_rate_policy(wl,
2357 &wlvif->ap.ucast_rate_idx[i]);
2358 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002359
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002360 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002361 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002362 if (wl->last_wlvif == wlvif)
2363 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002364 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002365 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002366 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002367 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002368
Eliad Pellera4e41302011-10-11 11:49:15 +02002369 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2370 wl->ap_count--;
2371 else
2372 wl->sta_count--;
2373
Eliad Pellerbaf62772011-10-10 10:12:52 +02002374 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002375
Eliad Peller9eb599e2011-10-10 10:12:59 +02002376 del_timer_sync(&wlvif->rx_streaming_timer);
2377 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2378 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002379
Eliad Pellerbaf62772011-10-10 10:12:52 +02002380 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002381}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002382
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002383static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2384 struct ieee80211_vif *vif)
2385{
2386 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002387 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002388 struct wl12xx_vif *iter;
Eliad Peller4549d092012-02-06 13:07:52 +02002389 struct vif_counter_data vif_count;
2390 bool cancel_recovery = true;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002391
Eliad Peller4549d092012-02-06 13:07:52 +02002392 wl12xx_get_vif_count(hw, vif, &vif_count);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002393 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002394
2395 if (wl->state == WL1271_STATE_OFF ||
2396 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2397 goto out;
2398
Juuso Oikarinen67353292010-11-18 15:19:02 +02002399 /*
2400 * wl->vif can be null here if someone shuts down the interface
2401 * just when hardware recovery has been started.
2402 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002403 wl12xx_for_each_wlvif(wl, iter) {
2404 if (iter != wlvif)
2405 continue;
2406
Eliad Peller536129c2011-10-05 11:55:45 +02002407 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002408 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002409 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002410 WARN_ON(iter != wlvif);
Eliad Peller4549d092012-02-06 13:07:52 +02002411 if (wl12xx_need_fw_change(wl, vif_count, false)) {
Eliad Peller3dee4392012-02-06 12:47:56 +02002412 wl12xx_force_active_psm(wl);
Eliad Peller4549d092012-02-06 13:07:52 +02002413 wl12xx_queue_recovery_work(wl);
2414 cancel_recovery = false;
2415 }
Eliad Peller10c8cd02011-10-10 10:13:06 +02002416out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002417 mutex_unlock(&wl->mutex);
Eliad Peller4549d092012-02-06 13:07:52 +02002418 if (cancel_recovery)
2419 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002420}
2421
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002422static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2423 struct ieee80211_vif *vif,
2424 enum nl80211_iftype new_type, bool p2p)
2425{
Eliad Peller4549d092012-02-06 13:07:52 +02002426 struct wl1271 *wl = hw->priv;
2427 int ret;
2428
2429 set_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002430 wl1271_op_remove_interface(hw, vif);
2431
2432 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2433 vif->p2p = p2p;
Eliad Peller4549d092012-02-06 13:07:52 +02002434 ret = wl1271_op_add_interface(hw, vif);
2435
2436 clear_bit(WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, &wl->flags);
2437 return ret;
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002438}
2439
Eliad Peller87fbcb02011-10-05 11:55:41 +02002440static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2441 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002442{
2443 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002444 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002445
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002446 /*
2447 * One of the side effects of the JOIN command is that is clears
2448 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2449 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002450 * Currently the only valid scenario for JOIN during association
2451 * is on roaming, in which case we will also be given new keys.
2452 * Keep the below message for now, unless it starts bothering
2453 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002454 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002455 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002456 wl1271_info("JOIN while associated.");
2457
Eliad Peller5ec8a442012-02-02 12:22:09 +02002458 /* clear encryption type */
2459 wlvif->encryption_type = KEY_NONE;
2460
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002461 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002462 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002463
Eliad Peller227e81e2011-08-14 13:17:26 +03002464 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002465 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002466 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002467 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002468 if (ret < 0)
2469 goto out;
2470
Eliad Pellerba8447f2011-10-10 10:13:00 +02002471 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002472 goto out;
2473
2474 /*
2475 * The join command disable the keep-alive mode, shut down its process,
2476 * and also clear the template config, so we need to reset it all after
2477 * the join. The acx_aid starts the keep-alive process, and the order
2478 * of the commands below is relevant.
2479 */
Eliad Peller0603d892011-10-05 11:55:51 +02002480 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002481 if (ret < 0)
2482 goto out;
2483
Eliad Peller0603d892011-10-05 11:55:51 +02002484 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002485 if (ret < 0)
2486 goto out;
2487
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002488 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002489 if (ret < 0)
2490 goto out;
2491
Eliad Peller0603d892011-10-05 11:55:51 +02002492 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2493 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002494 ACX_KEEP_ALIVE_TPL_VALID);
2495 if (ret < 0)
2496 goto out;
2497
2498out:
2499 return ret;
2500}
2501
Eliad Peller0603d892011-10-05 11:55:51 +02002502static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002503{
2504 int ret;
2505
Eliad Peller52630c52011-10-10 10:13:08 +02002506 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002507 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2508
Shahar Levi6d158ff2011-09-08 13:01:33 +03002509 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002510 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002511 }
2512
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002513 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002514 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002515 if (ret < 0)
2516 goto out;
2517
Oz Krakowskib992c682011-06-26 10:36:02 +03002518 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002519 wlvif->tx_security_last_seq_lsb = 0;
2520 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002521
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002522out:
2523 return ret;
2524}
2525
Eliad Peller87fbcb02011-10-05 11:55:41 +02002526static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002527{
Eliad Peller1b92f152011-10-10 10:13:09 +02002528 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002529 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002530}
2531
Eliad Peller87fbcb02011-10-05 11:55:41 +02002532static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2533 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002534{
2535 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002536 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2537
2538 if (idle == cur_idle)
2539 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002540
2541 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002542 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002543 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002544 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002545 if (ret < 0)
2546 goto out;
2547 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002548 wlvif->rate_set =
2549 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2550 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002551 if (ret < 0)
2552 goto out;
2553 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002554 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002555 ACX_KEEP_ALIVE_TPL_INVALID);
2556 if (ret < 0)
2557 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002558 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002559 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002560 /* The current firmware only supports sched_scan in idle */
2561 if (wl->sched_scanning) {
2562 wl1271_scan_sched_scan_stop(wl);
2563 ieee80211_sched_scan_stopped(wl->hw);
2564 }
2565
Eliad Peller679a6732011-10-11 11:55:44 +02002566 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002567 if (ret < 0)
2568 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002569 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002570 }
2571
2572out:
2573 return ret;
2574}
2575
Eliad Peller9f259c42011-10-10 10:13:12 +02002576static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2577 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002578{
Eliad Peller9f259c42011-10-10 10:13:12 +02002579 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2580 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002581
2582 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2583
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002584 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002585 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002586 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002587 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002588 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002589 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002590 wlvif->band = conf->channel->band;
2591 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002592
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002593 if (!is_ap) {
2594 /*
2595 * FIXME: the mac80211 should really provide a fixed
2596 * rate to use here. for now, just use the smallest
2597 * possible rate for the band as a fixed rate for
2598 * association frames and other control messages.
2599 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002600 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002601 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002602
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002603 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002604 wl1271_tx_min_rate_get(wl,
2605 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002606 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002607 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002608 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002609 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002610
Eliad Pellerba8447f2011-10-10 10:13:00 +02002611 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2612 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002613 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002614 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002615 ret = wl12xx_croc(wl,
2616 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002617 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002618 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002619 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002620 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002621 if (ret < 0)
2622 wl1271_warning("cmd join on channel "
2623 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002624 } else {
2625 /*
2626 * change the ROC channel. do it only if we are
2627 * not idle. otherwise, CROC will be called
2628 * anyway.
2629 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002630 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002631 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002632 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002633 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002634 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002635
Eliad Peller679a6732011-10-11 11:55:44 +02002636 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002637 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002638 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002639 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002640 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002641 }
2642 }
2643
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002644 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002645
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002646 if ((conf->flags & IEEE80211_CONF_PS) &&
2647 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002648 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002649
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002650 int ps_mode;
2651 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002652
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002653 if (wl->conf.conn.forced_ps) {
2654 ps_mode = STATION_POWER_SAVE_MODE;
2655 ps_mode_str = "forced";
2656 } else {
2657 ps_mode = STATION_AUTO_PS_MODE;
2658 ps_mode_str = "auto";
2659 }
2660
2661 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2662
2663 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2664
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002665 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002666 wl1271_warning("enter %s ps failed %d",
2667 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002669 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002670 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002672 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2673
Eliad Peller0603d892011-10-05 11:55:51 +02002674 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002675 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002676 if (ret < 0)
2677 wl1271_warning("exit auto ps failed %d", ret);
2678 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679 }
2680
Eliad Peller6bd65022011-10-10 10:13:11 +02002681 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002682 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002683 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002684 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002685
Eliad Peller6bd65022011-10-10 10:13:11 +02002686 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002687 }
2688
Eliad Peller9f259c42011-10-10 10:13:12 +02002689 return 0;
2690}
2691
2692static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2693{
2694 struct wl1271 *wl = hw->priv;
2695 struct wl12xx_vif *wlvif;
2696 struct ieee80211_conf *conf = &hw->conf;
2697 int channel, ret = 0;
2698
2699 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2700
2701 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2702 " changed 0x%x",
2703 channel,
2704 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2705 conf->power_level,
2706 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2707 changed);
2708
2709 /*
2710 * mac80211 will go to idle nearly immediately after transmitting some
2711 * frames, such as the deauth. To make sure those frames reach the air,
2712 * wait here until the TX queue is fully flushed.
2713 */
2714 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2715 (conf->flags & IEEE80211_CONF_IDLE))
2716 wl1271_tx_flush(wl);
2717
2718 mutex_lock(&wl->mutex);
2719
2720 /* we support configuring the channel and band even while off */
2721 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2722 wl->band = conf->channel->band;
2723 wl->channel = channel;
2724 }
2725
2726 if (changed & IEEE80211_CONF_CHANGE_POWER)
2727 wl->power_level = conf->power_level;
2728
2729 if (unlikely(wl->state == WL1271_STATE_OFF))
2730 goto out;
2731
2732 ret = wl1271_ps_elp_wakeup(wl);
2733 if (ret < 0)
2734 goto out;
2735
2736 /* configure each interface */
2737 wl12xx_for_each_wlvif(wl, wlvif) {
2738 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2739 if (ret < 0)
2740 goto out_sleep;
2741 }
2742
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002743out_sleep:
2744 wl1271_ps_elp_sleep(wl);
2745
2746out:
2747 mutex_unlock(&wl->mutex);
2748
2749 return ret;
2750}
2751
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002752struct wl1271_filter_params {
2753 bool enabled;
2754 int mc_list_length;
2755 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2756};
2757
Jiri Pirko22bedad2010-04-01 21:22:57 +00002758static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2759 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002760{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002761 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002762 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002763 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002764
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002765 if (unlikely(wl->state == WL1271_STATE_OFF))
2766 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002767
Juuso Oikarinen74441132009-10-13 12:47:53 +03002768 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002769 if (!fp) {
2770 wl1271_error("Out of memory setting filters.");
2771 return 0;
2772 }
2773
2774 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002775 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002776 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2777 fp->enabled = false;
2778 } else {
2779 fp->enabled = true;
2780 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002781 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002782 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002783 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002784 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002785 }
2786
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002787 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002788}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002789
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002790#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2791 FIF_ALLMULTI | \
2792 FIF_FCSFAIL | \
2793 FIF_BCN_PRBRESP_PROMISC | \
2794 FIF_CONTROL | \
2795 FIF_OTHER_BSS)
2796
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002797static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2798 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002799 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002800{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002801 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002802 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002803 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002804
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002805 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002806
Arik Nemtsov7d057862010-10-16 19:25:35 +02002807 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2808 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002809
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002810 mutex_lock(&wl->mutex);
2811
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002812 *total &= WL1271_SUPPORTED_FILTERS;
2813 changed &= WL1271_SUPPORTED_FILTERS;
2814
2815 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002816 goto out;
2817
Ido Yariva6208652011-03-01 15:14:41 +02002818 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002819 if (ret < 0)
2820 goto out;
2821
Eliad Peller6e8cd332011-10-10 10:13:13 +02002822 wl12xx_for_each_wlvif(wl, wlvif) {
2823 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2824 if (*total & FIF_ALLMULTI)
2825 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2826 false,
2827 NULL, 0);
2828 else if (fp)
2829 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2830 fp->enabled,
2831 fp->mc_list,
2832 fp->mc_list_length);
2833 if (ret < 0)
2834 goto out_sleep;
2835 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002836 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002837
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002838 /*
2839 * the fw doesn't provide an api to configure the filters. instead,
2840 * the filters configuration is based on the active roles / ROC
2841 * state.
2842 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002843
2844out_sleep:
2845 wl1271_ps_elp_sleep(wl);
2846
2847out:
2848 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002849 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002850}
2851
Eliad Peller170d0e62011-10-05 11:56:06 +02002852static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2853 u8 id, u8 key_type, u8 key_size,
2854 const u8 *key, u8 hlid, u32 tx_seq_32,
2855 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002856{
2857 struct wl1271_ap_key *ap_key;
2858 int i;
2859
2860 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2861
2862 if (key_size > MAX_KEY_SIZE)
2863 return -EINVAL;
2864
2865 /*
2866 * Find next free entry in ap_keys. Also check we are not replacing
2867 * an existing key.
2868 */
2869 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002870 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002871 break;
2872
Eliad Peller170d0e62011-10-05 11:56:06 +02002873 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002874 wl1271_warning("trying to record key replacement");
2875 return -EINVAL;
2876 }
2877 }
2878
2879 if (i == MAX_NUM_KEYS)
2880 return -EBUSY;
2881
2882 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2883 if (!ap_key)
2884 return -ENOMEM;
2885
2886 ap_key->id = id;
2887 ap_key->key_type = key_type;
2888 ap_key->key_size = key_size;
2889 memcpy(ap_key->key, key, key_size);
2890 ap_key->hlid = hlid;
2891 ap_key->tx_seq_32 = tx_seq_32;
2892 ap_key->tx_seq_16 = tx_seq_16;
2893
Eliad Peller170d0e62011-10-05 11:56:06 +02002894 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002895 return 0;
2896}
2897
Eliad Peller170d0e62011-10-05 11:56:06 +02002898static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002899{
2900 int i;
2901
2902 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002903 kfree(wlvif->ap.recorded_keys[i]);
2904 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 }
2906}
2907
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002908static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002909{
2910 int i, ret = 0;
2911 struct wl1271_ap_key *key;
2912 bool wep_key_added = false;
2913
2914 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002915 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002916 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002917 break;
2918
Eliad Peller170d0e62011-10-05 11:56:06 +02002919 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002920 hlid = key->hlid;
2921 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002922 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002923
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002924 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002925 key->id, key->key_type,
2926 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002927 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002928 key->tx_seq_16);
2929 if (ret < 0)
2930 goto out;
2931
2932 if (key->key_type == KEY_WEP)
2933 wep_key_added = true;
2934 }
2935
2936 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002937 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002938 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002939 if (ret < 0)
2940 goto out;
2941 }
2942
2943out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002944 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002945 return ret;
2946}
2947
Eliad Peller536129c2011-10-05 11:55:45 +02002948static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2949 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002950 u8 key_size, const u8 *key, u32 tx_seq_32,
2951 u16 tx_seq_16, struct ieee80211_sta *sta)
2952{
2953 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002954 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002955
2956 if (is_ap) {
2957 struct wl1271_station *wl_sta;
2958 u8 hlid;
2959
2960 if (sta) {
2961 wl_sta = (struct wl1271_station *)sta->drv_priv;
2962 hlid = wl_sta->hlid;
2963 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002964 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002965 }
2966
Eliad Peller53d40d02011-10-10 10:13:02 +02002967 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002968 /*
2969 * We do not support removing keys after AP shutdown.
2970 * Pretend we do to make mac80211 happy.
2971 */
2972 if (action != KEY_ADD_OR_REPLACE)
2973 return 0;
2974
Eliad Peller170d0e62011-10-05 11:56:06 +02002975 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002976 key_type, key_size,
2977 key, hlid, tx_seq_32,
2978 tx_seq_16);
2979 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002980 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002981 id, key_type, key_size,
2982 key, hlid, tx_seq_32,
2983 tx_seq_16);
2984 }
2985
2986 if (ret < 0)
2987 return ret;
2988 } else {
2989 const u8 *addr;
2990 static const u8 bcast_addr[ETH_ALEN] = {
2991 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2992 };
2993
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002994 /*
2995 * A STA set to GEM cipher requires 2 tx spare blocks.
2996 * Return to default value when GEM cipher key is removed
2997 */
2998 if (key_type == KEY_GEM) {
2999 if (action == KEY_ADD_OR_REPLACE)
3000 wl->tx_spare_blocks = 2;
3001 else if (action == KEY_REMOVE)
3002 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
3003 }
3004
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003005 addr = sta ? sta->addr : bcast_addr;
3006
3007 if (is_zero_ether_addr(addr)) {
3008 /* We dont support TX only encryption */
3009 return -EOPNOTSUPP;
3010 }
3011
3012 /* The wl1271 does not allow to remove unicast keys - they
3013 will be cleared automatically on next CMD_JOIN. Ignore the
3014 request silently, as we dont want the mac80211 to emit
3015 an error message. */
3016 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
3017 return 0;
3018
Eliad Peller010d3d32011-08-14 13:17:31 +03003019 /* don't remove key if hlid was already deleted */
3020 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02003021 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03003022 return 0;
3023
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003024 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003025 id, key_type, key_size,
3026 key, addr, tx_seq_32,
3027 tx_seq_16);
3028 if (ret < 0)
3029 return ret;
3030
3031 /* the default WEP key needs to be configured at least once */
3032 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03003033 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02003034 wlvif->default_key,
3035 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003036 if (ret < 0)
3037 return ret;
3038 }
3039 }
3040
3041 return 0;
3042}
3043
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003044static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
3045 struct ieee80211_vif *vif,
3046 struct ieee80211_sta *sta,
3047 struct ieee80211_key_conf *key_conf)
3048{
3049 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003050 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003051 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03003052 u32 tx_seq_32 = 0;
3053 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003054 u8 key_type;
3055
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003056 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
3057
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003058 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02003060 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 key_conf->keylen, key_conf->flags);
3062 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
3063
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003064 mutex_lock(&wl->mutex);
3065
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003066 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3067 ret = -EAGAIN;
3068 goto out_unlock;
3069 }
3070
Ido Yariva6208652011-03-01 15:14:41 +02003071 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003072 if (ret < 0)
3073 goto out_unlock;
3074
Johannes Berg97359d12010-08-10 09:46:38 +02003075 switch (key_conf->cipher) {
3076 case WLAN_CIPHER_SUITE_WEP40:
3077 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003078 key_type = KEY_WEP;
3079
3080 key_conf->hw_key_idx = key_conf->keyidx;
3081 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003082 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003083 key_type = KEY_TKIP;
3084
3085 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02003086 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3087 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003088 break;
Johannes Berg97359d12010-08-10 09:46:38 +02003089 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003090 key_type = KEY_AES;
3091
Arik Nemtsov12d4b972011-10-23 08:21:54 +02003092 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02003093 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3094 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003095 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003096 case WL1271_CIPHER_SUITE_GEM:
3097 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02003098 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
3099 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02003100 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003101 default:
Johannes Berg97359d12010-08-10 09:46:38 +02003102 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003103
3104 ret = -EOPNOTSUPP;
3105 goto out_sleep;
3106 }
3107
3108 switch (cmd) {
3109 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003110 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003111 key_conf->keyidx, key_type,
3112 key_conf->keylen, key_conf->key,
3113 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003114 if (ret < 0) {
3115 wl1271_error("Could not add or replace key");
3116 goto out_sleep;
3117 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02003118
3119 /*
3120 * reconfiguring arp response if the unicast (or common)
3121 * encryption key type was changed
3122 */
3123 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
3124 (sta || key_type == KEY_WEP) &&
3125 wlvif->encryption_type != key_type) {
3126 wlvif->encryption_type = key_type;
3127 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3128 if (ret < 0) {
3129 wl1271_warning("build arp rsp failed: %d", ret);
3130 goto out_sleep;
3131 }
3132 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003133 break;
3134
3135 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003136 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003137 key_conf->keyidx, key_type,
3138 key_conf->keylen, key_conf->key,
3139 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003140 if (ret < 0) {
3141 wl1271_error("Could not remove key");
3142 goto out_sleep;
3143 }
3144 break;
3145
3146 default:
3147 wl1271_error("Unsupported key cmd 0x%x", cmd);
3148 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003149 break;
3150 }
3151
3152out_sleep:
3153 wl1271_ps_elp_sleep(wl);
3154
3155out_unlock:
3156 mutex_unlock(&wl->mutex);
3157
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003158 return ret;
3159}
3160
3161static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003162 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003163 struct cfg80211_scan_request *req)
3164{
3165 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003166 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3167
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003168 int ret;
3169 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003170 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003171
3172 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3173
3174 if (req->n_ssids) {
3175 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003176 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003177 }
3178
3179 mutex_lock(&wl->mutex);
3180
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003181 if (wl->state == WL1271_STATE_OFF) {
3182 /*
3183 * We cannot return -EBUSY here because cfg80211 will expect
3184 * a call to ieee80211_scan_completed if we do - in this case
3185 * there won't be any call.
3186 */
3187 ret = -EAGAIN;
3188 goto out;
3189 }
3190
Ido Yariva6208652011-03-01 15:14:41 +02003191 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003192 if (ret < 0)
3193 goto out;
3194
Eliad Peller92e712d2011-12-18 20:25:43 +02003195 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3196 test_bit(wlvif->role_id, wl->roc_map)) {
3197 /* don't allow scanning right now */
3198 ret = -EBUSY;
3199 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003200 }
3201
Eliad Peller784f6942011-10-05 11:55:39 +02003202 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003203out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003204 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003205out:
3206 mutex_unlock(&wl->mutex);
3207
3208 return ret;
3209}
3210
Eliad Peller73ecce32011-06-27 13:06:45 +03003211static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3212 struct ieee80211_vif *vif)
3213{
3214 struct wl1271 *wl = hw->priv;
3215 int ret;
3216
3217 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3218
3219 mutex_lock(&wl->mutex);
3220
3221 if (wl->state == WL1271_STATE_OFF)
3222 goto out;
3223
3224 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3225 goto out;
3226
3227 ret = wl1271_ps_elp_wakeup(wl);
3228 if (ret < 0)
3229 goto out;
3230
3231 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3232 ret = wl1271_scan_stop(wl);
3233 if (ret < 0)
3234 goto out_sleep;
3235 }
3236 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3237 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003238 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003239 wl->scan.req = NULL;
3240 ieee80211_scan_completed(wl->hw, true);
3241
3242out_sleep:
3243 wl1271_ps_elp_sleep(wl);
3244out:
3245 mutex_unlock(&wl->mutex);
3246
3247 cancel_delayed_work_sync(&wl->scan_complete_work);
3248}
3249
Luciano Coelho33c2c062011-05-10 14:46:02 +03003250static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3251 struct ieee80211_vif *vif,
3252 struct cfg80211_sched_scan_request *req,
3253 struct ieee80211_sched_scan_ies *ies)
3254{
3255 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003256 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003257 int ret;
3258
3259 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3260
3261 mutex_lock(&wl->mutex);
3262
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003263 if (wl->state == WL1271_STATE_OFF) {
3264 ret = -EAGAIN;
3265 goto out;
3266 }
3267
Luciano Coelho33c2c062011-05-10 14:46:02 +03003268 ret = wl1271_ps_elp_wakeup(wl);
3269 if (ret < 0)
3270 goto out;
3271
Eliad Peller536129c2011-10-05 11:55:45 +02003272 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003273 if (ret < 0)
3274 goto out_sleep;
3275
Eliad Peller536129c2011-10-05 11:55:45 +02003276 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003277 if (ret < 0)
3278 goto out_sleep;
3279
3280 wl->sched_scanning = true;
3281
3282out_sleep:
3283 wl1271_ps_elp_sleep(wl);
3284out:
3285 mutex_unlock(&wl->mutex);
3286 return ret;
3287}
3288
3289static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3290 struct ieee80211_vif *vif)
3291{
3292 struct wl1271 *wl = hw->priv;
3293 int ret;
3294
3295 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3296
3297 mutex_lock(&wl->mutex);
3298
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003299 if (wl->state == WL1271_STATE_OFF)
3300 goto out;
3301
Luciano Coelho33c2c062011-05-10 14:46:02 +03003302 ret = wl1271_ps_elp_wakeup(wl);
3303 if (ret < 0)
3304 goto out;
3305
3306 wl1271_scan_sched_scan_stop(wl);
3307
3308 wl1271_ps_elp_sleep(wl);
3309out:
3310 mutex_unlock(&wl->mutex);
3311}
3312
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003313static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3314{
3315 struct wl1271 *wl = hw->priv;
3316 int ret = 0;
3317
3318 mutex_lock(&wl->mutex);
3319
3320 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3321 ret = -EAGAIN;
3322 goto out;
3323 }
3324
Ido Yariva6208652011-03-01 15:14:41 +02003325 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003326 if (ret < 0)
3327 goto out;
3328
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003329 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003330 if (ret < 0)
3331 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3332
3333 wl1271_ps_elp_sleep(wl);
3334
3335out:
3336 mutex_unlock(&wl->mutex);
3337
3338 return ret;
3339}
3340
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003341static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3342{
3343 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003344 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003345 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003346
3347 mutex_lock(&wl->mutex);
3348
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003349 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3350 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003351 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003352 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003353
Ido Yariva6208652011-03-01 15:14:41 +02003354 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003355 if (ret < 0)
3356 goto out;
3357
Eliad Peller6e8cd332011-10-10 10:13:13 +02003358 wl12xx_for_each_wlvif(wl, wlvif) {
3359 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3360 if (ret < 0)
3361 wl1271_warning("set rts threshold failed: %d", ret);
3362 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003363 wl1271_ps_elp_sleep(wl);
3364
3365out:
3366 mutex_unlock(&wl->mutex);
3367
3368 return ret;
3369}
3370
Eliad Peller1fe9f162011-10-05 11:55:48 +02003371static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003372 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003373{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003374 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003375 u8 ssid_len;
3376 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3377 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003378
Eliad Peller889cb362011-05-01 09:56:45 +03003379 if (!ptr) {
3380 wl1271_error("No SSID in IEs!");
3381 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003382 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003383
Eliad Peller889cb362011-05-01 09:56:45 +03003384 ssid_len = ptr[1];
3385 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3386 wl1271_error("SSID is too long!");
3387 return -EINVAL;
3388 }
3389
Eliad Peller1fe9f162011-10-05 11:55:48 +02003390 wlvif->ssid_len = ssid_len;
3391 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003392 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003393}
3394
Eliad Pellerd48055d2011-09-15 12:07:04 +03003395static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3396{
3397 int len;
3398 const u8 *next, *end = skb->data + skb->len;
3399 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3400 skb->len - ieoffset);
3401 if (!ie)
3402 return;
3403 len = ie[1] + 2;
3404 next = ie + len;
3405 memmove(ie, next, end - next);
3406 skb_trim(skb, skb->len - len);
3407}
3408
Eliad Peller26b4bf22011-09-15 12:07:05 +03003409static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3410 unsigned int oui, u8 oui_type,
3411 int ieoffset)
3412{
3413 int len;
3414 const u8 *next, *end = skb->data + skb->len;
3415 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3416 skb->data + ieoffset,
3417 skb->len - ieoffset);
3418 if (!ie)
3419 return;
3420 len = ie[1] + 2;
3421 next = ie + len;
3422 memmove(ie, next, end - next);
3423 skb_trim(skb, skb->len - len);
3424}
3425
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003426static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3427 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003428{
Eliad Pellercdaac622012-01-31 11:57:16 +02003429 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003430 struct sk_buff *skb;
3431 int ret;
3432
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003433 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003434 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003435 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003436
Eliad Pellercdaac622012-01-31 11:57:16 +02003437 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003438 CMD_TEMPL_AP_PROBE_RESPONSE,
3439 skb->data,
3440 skb->len, 0,
3441 rates);
3442
3443 dev_kfree_skb(skb);
3444 return ret;
3445}
3446
3447static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3448 struct ieee80211_vif *vif,
3449 u8 *probe_rsp_data,
3450 size_t probe_rsp_len,
3451 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003452{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003453 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3454 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003455 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3456 int ssid_ie_offset, ie_offset, templ_len;
3457 const u8 *ptr;
3458
3459 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003460 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003461 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003462 CMD_TEMPL_AP_PROBE_RESPONSE,
3463 probe_rsp_data,
3464 probe_rsp_len, 0,
3465 rates);
3466
3467 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3468 wl1271_error("probe_rsp template too big");
3469 return -EINVAL;
3470 }
3471
3472 /* start searching from IE offset */
3473 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3474
3475 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3476 probe_rsp_len - ie_offset);
3477 if (!ptr) {
3478 wl1271_error("No SSID in beacon!");
3479 return -EINVAL;
3480 }
3481
3482 ssid_ie_offset = ptr - probe_rsp_data;
3483 ptr += (ptr[1] + 2);
3484
3485 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3486
3487 /* insert SSID from bss_conf */
3488 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3489 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3490 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3491 bss_conf->ssid, bss_conf->ssid_len);
3492 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3493
3494 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3495 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3496 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3497
Eliad Pellercdaac622012-01-31 11:57:16 +02003498 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003499 CMD_TEMPL_AP_PROBE_RESPONSE,
3500 probe_rsp_templ,
3501 templ_len, 0,
3502 rates);
3503}
3504
Arik Nemtsove78a2872010-10-16 19:07:21 +02003505static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003506 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003507 struct ieee80211_bss_conf *bss_conf,
3508 u32 changed)
3509{
Eliad Peller0603d892011-10-05 11:55:51 +02003510 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 int ret = 0;
3512
3513 if (changed & BSS_CHANGED_ERP_SLOT) {
3514 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003515 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003516 else
Eliad Peller0603d892011-10-05 11:55:51 +02003517 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 if (ret < 0) {
3519 wl1271_warning("Set slot time failed %d", ret);
3520 goto out;
3521 }
3522 }
3523
3524 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3525 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003526 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003527 else
Eliad Peller0603d892011-10-05 11:55:51 +02003528 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 }
3530
3531 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3532 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003533 ret = wl1271_acx_cts_protect(wl, wlvif,
3534 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003535 else
Eliad Peller0603d892011-10-05 11:55:51 +02003536 ret = wl1271_acx_cts_protect(wl, wlvif,
3537 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 if (ret < 0) {
3539 wl1271_warning("Set ctsprotect failed %d", ret);
3540 goto out;
3541 }
3542 }
3543
3544out:
3545 return ret;
3546}
3547
3548static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3549 struct ieee80211_vif *vif,
3550 struct ieee80211_bss_conf *bss_conf,
3551 u32 changed)
3552{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003553 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003554 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 int ret = 0;
3556
3557 if ((changed & BSS_CHANGED_BEACON_INT)) {
3558 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3559 bss_conf->beacon_int);
3560
Eliad Peller6a899792011-10-05 11:55:58 +02003561 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003562 }
3563
Arik Nemtsov560f0022011-11-08 18:46:54 +02003564 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3565 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003566 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3567 wl1271_debug(DEBUG_AP, "probe response updated");
3568 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3569 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003570 }
3571
Arik Nemtsove78a2872010-10-16 19:07:21 +02003572 if ((changed & BSS_CHANGED_BEACON)) {
3573 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003574 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 int ieoffset = offsetof(struct ieee80211_mgmt,
3576 u.beacon.variable);
3577 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3578 u16 tmpl_id;
3579
Arik Nemtsov560f0022011-11-08 18:46:54 +02003580 if (!beacon) {
3581 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003583 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003584
3585 wl1271_debug(DEBUG_MASTER, "beacon updated");
3586
Eliad Peller1fe9f162011-10-05 11:55:48 +02003587 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003588 if (ret < 0) {
3589 dev_kfree_skb(beacon);
3590 goto out;
3591 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003592 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003593 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3594 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003595 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003596 beacon->data,
3597 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003598 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003599 if (ret < 0) {
3600 dev_kfree_skb(beacon);
3601 goto out;
3602 }
3603
Arik Nemtsov560f0022011-11-08 18:46:54 +02003604 /*
3605 * In case we already have a probe-resp beacon set explicitly
3606 * by usermode, don't use the beacon data.
3607 */
3608 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3609 goto end_bcn;
3610
Eliad Pellerd48055d2011-09-15 12:07:04 +03003611 /* remove TIM ie from probe response */
3612 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3613
Eliad Peller26b4bf22011-09-15 12:07:05 +03003614 /*
3615 * remove p2p ie from probe response.
3616 * the fw reponds to probe requests that don't include
3617 * the p2p ie. probe requests with p2p ie will be passed,
3618 * and will be responded by the supplicant (the spec
3619 * forbids including the p2p ie when responding to probe
3620 * requests that didn't include it).
3621 */
3622 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3623 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3624
Arik Nemtsove78a2872010-10-16 19:07:21 +02003625 hdr = (struct ieee80211_hdr *) beacon->data;
3626 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3627 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003628 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003629 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003630 beacon->data,
3631 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003632 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003633 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003634 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003635 CMD_TEMPL_PROBE_RESPONSE,
3636 beacon->data,
3637 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003638 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003639end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003640 dev_kfree_skb(beacon);
3641 if (ret < 0)
3642 goto out;
3643 }
3644
3645out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003646 if (ret != 0)
3647 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003648 return ret;
3649}
3650
3651/* AP mode changes */
3652static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003653 struct ieee80211_vif *vif,
3654 struct ieee80211_bss_conf *bss_conf,
3655 u32 changed)
3656{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003657 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003658 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003659
Arik Nemtsove78a2872010-10-16 19:07:21 +02003660 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3661 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003662
Eliad Peller87fbcb02011-10-05 11:55:41 +02003663 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003664 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003665 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003666 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003667
Eliad Peller87fbcb02011-10-05 11:55:41 +02003668 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003669 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003670 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003671 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003672 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003673
Eliad Peller784f6942011-10-05 11:55:39 +02003674 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003675 if (ret < 0)
3676 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003677 }
3678
Arik Nemtsove78a2872010-10-16 19:07:21 +02003679 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3680 if (ret < 0)
3681 goto out;
3682
3683 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3684 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003685 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003686 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003687 if (ret < 0)
3688 goto out;
3689
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003690 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003691 if (ret < 0)
3692 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003693
Eliad Peller53d40d02011-10-10 10:13:02 +02003694 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003695 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003696 }
3697 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003698 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003699 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003700 if (ret < 0)
3701 goto out;
3702
Eliad Peller53d40d02011-10-10 10:13:02 +02003703 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003704 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3705 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003706 wl1271_debug(DEBUG_AP, "stopped AP");
3707 }
3708 }
3709 }
3710
Eliad Peller0603d892011-10-05 11:55:51 +02003711 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003712 if (ret < 0)
3713 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003714
3715 /* Handle HT information change */
3716 if ((changed & BSS_CHANGED_HT) &&
3717 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003718 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003719 bss_conf->ht_operation_mode);
3720 if (ret < 0) {
3721 wl1271_warning("Set ht information failed %d", ret);
3722 goto out;
3723 }
3724 }
3725
Arik Nemtsove78a2872010-10-16 19:07:21 +02003726out:
3727 return;
3728}
3729
3730/* STA/IBSS mode changes */
3731static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3732 struct ieee80211_vif *vif,
3733 struct ieee80211_bss_conf *bss_conf,
3734 u32 changed)
3735{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003736 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003737 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003738 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003739 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003740 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003741 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003742 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003743 bool sta_exists = false;
3744 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003745
3746 if (is_ibss) {
3747 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3748 changed);
3749 if (ret < 0)
3750 goto out;
3751 }
3752
Eliad Peller227e81e2011-08-14 13:17:26 +03003753 if (changed & BSS_CHANGED_IBSS) {
3754 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003755 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003756 ibss_joined = true;
3757 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003758 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3759 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003760 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003761 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003762 }
3763 }
3764 }
3765
3766 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003767 do_join = true;
3768
3769 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003770 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003771 do_join = true;
3772
Eliad Peller227e81e2011-08-14 13:17:26 +03003773 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003774 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3775 bss_conf->enable_beacon ? "enabled" : "disabled");
3776
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003777 do_join = true;
3778 }
3779
Eliad Pellerc31e4942011-10-23 08:21:55 +02003780 if (changed & BSS_CHANGED_IDLE) {
3781 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3782 if (ret < 0)
3783 wl1271_warning("idle mode change failed %d", ret);
3784 }
3785
Arik Nemtsove78a2872010-10-16 19:07:21 +02003786 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003787 bool enable = false;
3788 if (bss_conf->cqm_rssi_thold)
3789 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003790 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003791 bss_conf->cqm_rssi_thold,
3792 bss_conf->cqm_rssi_hyst);
3793 if (ret < 0)
3794 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003795 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003796 }
3797
Eliad Peller7db4ee62012-01-24 18:18:42 +02003798 if (changed & BSS_CHANGED_BSSID &&
3799 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003800 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003801 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003802 if (ret < 0)
3803 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003804
Eliad Peller784f6942011-10-05 11:55:39 +02003805 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003806 if (ret < 0)
3807 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003808
Eliad Pellerfa287b82010-12-26 09:27:50 +01003809 /* Need to update the BSSID (for filtering etc) */
3810 do_join = true;
3811 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003812
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003813 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3814 rcu_read_lock();
3815 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3816 if (!sta)
3817 goto sta_not_found;
3818
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003819 /* save the supp_rates of the ap */
3820 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3821 if (sta->ht_cap.ht_supported)
3822 sta_rate_set |=
3823 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003824 sta_ht_cap = sta->ht_cap;
3825 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003826
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003827sta_not_found:
3828 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003829 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003830
Arik Nemtsove78a2872010-10-16 19:07:21 +02003831 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003832 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003833 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003834 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003835 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003836 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003837
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003838 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003839 * use basic rates from AP, and determine lowest rate
3840 * to use with control frames.
3841 */
3842 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003843 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003844 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003845 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003846 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003847 wl1271_tx_min_rate_get(wl,
3848 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003849 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003850 wlvif->rate_set =
3851 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003852 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003853 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003854 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003855 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003856 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003857
3858 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003859 * with wl1271, we don't need to update the
3860 * beacon_int and dtim_period, because the firmware
3861 * updates it by itself when the first beacon is
3862 * received after a join.
3863 */
Eliad Peller6840e372011-10-05 11:55:50 +02003864 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003865 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003866 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003867
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003868 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003869 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003870 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003871 dev_kfree_skb(wlvif->probereq);
3872 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003873 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003874 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003875 ieoffset = offsetof(struct ieee80211_mgmt,
3876 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003877 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003878
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003879 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003880 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003881 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003882 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003883 } else {
3884 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003885 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003886 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3887 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003888 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003889 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3890 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003891 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003892
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003893 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003894 dev_kfree_skb(wlvif->probereq);
3895 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003896
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003897 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003898 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003899 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003900 wl1271_tx_min_rate_get(wl,
3901 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003902 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003903 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003904 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003905
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003906 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003907 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003908
3909 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003910 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003911 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003912 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003913
3914 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003915 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003916 u32 conf_flags = wl->hw->conf.flags;
3917 /*
3918 * we might have to disable roc, if there was
3919 * no IF_OPER_UP notification.
3920 */
3921 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003922 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003923 if (ret < 0)
3924 goto out;
3925 }
3926 /*
3927 * (we also need to disable roc in case of
3928 * roaming on the same channel. until we will
3929 * have a better flow...)
3930 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003931 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3932 ret = wl12xx_croc(wl,
3933 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003934 if (ret < 0)
3935 goto out;
3936 }
3937
Eliad Peller0603d892011-10-05 11:55:51 +02003938 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003939 if (!(conf_flags & IEEE80211_CONF_IDLE))
3940 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003941 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003942 }
3943 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003944
Eliad Pellerd192d262011-05-24 14:33:08 +03003945 if (changed & BSS_CHANGED_IBSS) {
3946 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3947 bss_conf->ibss_joined);
3948
3949 if (bss_conf->ibss_joined) {
3950 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003951 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003952 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003953 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003954 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003955 wl1271_tx_min_rate_get(wl,
3956 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003957
Shahar Levi06b660e2011-09-05 13:54:36 +03003958 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003959 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3960 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003961 if (ret < 0)
3962 goto out;
3963 }
3964 }
3965
Eliad Peller0603d892011-10-05 11:55:51 +02003966 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003967 if (ret < 0)
3968 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003969
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003970 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003971 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003972 if (ret < 0) {
3973 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003974 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003975 }
Eliad Peller251c1772011-08-14 13:17:17 +03003976
3977 /* ROC until connected (after EAPOL exchange) */
3978 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003979 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003980 if (ret < 0)
3981 goto out;
3982
Eliad Pellerba8447f2011-10-10 10:13:00 +02003983 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003984 ieee80211_get_operstate(vif));
3985 }
3986 /*
3987 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003988 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003989 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003990 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003991 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003992 if (ret < 0)
3993 goto out;
3994 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003995 }
3996
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003997 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003998 if (sta_exists) {
3999 if ((changed & BSS_CHANGED_HT) &&
4000 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004001 ret = wl1271_acx_set_ht_capabilities(wl,
4002 &sta_ht_cap,
4003 true,
Eliad Peller154da672011-10-05 11:55:53 +02004004 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004005 if (ret < 0) {
4006 wl1271_warning("Set ht cap true failed %d",
4007 ret);
4008 goto out;
4009 }
4010 }
4011 /* handle new association without HT and disassociation */
4012 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004013 ret = wl1271_acx_set_ht_capabilities(wl,
4014 &sta_ht_cap,
4015 false,
Eliad Peller154da672011-10-05 11:55:53 +02004016 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004017 if (ret < 0) {
4018 wl1271_warning("Set ht cap false failed %d",
4019 ret);
4020 goto out;
4021 }
4022 }
4023 }
4024
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004025 /* Handle HT information change. Done after join. */
4026 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004027 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02004028 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004029 bss_conf->ht_operation_mode);
4030 if (ret < 0) {
4031 wl1271_warning("Set ht information failed %d", ret);
4032 goto out;
4033 }
4034 }
4035
Eliad Peller76a74c82012-02-02 12:22:11 +02004036 /* Handle arp filtering. Done after join. */
4037 if ((changed & BSS_CHANGED_ARP_FILTER) ||
4038 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
4039 __be32 addr = bss_conf->arp_addr_list[0];
4040 wlvif->sta.qos = bss_conf->qos;
4041 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
4042
4043 if (bss_conf->arp_addr_cnt == 1 &&
4044 bss_conf->arp_filter_enabled) {
4045 wlvif->ip_addr = addr;
4046 /*
4047 * The template should have been configured only upon
4048 * association. however, it seems that the correct ip
4049 * isn't being set (when sending), so we have to
4050 * reconfigure the template upon every ip change.
4051 */
4052 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
4053 if (ret < 0) {
4054 wl1271_warning("build arp rsp failed: %d", ret);
4055 goto out;
4056 }
4057
4058 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
4059 (ACX_ARP_FILTER_ARP_FILTERING |
4060 ACX_ARP_FILTER_AUTO_ARP),
4061 addr);
4062 } else {
4063 wlvif->ip_addr = 0;
4064 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
4065 }
4066
4067 if (ret < 0)
4068 goto out;
4069 }
4070
Arik Nemtsove78a2872010-10-16 19:07:21 +02004071out:
4072 return;
4073}
4074
4075static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
4076 struct ieee80211_vif *vif,
4077 struct ieee80211_bss_conf *bss_conf,
4078 u32 changed)
4079{
4080 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004081 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4082 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004083 int ret;
4084
4085 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
4086 (int)changed);
4087
4088 mutex_lock(&wl->mutex);
4089
4090 if (unlikely(wl->state == WL1271_STATE_OFF))
4091 goto out;
4092
Eliad Peller10c8cd02011-10-10 10:13:06 +02004093 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
4094 goto out;
4095
Ido Yariva6208652011-03-01 15:14:41 +02004096 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02004097 if (ret < 0)
4098 goto out;
4099
4100 if (is_ap)
4101 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
4102 else
4103 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
4104
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004105 wl1271_ps_elp_sleep(wl);
4106
4107out:
4108 mutex_unlock(&wl->mutex);
4109}
4110
Eliad Peller8a3a3c82011-10-02 10:15:52 +02004111static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
4112 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02004113 const struct ieee80211_tx_queue_params *params)
4114{
4115 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004116 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004117 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004118 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004119
4120 mutex_lock(&wl->mutex);
4121
4122 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4123
Kalle Valo4695dc92010-03-18 12:26:38 +02004124 if (params->uapsd)
4125 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4126 else
4127 ps_scheme = CONF_PS_SCHEME_LEGACY;
4128
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004129 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004130 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004131
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004132 ret = wl1271_ps_elp_wakeup(wl);
4133 if (ret < 0)
4134 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004135
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004136 /*
4137 * the txop is confed in units of 32us by the mac80211,
4138 * we need us
4139 */
Eliad Peller0603d892011-10-05 11:55:51 +02004140 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004141 params->cw_min, params->cw_max,
4142 params->aifs, params->txop << 5);
4143 if (ret < 0)
4144 goto out_sleep;
4145
Eliad Peller0603d892011-10-05 11:55:51 +02004146 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004147 CONF_CHANNEL_TYPE_EDCF,
4148 wl1271_tx_get_queue(queue),
4149 ps_scheme, CONF_ACK_POLICY_LEGACY,
4150 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004151
4152out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004153 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004154
4155out:
4156 mutex_unlock(&wl->mutex);
4157
4158 return ret;
4159}
4160
Eliad Peller37a41b42011-09-21 14:06:11 +03004161static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4162 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004163{
4164
4165 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004166 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004167 u64 mactime = ULLONG_MAX;
4168 int ret;
4169
4170 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4171
4172 mutex_lock(&wl->mutex);
4173
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004174 if (unlikely(wl->state == WL1271_STATE_OFF))
4175 goto out;
4176
Ido Yariva6208652011-03-01 15:14:41 +02004177 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004178 if (ret < 0)
4179 goto out;
4180
Eliad Peller9c531142012-01-31 11:57:18 +02004181 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004182 if (ret < 0)
4183 goto out_sleep;
4184
4185out_sleep:
4186 wl1271_ps_elp_sleep(wl);
4187
4188out:
4189 mutex_unlock(&wl->mutex);
4190 return mactime;
4191}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004192
John W. Linvilleece550d2010-07-28 16:41:06 -04004193static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4194 struct survey_info *survey)
4195{
4196 struct wl1271 *wl = hw->priv;
4197 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004198
John W. Linvilleece550d2010-07-28 16:41:06 -04004199 if (idx != 0)
4200 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004201
John W. Linvilleece550d2010-07-28 16:41:06 -04004202 survey->channel = conf->channel;
4203 survey->filled = SURVEY_INFO_NOISE_DBM;
4204 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004205
John W. Linvilleece550d2010-07-28 16:41:06 -04004206 return 0;
4207}
4208
Arik Nemtsov409622e2011-02-23 00:22:29 +02004209static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004210 struct wl12xx_vif *wlvif,
4211 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004212{
4213 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004214 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004215
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004216
4217 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004218 wl1271_warning("could not allocate HLID - too much stations");
4219 return -EBUSY;
4220 }
4221
4222 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004223 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4224 if (ret < 0) {
4225 wl1271_warning("could not allocate HLID - too many links");
4226 return -EBUSY;
4227 }
4228
4229 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004230 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004231 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004232 return 0;
4233}
4234
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004235void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004236{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004237 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004238 return;
4239
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004240 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004241 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004242 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004243 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004244 __clear_bit(hlid, &wl->ap_ps_map);
4245 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004246 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004247 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004248}
4249
4250static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4251 struct ieee80211_vif *vif,
4252 struct ieee80211_sta *sta)
4253{
4254 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004255 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004256 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004257 int ret = 0;
4258 u8 hlid;
4259
4260 mutex_lock(&wl->mutex);
4261
4262 if (unlikely(wl->state == WL1271_STATE_OFF))
4263 goto out;
4264
Eliad Peller536129c2011-10-05 11:55:45 +02004265 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004266 goto out;
4267
4268 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4269
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004270 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004271 if (ret < 0)
4272 goto out;
4273
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004274 wl_sta = (struct wl1271_station *)sta->drv_priv;
4275 hlid = wl_sta->hlid;
4276
Ido Yariva6208652011-03-01 15:14:41 +02004277 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004278 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004279 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004280
Eliad Peller1b92f152011-10-10 10:13:09 +02004281 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004282 if (ret < 0)
4283 goto out_sleep;
4284
Eliad Pellerb67476e2011-08-14 13:17:23 +03004285 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4286 if (ret < 0)
4287 goto out_sleep;
4288
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004289 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4290 if (ret < 0)
4291 goto out_sleep;
4292
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004293out_sleep:
4294 wl1271_ps_elp_sleep(wl);
4295
Arik Nemtsov409622e2011-02-23 00:22:29 +02004296out_free_sta:
4297 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004298 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004299
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004300out:
4301 mutex_unlock(&wl->mutex);
4302 return ret;
4303}
4304
4305static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4306 struct ieee80211_vif *vif,
4307 struct ieee80211_sta *sta)
4308{
4309 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004310 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004311 struct wl1271_station *wl_sta;
4312 int ret = 0, id;
4313
4314 mutex_lock(&wl->mutex);
4315
4316 if (unlikely(wl->state == WL1271_STATE_OFF))
4317 goto out;
4318
Eliad Peller536129c2011-10-05 11:55:45 +02004319 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004320 goto out;
4321
4322 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4323
4324 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004325 id = wl_sta->hlid;
4326 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004327 goto out;
4328
Ido Yariva6208652011-03-01 15:14:41 +02004329 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004330 if (ret < 0)
4331 goto out;
4332
Eliad Pellerc690ec82011-08-14 13:17:07 +03004333 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004334 if (ret < 0)
4335 goto out_sleep;
4336
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004337 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004338
4339out_sleep:
4340 wl1271_ps_elp_sleep(wl);
4341
4342out:
4343 mutex_unlock(&wl->mutex);
4344 return ret;
4345}
4346
Luciano Coelho4623ec72011-03-21 19:26:41 +02004347static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4348 struct ieee80211_vif *vif,
4349 enum ieee80211_ampdu_mlme_action action,
4350 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4351 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004352{
4353 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004354 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004355 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004356 u8 hlid, *ba_bitmap;
4357
4358 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4359 tid);
4360
4361 /* sanity check - the fields in FW are only 8bits wide */
4362 if (WARN_ON(tid > 0xFF))
4363 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004364
4365 mutex_lock(&wl->mutex);
4366
4367 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4368 ret = -EAGAIN;
4369 goto out;
4370 }
4371
Eliad Peller536129c2011-10-05 11:55:45 +02004372 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004373 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004374 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004375 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004376 struct wl1271_station *wl_sta;
4377
4378 wl_sta = (struct wl1271_station *)sta->drv_priv;
4379 hlid = wl_sta->hlid;
4380 ba_bitmap = &wl->links[hlid].ba_bitmap;
4381 } else {
4382 ret = -EINVAL;
4383 goto out;
4384 }
4385
Ido Yariva6208652011-03-01 15:14:41 +02004386 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004387 if (ret < 0)
4388 goto out;
4389
Shahar Levi70559a02011-05-22 16:10:22 +03004390 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4391 tid, action);
4392
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004393 switch (action) {
4394 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004395 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004396 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004397 break;
4398 }
4399
4400 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4401 ret = -EBUSY;
4402 wl1271_error("exceeded max RX BA sessions");
4403 break;
4404 }
4405
4406 if (*ba_bitmap & BIT(tid)) {
4407 ret = -EINVAL;
4408 wl1271_error("cannot enable RX BA session on active "
4409 "tid: %d", tid);
4410 break;
4411 }
4412
4413 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4414 hlid);
4415 if (!ret) {
4416 *ba_bitmap |= BIT(tid);
4417 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004418 }
4419 break;
4420
4421 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004422 if (!(*ba_bitmap & BIT(tid))) {
4423 ret = -EINVAL;
4424 wl1271_error("no active RX BA session on tid: %d",
4425 tid);
4426 break;
4427 }
4428
4429 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4430 hlid);
4431 if (!ret) {
4432 *ba_bitmap &= ~BIT(tid);
4433 wl->ba_rx_session_count--;
4434 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004435 break;
4436
4437 /*
4438 * The BA initiator session management in FW independently.
4439 * Falling break here on purpose for all TX APDU commands.
4440 */
4441 case IEEE80211_AMPDU_TX_START:
4442 case IEEE80211_AMPDU_TX_STOP:
4443 case IEEE80211_AMPDU_TX_OPERATIONAL:
4444 ret = -EINVAL;
4445 break;
4446
4447 default:
4448 wl1271_error("Incorrect ampdu action id=%x\n", action);
4449 ret = -EINVAL;
4450 }
4451
4452 wl1271_ps_elp_sleep(wl);
4453
4454out:
4455 mutex_unlock(&wl->mutex);
4456
4457 return ret;
4458}
4459
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004460static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4461 struct ieee80211_vif *vif,
4462 const struct cfg80211_bitrate_mask *mask)
4463{
Eliad Peller83587502011-10-10 10:12:53 +02004464 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004465 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004466 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004467
4468 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4469 mask->control[NL80211_BAND_2GHZ].legacy,
4470 mask->control[NL80211_BAND_5GHZ].legacy);
4471
4472 mutex_lock(&wl->mutex);
4473
4474 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004475 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004476 wl1271_tx_enabled_rates_get(wl,
4477 mask->control[i].legacy,
4478 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004479
4480 if (unlikely(wl->state == WL1271_STATE_OFF))
4481 goto out;
4482
4483 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4484 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4485
4486 ret = wl1271_ps_elp_wakeup(wl);
4487 if (ret < 0)
4488 goto out;
4489
4490 wl1271_set_band_rate(wl, wlvif);
4491 wlvif->basic_rate =
4492 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4493 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4494
4495 wl1271_ps_elp_sleep(wl);
4496 }
4497out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004498 mutex_unlock(&wl->mutex);
4499
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004500 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004501}
4502
Shahar Levi6d158ff2011-09-08 13:01:33 +03004503static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4504 struct ieee80211_channel_switch *ch_switch)
4505{
4506 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004507 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004508 int ret;
4509
4510 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4511
4512 mutex_lock(&wl->mutex);
4513
4514 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004515 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4516 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4517 ieee80211_chswitch_done(vif, false);
4518 }
4519 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004520 }
4521
4522 ret = wl1271_ps_elp_wakeup(wl);
4523 if (ret < 0)
4524 goto out;
4525
Eliad Peller52630c52011-10-10 10:13:08 +02004526 /* TODO: change mac80211 to pass vif as param */
4527 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004528 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004529
Eliad Peller52630c52011-10-10 10:13:08 +02004530 if (!ret)
4531 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4532 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004533
4534 wl1271_ps_elp_sleep(wl);
4535
4536out:
4537 mutex_unlock(&wl->mutex);
4538}
4539
Arik Nemtsov33437892011-04-26 23:35:39 +03004540static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4541{
4542 struct wl1271 *wl = hw->priv;
4543 bool ret = false;
4544
4545 mutex_lock(&wl->mutex);
4546
4547 if (unlikely(wl->state == WL1271_STATE_OFF))
4548 goto out;
4549
4550 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004551 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004552out:
4553 mutex_unlock(&wl->mutex);
4554
4555 return ret;
4556}
4557
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004558/* can't be const, mac80211 writes to this */
4559static struct ieee80211_rate wl1271_rates[] = {
4560 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004561 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4562 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004563 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004564 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4565 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004566 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4567 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004568 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4569 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004570 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4571 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004572 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4573 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004574 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4575 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004576 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4577 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004578 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004579 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4580 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004581 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004582 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4583 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004584 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004585 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4586 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004587 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004588 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4589 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004590 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004591 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4592 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004593 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004594 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4595 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004596 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004597 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4598 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004599};
4600
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004601/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004602static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004603 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004604 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004605 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4606 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4607 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004608 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004609 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4610 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4611 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004612 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004613 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4614 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4615 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004616 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004617};
4618
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004619/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004620static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004621 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004622 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004623 7, /* CONF_HW_RXTX_RATE_MCS7 */
4624 6, /* CONF_HW_RXTX_RATE_MCS6 */
4625 5, /* CONF_HW_RXTX_RATE_MCS5 */
4626 4, /* CONF_HW_RXTX_RATE_MCS4 */
4627 3, /* CONF_HW_RXTX_RATE_MCS3 */
4628 2, /* CONF_HW_RXTX_RATE_MCS2 */
4629 1, /* CONF_HW_RXTX_RATE_MCS1 */
4630 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004631
4632 11, /* CONF_HW_RXTX_RATE_54 */
4633 10, /* CONF_HW_RXTX_RATE_48 */
4634 9, /* CONF_HW_RXTX_RATE_36 */
4635 8, /* CONF_HW_RXTX_RATE_24 */
4636
4637 /* TI-specific rate */
4638 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4639
4640 7, /* CONF_HW_RXTX_RATE_18 */
4641 6, /* CONF_HW_RXTX_RATE_12 */
4642 3, /* CONF_HW_RXTX_RATE_11 */
4643 5, /* CONF_HW_RXTX_RATE_9 */
4644 4, /* CONF_HW_RXTX_RATE_6 */
4645 2, /* CONF_HW_RXTX_RATE_5_5 */
4646 1, /* CONF_HW_RXTX_RATE_2 */
4647 0 /* CONF_HW_RXTX_RATE_1 */
4648};
4649
Shahar Levie8b03a22010-10-13 16:09:39 +02004650/* 11n STA capabilities */
4651#define HW_RX_HIGHEST_RATE 72
4652
Shahar Levi00d20102010-11-08 11:20:10 +00004653#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004654 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4655 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004656 .ht_supported = true, \
4657 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4658 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4659 .mcs = { \
4660 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4661 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4662 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4663 }, \
4664}
4665
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666/* can't be const, mac80211 writes to this */
4667static struct ieee80211_supported_band wl1271_band_2ghz = {
4668 .channels = wl1271_channels,
4669 .n_channels = ARRAY_SIZE(wl1271_channels),
4670 .bitrates = wl1271_rates,
4671 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004672 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004673};
4674
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004675/* 5 GHz data rates for WL1273 */
4676static struct ieee80211_rate wl1271_rates_5ghz[] = {
4677 { .bitrate = 60,
4678 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4679 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4680 { .bitrate = 90,
4681 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4682 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4683 { .bitrate = 120,
4684 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4685 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4686 { .bitrate = 180,
4687 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4688 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4689 { .bitrate = 240,
4690 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4691 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4692 { .bitrate = 360,
4693 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4694 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4695 { .bitrate = 480,
4696 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4697 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4698 { .bitrate = 540,
4699 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4700 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4701};
4702
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004703/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004704static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004705 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4706 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4707 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4708 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4709 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4710 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4711 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4712 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4713 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4714 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4715 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4716 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4717 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4718 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4719 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4720 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4721 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4722 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4723 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4724 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4725 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4726 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4727 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4728 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4729 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4730 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4731 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4732 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4733 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4734 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4735 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4736 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4737 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4738 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004739};
4740
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004741/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004742static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004743 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004744 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004745 7, /* CONF_HW_RXTX_RATE_MCS7 */
4746 6, /* CONF_HW_RXTX_RATE_MCS6 */
4747 5, /* CONF_HW_RXTX_RATE_MCS5 */
4748 4, /* CONF_HW_RXTX_RATE_MCS4 */
4749 3, /* CONF_HW_RXTX_RATE_MCS3 */
4750 2, /* CONF_HW_RXTX_RATE_MCS2 */
4751 1, /* CONF_HW_RXTX_RATE_MCS1 */
4752 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004753
4754 7, /* CONF_HW_RXTX_RATE_54 */
4755 6, /* CONF_HW_RXTX_RATE_48 */
4756 5, /* CONF_HW_RXTX_RATE_36 */
4757 4, /* CONF_HW_RXTX_RATE_24 */
4758
4759 /* TI-specific rate */
4760 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4761
4762 3, /* CONF_HW_RXTX_RATE_18 */
4763 2, /* CONF_HW_RXTX_RATE_12 */
4764 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4765 1, /* CONF_HW_RXTX_RATE_9 */
4766 0, /* CONF_HW_RXTX_RATE_6 */
4767 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4768 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4769 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4770};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004771
4772static struct ieee80211_supported_band wl1271_band_5ghz = {
4773 .channels = wl1271_channels_5ghz,
4774 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4775 .bitrates = wl1271_rates_5ghz,
4776 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004777 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004778};
4779
Tobias Klausera0ea9492010-05-20 10:38:11 +02004780static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004781 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4782 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4783};
4784
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004785static const struct ieee80211_ops wl1271_ops = {
4786 .start = wl1271_op_start,
4787 .stop = wl1271_op_stop,
4788 .add_interface = wl1271_op_add_interface,
4789 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004790 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004791#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004792 .suspend = wl1271_op_suspend,
4793 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004794#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004795 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004796 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004797 .configure_filter = wl1271_op_configure_filter,
4798 .tx = wl1271_op_tx,
4799 .set_key = wl1271_op_set_key,
4800 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004801 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004802 .sched_scan_start = wl1271_op_sched_scan_start,
4803 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004804 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004805 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004806 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004807 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004808 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004809 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004810 .sta_add = wl1271_op_sta_add,
4811 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004812 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004813 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004814 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004815 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004816 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004817};
4818
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004819
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004820u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004821{
4822 u8 idx;
4823
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004824 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004825
4826 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4827 wl1271_error("Illegal RX rate from HW: %d", rate);
4828 return 0;
4829 }
4830
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004831 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004832 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4833 wl1271_error("Unsupported RX rate from HW: %d", rate);
4834 return 0;
4835 }
4836
4837 return idx;
4838}
4839
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004840static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4841 struct device_attribute *attr,
4842 char *buf)
4843{
4844 struct wl1271 *wl = dev_get_drvdata(dev);
4845 ssize_t len;
4846
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004847 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004848
4849 mutex_lock(&wl->mutex);
4850 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4851 wl->sg_enabled);
4852 mutex_unlock(&wl->mutex);
4853
4854 return len;
4855
4856}
4857
4858static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4859 struct device_attribute *attr,
4860 const char *buf, size_t count)
4861{
4862 struct wl1271 *wl = dev_get_drvdata(dev);
4863 unsigned long res;
4864 int ret;
4865
Luciano Coelho6277ed62011-04-01 17:49:54 +03004866 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004867 if (ret < 0) {
4868 wl1271_warning("incorrect value written to bt_coex_mode");
4869 return count;
4870 }
4871
4872 mutex_lock(&wl->mutex);
4873
4874 res = !!res;
4875
4876 if (res == wl->sg_enabled)
4877 goto out;
4878
4879 wl->sg_enabled = res;
4880
4881 if (wl->state == WL1271_STATE_OFF)
4882 goto out;
4883
Ido Yariva6208652011-03-01 15:14:41 +02004884 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004885 if (ret < 0)
4886 goto out;
4887
4888 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4889 wl1271_ps_elp_sleep(wl);
4890
4891 out:
4892 mutex_unlock(&wl->mutex);
4893 return count;
4894}
4895
4896static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4897 wl1271_sysfs_show_bt_coex_state,
4898 wl1271_sysfs_store_bt_coex_state);
4899
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004900static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4901 struct device_attribute *attr,
4902 char *buf)
4903{
4904 struct wl1271 *wl = dev_get_drvdata(dev);
4905 ssize_t len;
4906
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004907 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004908
4909 mutex_lock(&wl->mutex);
4910 if (wl->hw_pg_ver >= 0)
4911 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4912 else
4913 len = snprintf(buf, len, "n/a\n");
4914 mutex_unlock(&wl->mutex);
4915
4916 return len;
4917}
4918
Gery Kahn6f07b722011-07-18 14:21:49 +03004919static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004920 wl1271_sysfs_show_hw_pg_ver, NULL);
4921
Ido Yariv95dac04f2011-06-06 14:57:06 +03004922static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4923 struct bin_attribute *bin_attr,
4924 char *buffer, loff_t pos, size_t count)
4925{
4926 struct device *dev = container_of(kobj, struct device, kobj);
4927 struct wl1271 *wl = dev_get_drvdata(dev);
4928 ssize_t len;
4929 int ret;
4930
4931 ret = mutex_lock_interruptible(&wl->mutex);
4932 if (ret < 0)
4933 return -ERESTARTSYS;
4934
4935 /* Let only one thread read the log at a time, blocking others */
4936 while (wl->fwlog_size == 0) {
4937 DEFINE_WAIT(wait);
4938
4939 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4940 &wait,
4941 TASK_INTERRUPTIBLE);
4942
4943 if (wl->fwlog_size != 0) {
4944 finish_wait(&wl->fwlog_waitq, &wait);
4945 break;
4946 }
4947
4948 mutex_unlock(&wl->mutex);
4949
4950 schedule();
4951 finish_wait(&wl->fwlog_waitq, &wait);
4952
4953 if (signal_pending(current))
4954 return -ERESTARTSYS;
4955
4956 ret = mutex_lock_interruptible(&wl->mutex);
4957 if (ret < 0)
4958 return -ERESTARTSYS;
4959 }
4960
4961 /* Check if the fwlog is still valid */
4962 if (wl->fwlog_size < 0) {
4963 mutex_unlock(&wl->mutex);
4964 return 0;
4965 }
4966
4967 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4968 len = min(count, (size_t)wl->fwlog_size);
4969 wl->fwlog_size -= len;
4970 memcpy(buffer, wl->fwlog, len);
4971
4972 /* Make room for new messages */
4973 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4974
4975 mutex_unlock(&wl->mutex);
4976
4977 return len;
4978}
4979
4980static struct bin_attribute fwlog_attr = {
4981 .attr = {.name = "fwlog", .mode = S_IRUSR},
4982 .read = wl1271_sysfs_read_fwlog,
4983};
4984
Luciano Coelho5e037e72011-12-23 09:32:17 +02004985static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4986{
4987 bool supported = false;
4988 u8 major, minor;
4989
4990 if (wl->chip.id == CHIP_ID_1283_PG20) {
4991 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4992 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4993
4994 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4995 if (major > 2 || (major == 2 && minor >= 1))
4996 supported = true;
4997 } else {
4998 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4999 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
5000
5001 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
5002 if (major == 3 && minor >= 1)
5003 supported = true;
5004 }
5005
5006 wl1271_debug(DEBUG_PROBE,
5007 "PG Ver major = %d minor = %d, MAC %s present",
5008 major, minor, supported ? "is" : "is not");
5009
5010 return supported;
5011}
5012
5013static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
5014 u32 oui, u32 nic, int n)
5015{
5016 int i;
5017
5018 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
5019 oui, nic, n);
5020
5021 if (nic + n - 1 > 0xffffff)
5022 wl1271_warning("NIC part of the MAC address wraps around!");
5023
5024 for (i = 0; i < n; i++) {
5025 wl->addresses[i].addr[0] = (u8)(oui >> 16);
5026 wl->addresses[i].addr[1] = (u8)(oui >> 8);
5027 wl->addresses[i].addr[2] = (u8) oui;
5028 wl->addresses[i].addr[3] = (u8)(nic >> 16);
5029 wl->addresses[i].addr[4] = (u8)(nic >> 8);
5030 wl->addresses[i].addr[5] = (u8) nic;
5031 nic++;
5032 }
5033
5034 wl->hw->wiphy->n_addresses = n;
5035 wl->hw->wiphy->addresses = wl->addresses;
5036}
5037
5038static void wl12xx_get_fuse_mac(struct wl1271 *wl)
5039{
5040 u32 mac1, mac2;
5041
5042 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
5043
5044 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
5045 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
5046
5047 /* these are the two parts of the BD_ADDR */
5048 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
5049 ((mac1 & 0xff000000) >> 24);
5050 wl->fuse_nic_addr = mac1 & 0xffffff;
5051
5052 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
5053}
5054
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005055static int wl12xx_get_hw_info(struct wl1271 *wl)
5056{
5057 int ret;
5058 u32 die_info;
5059
5060 ret = wl12xx_set_power_on(wl);
5061 if (ret < 0)
5062 goto out;
5063
5064 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
5065
5066 if (wl->chip.id == CHIP_ID_1283_PG20)
5067 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
5068 else
5069 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
5070
5071 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
5072
Luciano Coelho5e037e72011-12-23 09:32:17 +02005073 if (!wl12xx_mac_in_fuse(wl)) {
5074 wl->fuse_oui_addr = 0;
5075 wl->fuse_nic_addr = 0;
5076 } else {
5077 wl12xx_get_fuse_mac(wl);
5078 }
5079
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005080 wl1271_power_off(wl);
5081out:
5082 return ret;
5083}
5084
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005085static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005086{
5087 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02005088 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005089
5090 if (wl->mac80211_registered)
5091 return 0;
5092
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005093 ret = wl12xx_get_hw_info(wl);
5094 if (ret < 0) {
5095 wl1271_error("couldn't get hw info");
5096 goto out;
5097 }
5098
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005099 ret = wl1271_fetch_nvs(wl);
5100 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02005101 /* NOTE: The wl->nvs->nvs element must be first, in
5102 * order to simplify the casting, we assume it is at
5103 * the beginning of the wl->nvs structure.
5104 */
5105 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005106
Luciano Coelho5e037e72011-12-23 09:32:17 +02005107 oui_addr =
5108 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
5109 nic_addr =
5110 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02005111 }
5112
Luciano Coelho5e037e72011-12-23 09:32:17 +02005113 /* if the MAC address is zeroed in the NVS derive from fuse */
5114 if (oui_addr == 0 && nic_addr == 0) {
5115 oui_addr = wl->fuse_oui_addr;
5116 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
5117 nic_addr = wl->fuse_nic_addr + 1;
5118 }
5119
5120 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005121
5122 ret = ieee80211_register_hw(wl->hw);
5123 if (ret < 0) {
5124 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005125 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005126 }
5127
5128 wl->mac80211_registered = true;
5129
Eliad Pellerd60080a2010-11-24 12:53:16 +02005130 wl1271_debugfs_init(wl);
5131
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005132 register_netdevice_notifier(&wl1271_dev_notifier);
5133
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005134 wl1271_notice("loaded");
5135
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005136out:
5137 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005138}
5139
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005140static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005141{
Eliad Peller3fcdab72012-02-06 12:47:54 +02005142 if (wl->plt)
Ido Yarivf3df1332012-01-11 09:42:39 +02005143 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005144
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005145 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005146 ieee80211_unregister_hw(wl->hw);
5147 wl->mac80211_registered = false;
5148
5149}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005150
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005151static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005152{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005153 static const u32 cipher_suites[] = {
5154 WLAN_CIPHER_SUITE_WEP40,
5155 WLAN_CIPHER_SUITE_WEP104,
5156 WLAN_CIPHER_SUITE_TKIP,
5157 WLAN_CIPHER_SUITE_CCMP,
5158 WL1271_CIPHER_SUITE_GEM,
5159 };
5160
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005161 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02005162 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005163 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005164
5165 /* unit us */
5166 /* FIXME: find a proper value */
5167 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005168 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005169
5170 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005171 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005172 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005173 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005174 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005175 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005176 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005177 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005178 IEEE80211_HW_AP_LINK_PS |
5179 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005180 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
5181 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005182
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005183 wl->hw->wiphy->cipher_suites = cipher_suites;
5184 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5185
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005186 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005187 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5188 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005189 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005190 wl->hw->wiphy->max_sched_scan_ssids = 16;
5191 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005192 /*
5193 * Maximum length of elements in scanning probe request templates
5194 * should be the maximum length possible for a template, without
5195 * the IEEE80211 header of the template
5196 */
Ido Reisc08e3712012-02-02 13:54:27 +02005197 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005198 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005199
Ido Reisc08e3712012-02-02 13:54:27 +02005200 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005201 sizeof(struct ieee80211_header);
5202
Eliad Peller1ec23f72011-08-25 14:26:54 +03005203 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5204
Luciano Coelho4a31c112011-03-21 23:16:14 +02005205 /* make sure all our channels fit in the scanned_ch bitmask */
5206 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5207 ARRAY_SIZE(wl1271_channels_5ghz) >
5208 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005209 /*
5210 * We keep local copies of the band structs because we need to
5211 * modify them on a per-device basis.
5212 */
5213 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5214 sizeof(wl1271_band_2ghz));
5215 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5216 sizeof(wl1271_band_5ghz));
5217
5218 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5219 &wl->bands[IEEE80211_BAND_2GHZ];
5220 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5221 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005222
Kalle Valo12bd8942010-03-18 12:26:33 +02005223 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005224 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005225
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005226 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5227
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005228 /* the FW answers probe-requests in AP-mode */
5229 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5230 wl->hw->wiphy->probe_resp_offload =
5231 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5232 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5233 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5234
Felipe Balbia390e852011-10-06 10:07:44 +03005235 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005236
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005237 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005238 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005239
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005240 wl->hw->max_rx_aggregation_subframes = 8;
5241
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005242 return 0;
5243}
5244
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005245#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005246
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005247static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005248{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005249 struct ieee80211_hw *hw;
5250 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005251 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005252 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005253
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005254 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005255
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005256 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5257 if (!hw) {
5258 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005259 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005260 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005261 }
5262
5263 wl = hw->priv;
5264 memset(wl, 0, sizeof(*wl));
5265
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005266 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005267 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005268
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005269 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005270
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005271 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005272 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005273 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5274
Ido Yariva6208652011-03-01 15:14:41 +02005275 skb_queue_head_init(&wl->deferred_rx_queue);
5276 skb_queue_head_init(&wl->deferred_tx_queue);
5277
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005278 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005279 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005280 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5281 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5282 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005283
Eliad Peller92ef8962011-06-07 12:50:46 +03005284 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5285 if (!wl->freezable_wq) {
5286 ret = -ENOMEM;
5287 goto err_hw;
5288 }
5289
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005290 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005291 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005292 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005293 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005294 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005295 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005296 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005297 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005298 wl->ap_ps_map = 0;
5299 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005300 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005301 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005302 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005303 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005304 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005305 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005306 wl->fwlog_size = 0;
5307 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005308
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005309 /* The system link is always allocated */
5310 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5311
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005312 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005313 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005314 wl->tx_frames[i] = NULL;
5315
5316 spin_lock_init(&wl->wl_lock);
5317
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005318 wl->state = WL1271_STATE_OFF;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005319 wl->fw_type = WL12XX_FW_TYPE_NONE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005320 mutex_init(&wl->mutex);
5321
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005322 /* Apply default driver configuration. */
5323 wl1271_conf_init(wl);
5324
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005325 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5326 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5327 if (!wl->aggr_buf) {
5328 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005329 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005330 }
5331
Ido Yariv990f5de2011-03-31 10:06:59 +02005332 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5333 if (!wl->dummy_packet) {
5334 ret = -ENOMEM;
5335 goto err_aggr;
5336 }
5337
Ido Yariv95dac04f2011-06-06 14:57:06 +03005338 /* Allocate one page for the FW log */
5339 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5340 if (!wl->fwlog) {
5341 ret = -ENOMEM;
5342 goto err_dummy_packet;
5343 }
5344
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005345 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005346
Ido Yariv990f5de2011-03-31 10:06:59 +02005347err_dummy_packet:
5348 dev_kfree_skb(wl->dummy_packet);
5349
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005350err_aggr:
5351 free_pages((unsigned long)wl->aggr_buf, order);
5352
Eliad Peller92ef8962011-06-07 12:50:46 +03005353err_wq:
5354 destroy_workqueue(wl->freezable_wq);
5355
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005356err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005357 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005358 ieee80211_free_hw(hw);
5359
5360err_hw_alloc:
5361
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005362 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005363}
5364
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005365static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005366{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005367 /* Unblock any fwlog readers */
5368 mutex_lock(&wl->mutex);
5369 wl->fwlog_size = -1;
5370 wake_up_interruptible_all(&wl->fwlog_waitq);
5371 mutex_unlock(&wl->mutex);
5372
Felipe Balbif79f8902011-10-06 13:05:25 +03005373 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005374
Felipe Balbif79f8902011-10-06 13:05:25 +03005375 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005376
Felipe Balbif79f8902011-10-06 13:05:25 +03005377 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005378 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005379 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005380 free_pages((unsigned long)wl->aggr_buf,
5381 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005382
5383 wl1271_debugfs_exit(wl);
5384
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005385 vfree(wl->fw);
5386 wl->fw = NULL;
Eliad Peller3fcdab72012-02-06 12:47:54 +02005387 wl->fw_type = WL12XX_FW_TYPE_NONE;
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005388 kfree(wl->nvs);
5389 wl->nvs = NULL;
5390
5391 kfree(wl->fw_status);
5392 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005393 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005394
5395 ieee80211_free_hw(wl->hw);
5396
5397 return 0;
5398}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005399
Felipe Balbia390e852011-10-06 10:07:44 +03005400static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5401{
5402 struct wl1271 *wl = cookie;
5403 unsigned long flags;
5404
5405 wl1271_debug(DEBUG_IRQ, "IRQ");
5406
5407 /* complete the ELP completion */
5408 spin_lock_irqsave(&wl->wl_lock, flags);
5409 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5410 if (wl->elp_compl) {
5411 complete(wl->elp_compl);
5412 wl->elp_compl = NULL;
5413 }
5414
5415 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5416 /* don't enqueue a work right now. mark it as pending */
5417 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5418 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5419 disable_irq_nosync(wl->irq);
5420 pm_wakeup_event(wl->dev, 0);
5421 spin_unlock_irqrestore(&wl->wl_lock, flags);
5422 return IRQ_HANDLED;
5423 }
5424 spin_unlock_irqrestore(&wl->wl_lock, flags);
5425
5426 return IRQ_WAKE_THREAD;
5427}
5428
Felipe Balbice2a2172011-10-05 14:12:55 +03005429static int __devinit wl12xx_probe(struct platform_device *pdev)
5430{
Felipe Balbia390e852011-10-06 10:07:44 +03005431 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5432 struct ieee80211_hw *hw;
5433 struct wl1271 *wl;
5434 unsigned long irqflags;
5435 int ret = -ENODEV;
5436
5437 hw = wl1271_alloc_hw();
5438 if (IS_ERR(hw)) {
5439 wl1271_error("can't allocate hw");
5440 ret = PTR_ERR(hw);
5441 goto out;
5442 }
5443
5444 wl = hw->priv;
5445 wl->irq = platform_get_irq(pdev, 0);
5446 wl->ref_clock = pdata->board_ref_clock;
5447 wl->tcxo_clock = pdata->board_tcxo_clock;
5448 wl->platform_quirks = pdata->platform_quirks;
5449 wl->set_power = pdata->set_power;
5450 wl->dev = &pdev->dev;
5451 wl->if_ops = pdata->ops;
5452
5453 platform_set_drvdata(pdev, wl);
5454
5455 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5456 irqflags = IRQF_TRIGGER_RISING;
5457 else
5458 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5459
5460 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5461 irqflags,
5462 pdev->name, wl);
5463 if (ret < 0) {
5464 wl1271_error("request_irq() failed: %d", ret);
5465 goto out_free_hw;
5466 }
5467
5468 ret = enable_irq_wake(wl->irq);
5469 if (!ret) {
5470 wl->irq_wake_enabled = true;
5471 device_init_wakeup(wl->dev, 1);
5472 if (pdata->pwr_in_suspend)
5473 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5474
5475 }
5476 disable_irq(wl->irq);
5477
5478 ret = wl1271_init_ieee80211(wl);
5479 if (ret)
5480 goto out_irq;
5481
5482 ret = wl1271_register_hw(wl);
5483 if (ret)
5484 goto out_irq;
5485
Felipe Balbif79f8902011-10-06 13:05:25 +03005486 /* Create sysfs file to control bt coex state */
5487 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5488 if (ret < 0) {
5489 wl1271_error("failed to create sysfs file bt_coex_state");
5490 goto out_irq;
5491 }
5492
5493 /* Create sysfs file to get HW PG version */
5494 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5495 if (ret < 0) {
5496 wl1271_error("failed to create sysfs file hw_pg_ver");
5497 goto out_bt_coex_state;
5498 }
5499
5500 /* Create sysfs file for the FW log */
5501 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5502 if (ret < 0) {
5503 wl1271_error("failed to create sysfs file fwlog");
5504 goto out_hw_pg_ver;
5505 }
5506
Felipe Balbice2a2172011-10-05 14:12:55 +03005507 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005508
Felipe Balbif79f8902011-10-06 13:05:25 +03005509out_hw_pg_ver:
5510 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5511
5512out_bt_coex_state:
5513 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5514
Felipe Balbia390e852011-10-06 10:07:44 +03005515out_irq:
5516 free_irq(wl->irq, wl);
5517
5518out_free_hw:
5519 wl1271_free_hw(wl);
5520
5521out:
5522 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005523}
5524
5525static int __devexit wl12xx_remove(struct platform_device *pdev)
5526{
Felipe Balbia390e852011-10-06 10:07:44 +03005527 struct wl1271 *wl = platform_get_drvdata(pdev);
5528
5529 if (wl->irq_wake_enabled) {
5530 device_init_wakeup(wl->dev, 0);
5531 disable_irq_wake(wl->irq);
5532 }
5533 wl1271_unregister_hw(wl);
5534 free_irq(wl->irq, wl);
5535 wl1271_free_hw(wl);
5536
Felipe Balbice2a2172011-10-05 14:12:55 +03005537 return 0;
5538}
5539
5540static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005541 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005542 { } /* Terminating Entry */
5543};
5544MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5545
5546static struct platform_driver wl12xx_driver = {
5547 .probe = wl12xx_probe,
5548 .remove = __devexit_p(wl12xx_remove),
5549 .id_table = wl12xx_id_table,
5550 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005551 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005552 .owner = THIS_MODULE,
5553 }
5554};
5555
5556static int __init wl12xx_init(void)
5557{
5558 return platform_driver_register(&wl12xx_driver);
5559}
5560module_init(wl12xx_init);
5561
5562static void __exit wl12xx_exit(void)
5563{
5564 platform_driver_unregister(&wl12xx_driver);
5565}
5566module_exit(wl12xx_exit);
5567
Guy Eilam491bbd62011-01-12 10:33:29 +01005568u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005569EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005570module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005571MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5572
Ido Yariv95dac04f2011-06-06 14:57:06 +03005573module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005574MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005575 "FW logger options: continuous, ondemand, dbgpins or disable");
5576
Eliad Peller2a5bff02011-08-25 18:10:59 +03005577module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5578MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5579
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005580MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005581MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005582MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");