blob: 253847ff344bca804fc33dc7cc42d20cbfa127b5 [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,
275 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300276 .sched_scan = {
277 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300278 .min_dwell_time_active = 30,
279 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300280 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300281 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300282 .num_probe_reqs = 2,
283 .rssi_threshold = -90,
284 .snr_threshold = 0,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100296 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300297 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300300 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100301 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200303 .num_stations = 1,
304 .ssid_profiles = 1,
305 .rx_block_num = 70,
306 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300307 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200308 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200309 .min_req_rx_blocks = 22,
310 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200311 },
312 .mem_wl128x = {
313 .num_stations = 1,
314 .ssid_profiles = 1,
315 .rx_block_num = 40,
316 .tx_min_block_num = 40,
317 .dynamic_memory = 1,
318 .min_req_tx_blocks = 45,
319 .min_req_rx_blocks = 22,
320 .tx_min = 27,
321 },
Shahar Leviff868432011-04-11 15:41:46 +0300322 .fm_coex = {
323 .enable = true,
324 .swallow_period = 5,
325 .n_divider_fref_set_1 = 0xff, /* default */
326 .n_divider_fref_set_2 = 12,
327 .m_divider_fref_set_1 = 148,
328 .m_divider_fref_set_2 = 0xffff, /* default */
329 .coex_pll_stabilization_time = 0xffffffff, /* default */
330 .ldo_stabilization_time = 0xffff, /* default */
331 .fm_disturbed_band_margin = 0xff, /* default */
332 .swallow_clk_diff = 0xff, /* default */
333 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300334 .rx_streaming = {
335 .duration = 150,
336 .queues = 0x1,
337 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300338 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300339 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300340 .fwlog = {
341 .mode = WL12XX_FWLOG_ON_DEMAND,
342 .mem_blocks = 2,
343 .severity = 0,
344 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
345 .output = WL12XX_FWLOG_OUTPUT_HOST,
346 .threshold = 0,
347 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300348 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300349 .rate = {
350 .rate_retry_score = 32000,
351 .per_add = 8192,
352 .per_th1 = 2048,
353 .per_th2 = 4096,
354 .max_per = 8100,
355 .inverse_curiosity_factor = 5,
356 .tx_fail_low_th = 4,
357 .tx_fail_high_th = 10,
358 .per_alpha_shift = 4,
359 .per_add_shift = 13,
360 .per_beta1_shift = 10,
361 .per_beta2_shift = 8,
362 .rate_check_up = 2,
363 .rate_check_down = 12,
364 .rate_retry_policy = {
365 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00,
368 },
369 },
Eliad Peller94877752011-08-28 15:11:56 +0300370 .hangover = {
371 .recover_time = 0,
372 .hangover_period = 20,
373 .dynamic_mode = 1,
374 .early_termination_mode = 1,
375 .max_period = 20,
376 .min_period = 1,
377 .increase_delta = 1,
378 .decrease_delta = 2,
379 .quiet_time = 4,
380 .increase_time = 1,
381 .window_size = 16,
382 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300383};
384
Ido Yariv95dac04f2011-06-06 14:57:06 +0300385static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300386static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300387
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300388static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200389 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300390 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200391static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200392static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200393
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200394static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300395static LIST_HEAD(wl_list);
396
Eliad Pellerba8447f2011-10-10 10:13:00 +0200397static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
398 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399{
400 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (operstate != IF_OPER_UP)
403 return 0;
404
Eliad Peller8181aec2011-10-10 10:13:04 +0200405 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300406 return 0;
407
Eliad Peller154da672011-10-05 11:55:53 +0200408 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300409 if (ret < 0)
410 return ret;
411
Eliad Peller0603d892011-10-05 11:55:51 +0200412 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300413
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300414 wl1271_info("Association completed.");
415 return 0;
416}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300417static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
418 void *arg)
419{
420 struct net_device *dev = arg;
421 struct wireless_dev *wdev;
422 struct wiphy *wiphy;
423 struct ieee80211_hw *hw;
424 struct wl1271 *wl;
425 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200426 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300427 int ret = 0;
428
429 /* Check that this notification is for us. */
430 if (what != NETDEV_CHANGE)
431 return NOTIFY_DONE;
432
433 wdev = dev->ieee80211_ptr;
434 if (wdev == NULL)
435 return NOTIFY_DONE;
436
437 wiphy = wdev->wiphy;
438 if (wiphy == NULL)
439 return NOTIFY_DONE;
440
441 hw = wiphy_priv(wiphy);
442 if (hw == NULL)
443 return NOTIFY_DONE;
444
445 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200446 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300447 list_for_each_entry(wl, &wl_list, list) {
448 if (wl == wl_temp)
449 break;
450 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200451 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300452 if (wl != wl_temp)
453 return NOTIFY_DONE;
454
455 mutex_lock(&wl->mutex);
456
457 if (wl->state == WL1271_STATE_OFF)
458 goto out;
459
Eliad Peller6ab70912011-12-18 20:25:45 +0200460 if (dev->operstate != IF_OPER_UP)
461 goto out;
462 /*
463 * The correct behavior should be just getting the appropriate wlvif
464 * from the given dev, but currently we don't have a mac80211
465 * interface for it.
466 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200467 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200468 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
469
Eliad Pellerba8447f2011-10-10 10:13:00 +0200470 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
471 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 ret = wl1271_ps_elp_wakeup(wl);
474 if (ret < 0)
475 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300476
Eliad Peller6ab70912011-12-18 20:25:45 +0200477 wl1271_check_operstate(wl, wlvif,
478 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300479
Eliad Pellerba8447f2011-10-10 10:13:00 +0200480 wl1271_ps_elp_sleep(wl);
481 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300482out:
483 mutex_unlock(&wl->mutex);
484
485 return NOTIFY_OK;
486}
487
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100488static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200489 struct regulatory_request *request)
490{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100491 struct ieee80211_supported_band *band;
492 struct ieee80211_channel *ch;
493 int i;
494
495 band = wiphy->bands[IEEE80211_BAND_5GHZ];
496 for (i = 0; i < band->n_channels; i++) {
497 ch = &band->channels[i];
498 if (ch->flags & IEEE80211_CHAN_DISABLED)
499 continue;
500
501 if (ch->flags & IEEE80211_CHAN_RADAR)
502 ch->flags |= IEEE80211_CHAN_NO_IBSS |
503 IEEE80211_CHAN_PASSIVE_SCAN;
504
505 }
506
507 return 0;
508}
509
Eliad Peller9eb599e2011-10-10 10:12:59 +0200510static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
511 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300512{
513 int ret = 0;
514
515 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200516 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517 if (ret < 0)
518 goto out;
519
520 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200523 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300524out:
525 return ret;
526}
527
528/*
529 * this function is being called when the rx_streaming interval
530 * has beed changed or rx_streaming should be disabled
531 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200532int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300533{
534 int ret = 0;
535 int period = wl->conf.rx_streaming.interval;
536
537 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200538 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300539 goto out;
540
541 /* reconfigure/disable according to new streaming_period */
542 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200543 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 (wl->conf.rx_streaming.always ||
545 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200546 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300547 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200548 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300549 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200550 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300551 }
552out:
553 return ret;
554}
555
556static void wl1271_rx_streaming_enable_work(struct work_struct *work)
557{
558 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200559 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
560 rx_streaming_enable_work);
561 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562
563 mutex_lock(&wl->mutex);
564
Eliad Peller0744bdb2011-10-10 10:13:05 +0200565 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200566 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 (!wl->conf.rx_streaming.always &&
568 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
569 goto out;
570
571 if (!wl->conf.rx_streaming.interval)
572 goto out;
573
574 ret = wl1271_ps_elp_wakeup(wl);
575 if (ret < 0)
576 goto out;
577
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300579 if (ret < 0)
580 goto out_sleep;
581
582 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200583 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300584 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
585
586out_sleep:
587 wl1271_ps_elp_sleep(wl);
588out:
589 mutex_unlock(&wl->mutex);
590}
591
592static void wl1271_rx_streaming_disable_work(struct work_struct *work)
593{
594 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200595 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
596 rx_streaming_disable_work);
597 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300598
599 mutex_lock(&wl->mutex);
600
Eliad Peller0744bdb2011-10-10 10:13:05 +0200601 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 goto out;
603
604 ret = wl1271_ps_elp_wakeup(wl);
605 if (ret < 0)
606 goto out;
607
Eliad Peller9eb599e2011-10-10 10:12:59 +0200608 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300609 if (ret)
610 goto out_sleep;
611
612out_sleep:
613 wl1271_ps_elp_sleep(wl);
614out:
615 mutex_unlock(&wl->mutex);
616}
617
618static void wl1271_rx_streaming_timer(unsigned long data)
619{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200620 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
621 struct wl1271 *wl = wlvif->wl;
622 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300623}
624
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300625static void wl1271_conf_init(struct wl1271 *wl)
626{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
628 /*
629 * This function applies the default configuration to the driver. This
630 * function is invoked upon driver load (spi probe.)
631 *
632 * The configuration is stored in a run-time structure in order to
633 * facilitate for run-time adjustment of any of the parameters. Making
634 * changes to the configuration structure will apply the new values on
635 * the next interface up (wl1271_op_start.)
636 */
637
638 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300639 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300640
Ido Yariv95dac04f2011-06-06 14:57:06 +0300641 /* Adjust settings according to optional module parameters */
642 if (fwlog_param) {
643 if (!strcmp(fwlog_param, "continuous")) {
644 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
645 } else if (!strcmp(fwlog_param, "ondemand")) {
646 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
647 } else if (!strcmp(fwlog_param, "dbgpins")) {
648 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
649 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
650 } else if (!strcmp(fwlog_param, "disable")) {
651 wl->conf.fwlog.mem_blocks = 0;
652 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
653 } else {
654 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
655 }
656 }
657}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659static int wl1271_plt_init(struct wl1271 *wl)
660{
Eliad Peller188e7f52011-12-06 12:15:06 +0200661 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_general_parms(wl);
665 else
666 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id == CHIP_ID_1283_PG20)
671 ret = wl128x_cmd_radio_parms(wl);
672 else
673 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200674 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200675 return ret;
676
Shahar Levi49d750ca2011-03-06 16:32:09 +0200677 if (wl->chip.id != CHIP_ID_1283_PG20) {
678 ret = wl1271_cmd_ext_radio_parms(wl);
679 if (ret < 0)
680 return ret;
681 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200682 if (ret < 0)
683 return ret;
684
Shahar Levi48a61472011-03-06 16:32:08 +0200685 /* Chip-specific initializations */
686 ret = wl1271_chip_specific_init(wl);
687 if (ret < 0)
688 return ret;
689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 ret = wl1271_acx_init_mem_config(wl);
691 if (ret < 0)
692 return ret;
693
Eliad Peller7f0979882011-08-14 13:17:06 +0300694 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600695 if (ret < 0)
696 goto out_free_memmap;
697
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200699 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200701 goto out_free_memmap;
702
703 /* Configure for CAM power saving (ie. always active) */
704 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
705 if (ret < 0)
706 goto out_free_memmap;
707
708 /* configure PM */
709 ret = wl1271_acx_pm_config(wl);
710 if (ret < 0)
711 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712
713 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200714
715 out_free_memmap:
716 kfree(wl->target_mem_map);
717 wl->target_mem_map = NULL;
718
719 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720}
721
Eliad Peller6e8cd332011-10-10 10:13:13 +0200722static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
723 struct wl12xx_vif *wlvif,
724 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200725{
Arik Nemtsovda032092011-08-25 12:43:15 +0300726 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300729 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
731 /*
732 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300733 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200734 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300735 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200736 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200737
Arik Nemtsovda032092011-08-25 12:43:15 +0300738 /*
739 * Start high-level PS if the STA is asleep with enough blocks in FW.
740 * Make an exception if this is the only connected station. In this
741 * case FW-memory congestion is not a problem.
742 */
743 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200744 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745}
746
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300747static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200748 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300749 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200750{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200751 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200752 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300753 u8 hlid, cnt;
754
755 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200756
757 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
758 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
759 wl1271_debug(DEBUG_PSM,
760 "link ps prev 0x%x cur 0x%x changed 0x%x",
761 wl->ap_fw_ps_map, cur_fw_ps_map,
762 wl->ap_fw_ps_map ^ cur_fw_ps_map);
763
764 wl->ap_fw_ps_map = cur_fw_ps_map;
765 }
766
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200767 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
768 lnk = &wl->links[hlid];
769 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200770
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200771 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
772 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200773
Eliad Peller6e8cd332011-10-10 10:13:13 +0200774 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
775 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200776 }
777}
778
Eliad Peller4d56ad92011-08-14 13:17:05 +0300779static void wl12xx_fw_status(struct wl1271 *wl,
780 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200782 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200783 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200784 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300785 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300786 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
Eliad Peller4d56ad92011-08-14 13:17:05 +0300788 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
791 "drv_rx_counter = %d, tx_results_counter = %d)",
792 status->intr,
793 status->fw_rx_counter,
794 status->drv_rx_counter,
795 status->tx_results_counter);
796
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300797 for (i = 0; i < NUM_TX_QUEUES; i++) {
798 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300799 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300800 (status->tx_released_pkts[i] -
801 wl->tx_pkts_freed[i]) & 0xff;
802
803 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
804 }
805
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300806 /* prevent wrap-around in total blocks counter */
807 if (likely(wl->tx_blocks_freed <=
808 le32_to_cpu(status->total_released_blks)))
809 freed_blocks = le32_to_cpu(status->total_released_blks) -
810 wl->tx_blocks_freed;
811 else
812 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
813 le32_to_cpu(status->total_released_blks);
814
Eliad Peller4d56ad92011-08-14 13:17:05 +0300815 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200816
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300817 wl->tx_allocated_blocks -= freed_blocks;
818
Eliad Peller4d56ad92011-08-14 13:17:05 +0300819 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200820
Eliad Peller4d56ad92011-08-14 13:17:05 +0300821 /*
822 * The FW might change the total number of TX memblocks before
823 * we get a notification about blocks being released. Thus, the
824 * available blocks calculation might yield a temporary result
825 * which is lower than the actual available blocks. Keeping in
826 * mind that only blocks that were allocated can be moved from
827 * TX to RX, tx_blocks_available should never decrease here.
828 */
829 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
830 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831
Ido Yariva5225502010-10-12 14:49:10 +0200832 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200833 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200834 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300835
Eliad Peller4d56ad92011-08-14 13:17:05 +0300836 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200837 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200838 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200839 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200842 getnstimeofday(&ts);
843 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
844 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845}
846
Ido Yariva6208652011-03-01 15:14:41 +0200847static void wl1271_flush_deferred_work(struct wl1271 *wl)
848{
849 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200850
Ido Yariva6208652011-03-01 15:14:41 +0200851 /* Pass all received frames to the network stack */
852 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
853 ieee80211_rx_ni(wl->hw, skb);
854
855 /* Return sent skbs to the network stack */
856 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300857 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200858}
859
860static void wl1271_netstack_work(struct work_struct *work)
861{
862 struct wl1271 *wl =
863 container_of(work, struct wl1271, netstack_work);
864
865 do {
866 wl1271_flush_deferred_work(wl);
867 } while (skb_queue_len(&wl->deferred_rx_queue));
868}
869
870#define WL1271_IRQ_MAX_LOOPS 256
871
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300872static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300875 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200876 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200877 struct wl1271 *wl = (struct wl1271 *)cookie;
878 bool done = false;
879 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200880 unsigned long flags;
881
882 /* TX might be handled here, avoid redundant work */
883 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
884 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300885
Ido Yariv341b7cd2011-03-31 10:07:01 +0200886 /*
887 * In case edge triggered interrupt must be used, we cannot iterate
888 * more than once without introducing race conditions with the hardirq.
889 */
890 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
891 loopcount = 1;
892
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 mutex_lock(&wl->mutex);
894
895 wl1271_debug(DEBUG_IRQ, "IRQ work");
896
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200897 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 goto out;
899
Ido Yariva6208652011-03-01 15:14:41 +0200900 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 if (ret < 0)
902 goto out;
903
Ido Yariva6208652011-03-01 15:14:41 +0200904 while (!done && loopcount--) {
905 /*
906 * In order to avoid a race with the hardirq, clear the flag
907 * before acknowledging the chip. Since the mutex is held,
908 * wl1271_ps_elp_wakeup cannot be called concurrently.
909 */
910 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
911 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200912
Eliad Peller4d56ad92011-08-14 13:17:05 +0300913 wl12xx_fw_status(wl, wl->fw_status);
914 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200915 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200916 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200917 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200918 continue;
919 }
920
Eliad Pellerccc83b02010-10-27 14:09:57 +0200921 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
922 wl1271_error("watchdog interrupt received! "
923 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300924 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200925
926 /* restarting the chip. ignore any other interrupt. */
927 goto out;
928 }
929
Ido Yariva6208652011-03-01 15:14:41 +0200930 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200931 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
932
Eliad Peller4d56ad92011-08-14 13:17:05 +0300933 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200934
Ido Yariva5225502010-10-12 14:49:10 +0200935 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200936 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200937 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300938 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 /*
941 * In order to avoid starvation of the TX path,
942 * call the work function directly.
943 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200944 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200945 } else {
946 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200947 }
948
Ido Yariv8aad2462011-03-01 15:14:38 +0200949 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300950 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200951 (wl->tx_results_count & 0xff))
952 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200953
954 /* Make sure the deferred queues don't get too long */
955 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
956 skb_queue_len(&wl->deferred_rx_queue);
957 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
958 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959 }
960
961 if (intr & WL1271_ACX_INTR_EVENT_A) {
962 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
963 wl1271_event_handle(wl, 0);
964 }
965
966 if (intr & WL1271_ACX_INTR_EVENT_B) {
967 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
968 wl1271_event_handle(wl, 1);
969 }
970
971 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
972 wl1271_debug(DEBUG_IRQ,
973 "WL1271_ACX_INTR_INIT_COMPLETE");
974
975 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
976 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 }
978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 wl1271_ps_elp_sleep(wl);
980
981out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200982 spin_lock_irqsave(&wl->wl_lock, flags);
983 /* In case TX was not handled here, queue TX work */
984 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
985 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300986 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200987 ieee80211_queue_work(wl->hw, &wl->tx_work);
988 spin_unlock_irqrestore(&wl->wl_lock, flags);
989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200991
992 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993}
994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995static int wl1271_fetch_firmware(struct wl1271 *wl)
996{
997 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 int ret;
1000
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001001 if (wl->chip.id == CHIP_ID_1283_PG20)
1002 fw_name = WL128X_FW_NAME;
1003 else
1004 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001005
1006 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1007
Felipe Balbia390e852011-10-06 10:07:44 +03001008 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009
1010 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001011 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 return ret;
1013 }
1014
1015 if (fw->size % 4) {
1016 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1017 fw->size);
1018 ret = -EILSEQ;
1019 goto out;
1020 }
1021
Arik Nemtsov166d5042010-10-16 21:44:57 +02001022 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001024 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025
1026 if (!wl->fw) {
1027 wl1271_error("could not allocate memory for the firmware");
1028 ret = -ENOMEM;
1029 goto out;
1030 }
1031
1032 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 ret = 0;
1034
1035out:
1036 release_firmware(fw);
1037
1038 return ret;
1039}
1040
1041static int wl1271_fetch_nvs(struct wl1271 *wl)
1042{
1043 const struct firmware *fw;
1044 int ret;
1045
Felipe Balbia390e852011-10-06 10:07:44 +03001046 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
1048 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001049 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1050 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 return ret;
1052 }
1053
Shahar Levibc765bf2011-03-06 16:32:10 +02001054 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 if (!wl->nvs) {
1057 wl1271_error("could not allocate memory for the nvs file");
1058 ret = -ENOMEM;
1059 goto out;
1060 }
1061
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001062 wl->nvs_len = fw->size;
1063
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064out:
1065 release_firmware(fw);
1066
1067 return ret;
1068}
1069
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001070void wl12xx_queue_recovery_work(struct wl1271 *wl)
1071{
1072 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1073 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1074}
1075
Ido Yariv95dac04f2011-06-06 14:57:06 +03001076size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1077{
1078 size_t len = 0;
1079
1080 /* The FW log is a length-value list, find where the log end */
1081 while (len < maxlen) {
1082 if (memblock[len] == 0)
1083 break;
1084 if (len + memblock[len] + 1 > maxlen)
1085 break;
1086 len += memblock[len] + 1;
1087 }
1088
1089 /* Make sure we have enough room */
1090 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1091
1092 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1093 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1094 wl->fwlog_size += len;
1095
1096 return len;
1097}
1098
1099static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1100{
1101 u32 addr;
1102 u32 first_addr;
1103 u8 *block;
1104
1105 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1106 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1107 (wl->conf.fwlog.mem_blocks == 0))
1108 return;
1109
1110 wl1271_info("Reading FW panic log");
1111
1112 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1113 if (!block)
1114 return;
1115
1116 /*
1117 * Make sure the chip is awake and the logger isn't active.
1118 * This might fail if the firmware hanged.
1119 */
1120 if (!wl1271_ps_elp_wakeup(wl))
1121 wl12xx_cmd_stop_fwlog(wl);
1122
1123 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001124 wl12xx_fw_status(wl, wl->fw_status);
1125 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001126 if (!first_addr)
1127 goto out;
1128
1129 /* Traverse the memory blocks linked list */
1130 addr = first_addr;
1131 do {
1132 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1133 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1134 false);
1135
1136 /*
1137 * Memory blocks are linked to one another. The first 4 bytes
1138 * of each memory block hold the hardware address of the next
1139 * one. The last memory block points to the first one.
1140 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001141 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001142 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1143 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1144 break;
1145 } while (addr && (addr != first_addr));
1146
1147 wake_up_interruptible(&wl->fwlog_waitq);
1148
1149out:
1150 kfree(block);
1151}
1152
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001153static void wl1271_recovery_work(struct work_struct *work)
1154{
1155 struct wl1271 *wl =
1156 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001157 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001158 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001159
1160 mutex_lock(&wl->mutex);
1161
1162 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001163 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001164
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001165 /* Avoid a recursive recovery */
1166 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1167
Ido Yariv95dac04f2011-06-06 14:57:06 +03001168 wl12xx_read_fwlog_panic(wl);
1169
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001170 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1171 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001172
Eliad Peller2a5bff02011-08-25 18:10:59 +03001173 BUG_ON(bug_on_recovery);
1174
Oz Krakowskib992c682011-06-26 10:36:02 +03001175 /*
1176 * Advance security sequence number to overcome potential progress
1177 * in the firmware during recovery. This doens't hurt if the network is
1178 * not encrypted.
1179 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001180 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001181 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001182 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001183 wlvif->tx_security_seq +=
1184 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1185 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001186
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001187 /* Prevent spurious TX during FW restart */
1188 ieee80211_stop_queues(wl->hw);
1189
Luciano Coelho33c2c062011-05-10 14:46:02 +03001190 if (wl->sched_scanning) {
1191 ieee80211_sched_scan_stopped(wl->hw);
1192 wl->sched_scanning = false;
1193 }
1194
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001195 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001196 while (!list_empty(&wl->wlvif_list)) {
1197 wlvif = list_first_entry(&wl->wlvif_list,
1198 struct wl12xx_vif, list);
1199 vif = wl12xx_wlvif_to_vif(wlvif);
1200 __wl1271_op_remove_interface(wl, vif, false);
1201 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001202 mutex_unlock(&wl->mutex);
1203 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001204
1205 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1206
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001207 ieee80211_restart_hw(wl->hw);
1208
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001209 /*
1210 * Its safe to enable TX now - the queues are stopped after a request
1211 * to restart the HW.
1212 */
1213 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001214 return;
1215out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216 mutex_unlock(&wl->mutex);
1217}
1218
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219static void wl1271_fw_wakeup(struct wl1271 *wl)
1220{
1221 u32 elp_reg;
1222
1223 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001224 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225}
1226
1227static int wl1271_setup(struct wl1271 *wl)
1228{
1229 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1230 if (!wl->fw_status)
1231 return -ENOMEM;
1232
1233 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1234 if (!wl->tx_res_if) {
1235 kfree(wl->fw_status);
1236 return -ENOMEM;
1237 }
1238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 return 0;
1240}
1241
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001242static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001244 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001246 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001247 ret = wl1271_power_on(wl);
1248 if (ret < 0)
1249 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001251 wl1271_io_reset(wl);
1252 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001254 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255
1256 /* ELP module wake up */
1257 wl1271_fw_wakeup(wl);
1258
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001259out:
1260 return ret;
1261}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001263static int wl1271_chip_wakeup(struct wl1271 *wl)
1264{
1265 int ret = 0;
1266
1267 ret = wl12xx_set_power_on(wl);
1268 if (ret < 0)
1269 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001271 /*
1272 * For wl127x based devices we could use the default block
1273 * size (512 bytes), but due to a bug in the sdio driver, we
1274 * need to set it explicitly after the chip is powered on. To
1275 * simplify the code and since the performance impact is
1276 * negligible, we use the same block size for all different
1277 * chip types.
1278 */
1279 if (!wl1271_set_block_size(wl))
1280 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281
1282 switch (wl->chip.id) {
1283 case CHIP_ID_1271_PG10:
1284 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1285 wl->chip.id);
1286
1287 ret = wl1271_setup(wl);
1288 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001289 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001290 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 case CHIP_ID_1271_PG20:
1294 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1295 wl->chip.id);
1296
1297 ret = wl1271_setup(wl);
1298 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001299 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001300 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001302
Shahar Levi0830cee2011-03-06 16:32:20 +02001303 case CHIP_ID_1283_PG20:
1304 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1305 wl->chip.id);
1306
1307 ret = wl1271_setup(wl);
1308 if (ret < 0)
1309 goto out;
1310 break;
1311 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001315 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 }
1317
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001318 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319 ret = wl1271_fetch_firmware(wl);
1320 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001321 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 }
1323
1324 /* No NVS from netlink, try to get it from the filesystem */
1325 if (wl->nvs == NULL) {
1326 ret = wl1271_fetch_nvs(wl);
1327 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001328 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 }
1330
1331out:
1332 return ret;
1333}
1334
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335int wl1271_plt_start(struct wl1271 *wl)
1336{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001337 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001338 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 int ret;
1340
1341 mutex_lock(&wl->mutex);
1342
1343 wl1271_notice("power up");
1344
1345 if (wl->state != WL1271_STATE_OFF) {
1346 wl1271_error("cannot go into PLT state because not "
1347 "in off state: %d", wl->state);
1348 ret = -EBUSY;
1349 goto out;
1350 }
1351
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 while (retries) {
1353 retries--;
1354 ret = wl1271_chip_wakeup(wl);
1355 if (ret < 0)
1356 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 ret = wl1271_boot(wl);
1359 if (ret < 0)
1360 goto power_off;
1361
1362 ret = wl1271_plt_init(wl);
1363 if (ret < 0)
1364 goto irq_disable;
1365
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 wl->state = WL1271_STATE_PLT;
1367 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001368 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001369
Gery Kahn6f07b722011-07-18 14:21:49 +03001370 /* update hw/fw version info in wiphy struct */
1371 wiphy->hw_version = wl->chip.id;
1372 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1373 sizeof(wiphy->fw_version));
1374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375 goto out;
1376
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001377irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001378 mutex_unlock(&wl->mutex);
1379 /* Unlocking the mutex in the middle of handling is
1380 inherently unsafe. In this case we deem it safe to do,
1381 because we need to let any possibly pending IRQ out of
1382 the system (and while we are WL1271_STATE_OFF the IRQ
1383 work function will not do anything.) Also, any other
1384 possible concurrent operations will fail due to the
1385 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001386 wl1271_disable_interrupts(wl);
1387 wl1271_flush_deferred_work(wl);
1388 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001389 mutex_lock(&wl->mutex);
1390power_off:
1391 wl1271_power_off(wl);
1392 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1395 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396out:
1397 mutex_unlock(&wl->mutex);
1398
1399 return ret;
1400}
1401
Ido Yarivf3df1332012-01-11 09:42:39 +02001402int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403{
1404 int ret = 0;
1405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406 wl1271_notice("power down");
1407
Ido Yariv46b0cc92012-01-11 09:42:41 +02001408 /*
1409 * Interrupts must be disabled before setting the state to OFF.
1410 * Otherwise, the interrupt handler might be called and exit without
1411 * reading the interrupt status.
1412 */
1413 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001414 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001416 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001417
1418 /*
1419 * This will not necessarily enable interrupts as interrupts
1420 * may have been disabled when op_stop was called. It will,
1421 * however, balance the above call to disable_interrupts().
1422 */
1423 wl1271_enable_interrupts(wl);
1424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 wl1271_error("cannot power down because not in PLT "
1426 "state: %d", wl->state);
1427 ret = -EBUSY;
1428 goto out;
1429 }
1430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001432
Ido Yariva6208652011-03-01 15:14:41 +02001433 wl1271_flush_deferred_work(wl);
1434 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001435 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001436 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001437
1438 mutex_lock(&wl->mutex);
1439 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001440 wl->flags = 0;
1441 wl->state = WL1271_STATE_OFF;
1442 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001443 mutex_unlock(&wl->mutex);
1444
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001445out:
1446 return ret;
1447}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001448
Johannes Berg7bb45682011-02-24 14:42:06 +01001449static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450{
1451 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001452 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1453 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001454 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001455 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001456 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458
Eliad Peller0f168012011-10-11 13:52:25 +02001459 if (vif)
1460 wlvif = wl12xx_vif_to_data(vif);
1461
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001462 mapping = skb_get_queue_mapping(skb);
1463 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001464
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001465 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001466
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001467 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001468
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001469 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001470 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001471 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001472 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001473 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001474 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001475 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001477 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1478 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1479
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001480 wl->tx_queue_count[q]++;
1481
1482 /*
1483 * The workqueue is slow to process the tx_queue and we need stop
1484 * the queue here, otherwise the queue will get too long.
1485 */
1486 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1487 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1488 ieee80211_stop_queue(wl->hw, mapping);
1489 set_bit(q, &wl->stopped_queues_map);
1490 }
1491
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 /*
1493 * The chip specific setup must run before the first TX packet -
1494 * before that, the tx_work will not be initialized!
1495 */
1496
Ido Yarivb07d4032011-03-01 15:14:43 +02001497 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1498 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001499 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001500
Arik Nemtsov04216da2011-08-14 13:17:38 +03001501out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001502 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503}
1504
Shahar Leviae47c452011-03-06 16:32:14 +02001505int wl1271_tx_dummy_packet(struct wl1271 *wl)
1506{
Ido Yariv990f5de2011-03-31 10:06:59 +02001507 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001508 int q;
1509
1510 /* no need to queue a new dummy packet if one is already pending */
1511 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1512 return 0;
1513
1514 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001515
Ido Yariv990f5de2011-03-31 10:06:59 +02001516 spin_lock_irqsave(&wl->wl_lock, flags);
1517 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001518 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001519 spin_unlock_irqrestore(&wl->wl_lock, flags);
1520
1521 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1522 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001523 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001524
1525 /*
1526 * If the FW TX is busy, TX work will be scheduled by the threaded
1527 * interrupt handler function
1528 */
1529 return 0;
1530}
1531
1532/*
1533 * The size of the dummy packet should be at least 1400 bytes. However, in
1534 * order to minimize the number of bus transactions, aligning it to 512 bytes
1535 * boundaries could be beneficial, performance wise
1536 */
1537#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1538
Luciano Coelhocf27d862011-04-01 21:08:23 +03001539static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001540{
1541 struct sk_buff *skb;
1542 struct ieee80211_hdr_3addr *hdr;
1543 unsigned int dummy_packet_size;
1544
1545 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1546 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1547
1548 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001549 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001550 wl1271_warning("Failed to allocate a dummy packet skb");
1551 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001552 }
1553
1554 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1555
1556 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1557 memset(hdr, 0, sizeof(*hdr));
1558 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 IEEE80211_STYPE_NULLFUNC |
1560 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001561
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001563
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001564 /* Dummy packets require the TID to be management */
1565 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001566
1567 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001568 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001569 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001570
Ido Yariv990f5de2011-03-31 10:06:59 +02001571 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001572}
1573
Ido Yariv990f5de2011-03-31 10:06:59 +02001574
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001575static struct notifier_block wl1271_dev_notifier = {
1576 .notifier_call = wl1271_dev_notify,
1577};
1578
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001579#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001580static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1581 struct wl12xx_vif *wlvif)
1582{
1583 int ret = 0;
1584
1585 mutex_lock(&wl->mutex);
1586
1587 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1588 goto out_unlock;
1589
1590 ret = wl1271_ps_elp_wakeup(wl);
1591 if (ret < 0)
1592 goto out_unlock;
1593
1594 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1595 wl->conf.conn.suspend_wake_up_event,
1596 wl->conf.conn.suspend_listen_interval);
1597
1598 if (ret < 0)
1599 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1600
1601
1602 wl1271_ps_elp_sleep(wl);
1603
1604out_unlock:
1605 mutex_unlock(&wl->mutex);
1606 return ret;
1607
1608}
Eliad Peller94390642011-05-13 11:57:13 +03001609
Eliad Peller0603d892011-10-05 11:55:51 +02001610static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1611 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001612{
Eliad Pellere85d1622011-06-27 13:06:43 +03001613 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001614
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001615 mutex_lock(&wl->mutex);
1616
Eliad Peller53d40d02011-10-10 10:13:02 +02001617 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 goto out_unlock;
1619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 ret = wl1271_ps_elp_wakeup(wl);
1621 if (ret < 0)
1622 goto out_unlock;
1623
Eliad Peller0603d892011-10-05 11:55:51 +02001624 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625
1626 wl1271_ps_elp_sleep(wl);
1627out_unlock:
1628 mutex_unlock(&wl->mutex);
1629 return ret;
1630
1631}
1632
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001633static int wl1271_configure_suspend(struct wl1271 *wl,
1634 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001636 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1637 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001638 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001639 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640 return 0;
1641}
1642
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001643static void wl1271_configure_resume(struct wl1271 *wl,
1644 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001646 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001647 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001648 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001649
Eyal Shapiradae728f2012-02-02 12:03:39 +02001650 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001651 return;
1652
1653 mutex_lock(&wl->mutex);
1654 ret = wl1271_ps_elp_wakeup(wl);
1655 if (ret < 0)
1656 goto out;
1657
Eyal Shapiradae728f2012-02-02 12:03:39 +02001658 if (is_sta) {
1659 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1660 wl->conf.conn.wake_up_event,
1661 wl->conf.conn.listen_interval);
1662
1663 if (ret < 0)
1664 wl1271_error("resume: wake up conditions failed: %d",
1665 ret);
1666
1667 } else if (is_ap) {
1668 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1669 }
Eliad Peller94390642011-05-13 11:57:13 +03001670
1671 wl1271_ps_elp_sleep(wl);
1672out:
1673 mutex_unlock(&wl->mutex);
1674}
1675
Eliad Peller402e48612011-05-13 11:57:09 +03001676static int wl1271_op_suspend(struct ieee80211_hw *hw,
1677 struct cfg80211_wowlan *wow)
1678{
1679 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001680 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001681 int ret;
1682
Eliad Peller402e48612011-05-13 11:57:09 +03001683 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001684 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001685
Eliad Peller4a859df2011-06-06 12:21:52 +03001686 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001687 wl12xx_for_each_wlvif(wl, wlvif) {
1688 ret = wl1271_configure_suspend(wl, wlvif);
1689 if (ret < 0) {
1690 wl1271_warning("couldn't prepare device to suspend");
1691 return ret;
1692 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001693 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001694 /* flush any remaining work */
1695 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001696
1697 /*
1698 * disable and re-enable interrupts in order to flush
1699 * the threaded_irq
1700 */
1701 wl1271_disable_interrupts(wl);
1702
1703 /*
1704 * set suspended flag to avoid triggering a new threaded_irq
1705 * work. no need for spinlock as interrupts are disabled.
1706 */
1707 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1708
1709 wl1271_enable_interrupts(wl);
1710 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001711 flush_delayed_work(&wl->elp_work);
1712
Eliad Peller402e48612011-05-13 11:57:09 +03001713 return 0;
1714}
1715
1716static int wl1271_op_resume(struct ieee80211_hw *hw)
1717{
1718 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001719 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001720 unsigned long flags;
1721 bool run_irq_work = false;
1722
Eliad Peller402e48612011-05-13 11:57:09 +03001723 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1724 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001726
1727 /*
1728 * re-enable irq_work enqueuing, and call irq_work directly if
1729 * there is a pending work.
1730 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 spin_lock_irqsave(&wl->wl_lock, flags);
1732 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1733 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1734 run_irq_work = true;
1735 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001736
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 if (run_irq_work) {
1738 wl1271_debug(DEBUG_MAC80211,
1739 "run postponed irq_work directly");
1740 wl1271_irq(0, wl);
1741 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001742 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001743 wl12xx_for_each_wlvif(wl, wlvif) {
1744 wl1271_configure_resume(wl, wlvif);
1745 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001746 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001747
Eliad Peller402e48612011-05-13 11:57:09 +03001748 return 0;
1749}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001750#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001751
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752static int wl1271_op_start(struct ieee80211_hw *hw)
1753{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001754 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1755
1756 /*
1757 * We have to delay the booting of the hardware because
1758 * we need to know the local MAC address before downloading and
1759 * initializing the firmware. The MAC address cannot be changed
1760 * after boot, and without the proper MAC address, the firmware
1761 * will not function properly.
1762 *
1763 * The MAC address is first known when the corresponding interface
1764 * is added. That is where we will initialize the hardware.
1765 */
1766
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001767 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001768}
1769
1770static void wl1271_op_stop(struct ieee80211_hw *hw)
1771{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001772 struct wl1271 *wl = hw->priv;
1773 int i;
1774
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001775 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776
Ido Yariv46b0cc92012-01-11 09:42:41 +02001777 /*
1778 * Interrupts must be disabled before setting the state to OFF.
1779 * Otherwise, the interrupt handler might be called and exit without
1780 * reading the interrupt status.
1781 */
1782 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001783 mutex_lock(&wl->mutex);
1784 if (wl->state == WL1271_STATE_OFF) {
1785 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001786
1787 /*
1788 * This will not necessarily enable interrupts as interrupts
1789 * may have been disabled when op_stop was called. It will,
1790 * however, balance the above call to disable_interrupts().
1791 */
1792 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001793 return;
1794 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001795
Eliad Pellerbaf62772011-10-10 10:12:52 +02001796 /*
1797 * this must be before the cancel_work calls below, so that the work
1798 * functions don't perform further work.
1799 */
1800 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001801 mutex_unlock(&wl->mutex);
1802
1803 mutex_lock(&wl_list_mutex);
1804 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001805 mutex_unlock(&wl_list_mutex);
1806
Eliad Pellerbaf62772011-10-10 10:12:52 +02001807 wl1271_flush_deferred_work(wl);
1808 cancel_delayed_work_sync(&wl->scan_complete_work);
1809 cancel_work_sync(&wl->netstack_work);
1810 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001811 cancel_delayed_work_sync(&wl->elp_work);
1812
1813 /* let's notify MAC80211 about the remaining pending TX frames */
1814 wl12xx_tx_reset(wl, true);
1815 mutex_lock(&wl->mutex);
1816
1817 wl1271_power_off(wl);
1818
1819 wl->band = IEEE80211_BAND_2GHZ;
1820
1821 wl->rx_counter = 0;
1822 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1823 wl->tx_blocks_available = 0;
1824 wl->tx_allocated_blocks = 0;
1825 wl->tx_results_count = 0;
1826 wl->tx_packets_count = 0;
1827 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001828 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1829 wl->ap_fw_ps_map = 0;
1830 wl->ap_ps_map = 0;
1831 wl->sched_scanning = false;
1832 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1833 memset(wl->links_map, 0, sizeof(wl->links_map));
1834 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1835 wl->active_sta_count = 0;
1836
1837 /* The system link is always allocated */
1838 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1839
1840 /*
1841 * this is performed after the cancel_work calls and the associated
1842 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1843 * get executed before all these vars have been reset.
1844 */
1845 wl->flags = 0;
1846
1847 wl->tx_blocks_freed = 0;
1848
1849 for (i = 0; i < NUM_TX_QUEUES; i++) {
1850 wl->tx_pkts_freed[i] = 0;
1851 wl->tx_allocated_pkts[i] = 0;
1852 }
1853
1854 wl1271_debugfs_reset(wl);
1855
1856 kfree(wl->fw_status);
1857 wl->fw_status = NULL;
1858 kfree(wl->tx_res_if);
1859 wl->tx_res_if = NULL;
1860 kfree(wl->target_mem_map);
1861 wl->target_mem_map = NULL;
1862
1863 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001864}
1865
Eliad Pellere5a359f2011-10-10 10:13:15 +02001866static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1867{
1868 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1869 WL12XX_MAX_RATE_POLICIES);
1870 if (policy >= WL12XX_MAX_RATE_POLICIES)
1871 return -EBUSY;
1872
1873 __set_bit(policy, wl->rate_policies_map);
1874 *idx = policy;
1875 return 0;
1876}
1877
1878static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1879{
1880 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1881 return;
1882
1883 __clear_bit(*idx, wl->rate_policies_map);
1884 *idx = WL12XX_MAX_RATE_POLICIES;
1885}
1886
Eliad Peller536129c2011-10-05 11:55:45 +02001887static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001888{
Eliad Peller536129c2011-10-05 11:55:45 +02001889 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001890 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001891 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001892 return WL1271_ROLE_P2P_GO;
1893 else
1894 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001895
1896 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001897 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001898 return WL1271_ROLE_P2P_CL;
1899 else
1900 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001901
Eliad Peller227e81e2011-08-14 13:17:26 +03001902 case BSS_TYPE_IBSS:
1903 return WL1271_ROLE_IBSS;
1904
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001905 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001906 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001907 }
1908 return WL12XX_INVALID_ROLE_TYPE;
1909}
1910
Eliad Peller83587502011-10-10 10:12:53 +02001911static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001912{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001913 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001914 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001915
Eliad Peller48e93e42011-10-10 10:12:58 +02001916 /* clear everything but the persistent data */
1917 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001918
1919 switch (ieee80211_vif_type_p2p(vif)) {
1920 case NL80211_IFTYPE_P2P_CLIENT:
1921 wlvif->p2p = 1;
1922 /* fall-through */
1923 case NL80211_IFTYPE_STATION:
1924 wlvif->bss_type = BSS_TYPE_STA_BSS;
1925 break;
1926 case NL80211_IFTYPE_ADHOC:
1927 wlvif->bss_type = BSS_TYPE_IBSS;
1928 break;
1929 case NL80211_IFTYPE_P2P_GO:
1930 wlvif->p2p = 1;
1931 /* fall-through */
1932 case NL80211_IFTYPE_AP:
1933 wlvif->bss_type = BSS_TYPE_AP_BSS;
1934 break;
1935 default:
1936 wlvif->bss_type = MAX_BSS_TYPE;
1937 return -EOPNOTSUPP;
1938 }
1939
Eliad Peller0603d892011-10-05 11:55:51 +02001940 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001941 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001942 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001943
Eliad Pellere936bbe2011-10-05 11:55:56 +02001944 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1945 wlvif->bss_type == BSS_TYPE_IBSS) {
1946 /* init sta/ibss data */
1947 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001948 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1949 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1950 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 } else {
1952 /* init ap data */
1953 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1954 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001955 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1956 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1957 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1958 wl12xx_allocate_rate_policy(wl,
1959 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001960 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001961
Eliad Peller83587502011-10-10 10:12:53 +02001962 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1963 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001964 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001965 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001966 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001967 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1968
Eliad Peller1b92f152011-10-10 10:13:09 +02001969 /*
1970 * mac80211 configures some values globally, while we treat them
1971 * per-interface. thus, on init, we have to copy them from wl
1972 */
1973 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001974 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001975 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001976
Eliad Peller9eb599e2011-10-10 10:12:59 +02001977 INIT_WORK(&wlvif->rx_streaming_enable_work,
1978 wl1271_rx_streaming_enable_work);
1979 INIT_WORK(&wlvif->rx_streaming_disable_work,
1980 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001981 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001982
Eliad Peller9eb599e2011-10-10 10:12:59 +02001983 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1984 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001985 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001986}
1987
Eliad Peller1d095472011-10-10 10:12:49 +02001988static bool wl12xx_init_fw(struct wl1271 *wl)
1989{
1990 int retries = WL1271_BOOT_RETRIES;
1991 bool booted = false;
1992 struct wiphy *wiphy = wl->hw->wiphy;
1993 int ret;
1994
1995 while (retries) {
1996 retries--;
1997 ret = wl1271_chip_wakeup(wl);
1998 if (ret < 0)
1999 goto power_off;
2000
2001 ret = wl1271_boot(wl);
2002 if (ret < 0)
2003 goto power_off;
2004
2005 ret = wl1271_hw_init(wl);
2006 if (ret < 0)
2007 goto irq_disable;
2008
2009 booted = true;
2010 break;
2011
2012irq_disable:
2013 mutex_unlock(&wl->mutex);
2014 /* Unlocking the mutex in the middle of handling is
2015 inherently unsafe. In this case we deem it safe to do,
2016 because we need to let any possibly pending IRQ out of
2017 the system (and while we are WL1271_STATE_OFF the IRQ
2018 work function will not do anything.) Also, any other
2019 possible concurrent operations will fail due to the
2020 current state, hence the wl1271 struct should be safe. */
2021 wl1271_disable_interrupts(wl);
2022 wl1271_flush_deferred_work(wl);
2023 cancel_work_sync(&wl->netstack_work);
2024 mutex_lock(&wl->mutex);
2025power_off:
2026 wl1271_power_off(wl);
2027 }
2028
2029 if (!booted) {
2030 wl1271_error("firmware boot failed despite %d retries",
2031 WL1271_BOOT_RETRIES);
2032 goto out;
2033 }
2034
2035 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2036
2037 /* update hw/fw version info in wiphy struct */
2038 wiphy->hw_version = wl->chip.id;
2039 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2040 sizeof(wiphy->fw_version));
2041
2042 /*
2043 * Now we know if 11a is supported (info from the NVS), so disable
2044 * 11a channels if not supported
2045 */
2046 if (!wl->enable_11a)
2047 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2048
2049 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2050 wl->enable_11a ? "" : "not ");
2051
2052 wl->state = WL1271_STATE_ON;
2053out:
2054 return booted;
2055}
2056
Eliad Peller92e712d2011-12-18 20:25:43 +02002057static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2058{
2059 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2060}
2061
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002062static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2063 struct ieee80211_vif *vif)
2064{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002066 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002068 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002069 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070
Johannes Bergea086352012-01-19 09:29:58 +01002071 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2072 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002073
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002074 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002075 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076
2077 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002078 ret = wl1271_ps_elp_wakeup(wl);
2079 if (ret < 0)
2080 goto out_unlock;
2081
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002082 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002083 wl1271_debug(DEBUG_MAC80211,
2084 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002085 ret = -EBUSY;
2086 goto out;
2087 }
2088
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002089 /*
2090 * in some very corner case HW recovery scenarios its possible to
2091 * get here before __wl1271_op_remove_interface is complete, so
2092 * opt out if that is the case.
2093 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002094 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2095 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002096 ret = -EBUSY;
2097 goto out;
2098 }
2099
Eliad Peller83587502011-10-10 10:12:53 +02002100 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002101 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002103
Eliad Peller252efa42011-10-05 11:56:00 +02002104 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002105 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002106 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2107 ret = -EINVAL;
2108 goto out;
2109 }
Eliad Peller1d095472011-10-10 10:12:49 +02002110
Eliad Peller784f6942011-10-05 11:55:39 +02002111 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002112 * TODO: after the nvs issue will be solved, move this block
2113 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002114 */
Eliad Peller1d095472011-10-10 10:12:49 +02002115 if (wl->state == WL1271_STATE_OFF) {
2116 /*
2117 * we still need this in order to configure the fw
2118 * while uploading the nvs
2119 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002120 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121
Eliad Peller1d095472011-10-10 10:12:49 +02002122 booted = wl12xx_init_fw(wl);
2123 if (!booted) {
2124 ret = -EINVAL;
2125 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002126 }
Eliad Peller1d095472011-10-10 10:12:49 +02002127 }
Eliad Peller04e80792011-08-14 13:17:09 +03002128
Eliad Peller1d095472011-10-10 10:12:49 +02002129 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2130 wlvif->bss_type == BSS_TYPE_IBSS) {
2131 /*
2132 * The device role is a special role used for
2133 * rx and tx frames prior to association (as
2134 * the STA role can get packets only from
2135 * its associated bssid)
2136 */
Eliad Peller784f6942011-10-05 11:55:39 +02002137 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002138 WL1271_ROLE_DEVICE,
2139 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002140 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002141 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002142 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143
Eliad Peller1d095472011-10-10 10:12:49 +02002144 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2145 role_type, &wlvif->role_id);
2146 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002147 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002148
2149 ret = wl1271_init_vif_specific(wl, vif);
2150 if (ret < 0)
2151 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002152
2153 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002154 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002155 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002156
2157 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2158 wl->ap_count++;
2159 else
2160 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002161out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002162 wl1271_ps_elp_sleep(wl);
2163out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164 mutex_unlock(&wl->mutex);
2165
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002166 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002167 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002168 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002169 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002170
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171 return ret;
2172}
2173
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002174static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002175 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002176 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177{
Eliad Peller536129c2011-10-05 11:55:45 +02002178 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002179 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002181 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182
Eliad Peller10c8cd02011-10-10 10:13:06 +02002183 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2184 return;
2185
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002186 wl->vif = NULL;
2187
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002188 /* because of hardware recovery, we may get here twice */
2189 if (wl->state != WL1271_STATE_ON)
2190 return;
2191
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002192 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193
Eliad Pellerbaf62772011-10-10 10:12:52 +02002194 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2195 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002196 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002197 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002198 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002199 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002200 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 }
2202
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002203 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2204 /* disable active roles */
2205 ret = wl1271_ps_elp_wakeup(wl);
2206 if (ret < 0)
2207 goto deinit;
2208
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002209 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2210 wlvif->bss_type == BSS_TYPE_IBSS) {
2211 if (wl12xx_dev_role_started(wlvif))
2212 wl12xx_stop_dev(wl, wlvif);
2213
Eliad Peller7edebf52011-10-05 11:55:52 +02002214 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002215 if (ret < 0)
2216 goto deinit;
2217 }
2218
Eliad Peller0603d892011-10-05 11:55:51 +02002219 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002220 if (ret < 0)
2221 goto deinit;
2222
2223 wl1271_ps_elp_sleep(wl);
2224 }
2225deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002226 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002227 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002228
2229 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2230 wlvif->bss_type == BSS_TYPE_IBSS) {
2231 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2232 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2233 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2234 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2235 } else {
2236 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2237 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2238 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2239 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2240 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2241 wl12xx_free_rate_policy(wl,
2242 &wlvif->ap.ucast_rate_idx[i]);
2243 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002244
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002245 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002246 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002247 if (wl->last_wlvif == wlvif)
2248 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002249 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002250 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002251 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002252 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002253
Eliad Pellera4e41302011-10-11 11:49:15 +02002254 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2255 wl->ap_count--;
2256 else
2257 wl->sta_count--;
2258
Eliad Pellerbaf62772011-10-10 10:12:52 +02002259 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002260
Eliad Peller9eb599e2011-10-10 10:12:59 +02002261 del_timer_sync(&wlvif->rx_streaming_timer);
2262 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2263 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002264
Eliad Pellerbaf62772011-10-10 10:12:52 +02002265 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002266}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002267
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002268static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2269 struct ieee80211_vif *vif)
2270{
2271 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002272 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002273 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002274
2275 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002276
2277 if (wl->state == WL1271_STATE_OFF ||
2278 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2279 goto out;
2280
Juuso Oikarinen67353292010-11-18 15:19:02 +02002281 /*
2282 * wl->vif can be null here if someone shuts down the interface
2283 * just when hardware recovery has been started.
2284 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002285 wl12xx_for_each_wlvif(wl, iter) {
2286 if (iter != wlvif)
2287 continue;
2288
Eliad Peller536129c2011-10-05 11:55:45 +02002289 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002290 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002291 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002292 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002293out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002294 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002295 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296}
2297
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002298static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2299 struct ieee80211_vif *vif,
2300 enum nl80211_iftype new_type, bool p2p)
2301{
2302 wl1271_op_remove_interface(hw, vif);
2303
2304 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2305 vif->p2p = p2p;
2306 return wl1271_op_add_interface(hw, vif);
2307}
2308
Eliad Peller87fbcb02011-10-05 11:55:41 +02002309static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2310 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002311{
2312 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002313 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002314
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002315 /*
2316 * One of the side effects of the JOIN command is that is clears
2317 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2318 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002319 * Currently the only valid scenario for JOIN during association
2320 * is on roaming, in which case we will also be given new keys.
2321 * Keep the below message for now, unless it starts bothering
2322 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002323 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002324 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002325 wl1271_info("JOIN while associated.");
2326
Eliad Peller5ec8a442012-02-02 12:22:09 +02002327 /* clear encryption type */
2328 wlvif->encryption_type = KEY_NONE;
2329
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002330 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002331 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002332
Eliad Peller227e81e2011-08-14 13:17:26 +03002333 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002334 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002335 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002336 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002337 if (ret < 0)
2338 goto out;
2339
Eliad Pellerba8447f2011-10-10 10:13:00 +02002340 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002341 goto out;
2342
2343 /*
2344 * The join command disable the keep-alive mode, shut down its process,
2345 * and also clear the template config, so we need to reset it all after
2346 * the join. The acx_aid starts the keep-alive process, and the order
2347 * of the commands below is relevant.
2348 */
Eliad Peller0603d892011-10-05 11:55:51 +02002349 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 if (ret < 0)
2351 goto out;
2352
Eliad Peller0603d892011-10-05 11:55:51 +02002353 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002354 if (ret < 0)
2355 goto out;
2356
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002357 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002358 if (ret < 0)
2359 goto out;
2360
Eliad Peller0603d892011-10-05 11:55:51 +02002361 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2362 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002363 ACX_KEEP_ALIVE_TPL_VALID);
2364 if (ret < 0)
2365 goto out;
2366
2367out:
2368 return ret;
2369}
2370
Eliad Peller0603d892011-10-05 11:55:51 +02002371static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002372{
2373 int ret;
2374
Eliad Peller52630c52011-10-10 10:13:08 +02002375 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002376 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2377
Shahar Levi6d158ff2011-09-08 13:01:33 +03002378 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002379 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002380 }
2381
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002382 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002383 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002384 if (ret < 0)
2385 goto out;
2386
Oz Krakowskib992c682011-06-26 10:36:02 +03002387 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002388 wlvif->tx_security_last_seq_lsb = 0;
2389 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002390
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002391out:
2392 return ret;
2393}
2394
Eliad Peller87fbcb02011-10-05 11:55:41 +02002395static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396{
Eliad Peller1b92f152011-10-10 10:13:09 +02002397 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002398 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002399}
2400
Eliad Peller87fbcb02011-10-05 11:55:41 +02002401static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2402 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002403{
2404 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002405 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2406
2407 if (idle == cur_idle)
2408 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002409
2410 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002411 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002412 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002413 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002414 if (ret < 0)
2415 goto out;
2416 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002417 wlvif->rate_set =
2418 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2419 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002420 if (ret < 0)
2421 goto out;
2422 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002423 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002424 ACX_KEEP_ALIVE_TPL_INVALID);
2425 if (ret < 0)
2426 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002427 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002428 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002429 /* The current firmware only supports sched_scan in idle */
2430 if (wl->sched_scanning) {
2431 wl1271_scan_sched_scan_stop(wl);
2432 ieee80211_sched_scan_stopped(wl->hw);
2433 }
2434
Eliad Peller679a6732011-10-11 11:55:44 +02002435 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002436 if (ret < 0)
2437 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002438 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002439 }
2440
2441out:
2442 return ret;
2443}
2444
Eliad Peller9f259c42011-10-10 10:13:12 +02002445static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2446 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447{
Eliad Peller9f259c42011-10-10 10:13:12 +02002448 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2449 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450
2451 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2452
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002453 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002454 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002455 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002456 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002457 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002458 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002459 wlvif->band = conf->channel->band;
2460 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002461
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002462 if (!is_ap) {
2463 /*
2464 * FIXME: the mac80211 should really provide a fixed
2465 * rate to use here. for now, just use the smallest
2466 * possible rate for the band as a fixed rate for
2467 * association frames and other control messages.
2468 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002469 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002470 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002472 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002473 wl1271_tx_min_rate_get(wl,
2474 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002475 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002476 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002477 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002478 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002479
Eliad Pellerba8447f2011-10-10 10:13:00 +02002480 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2481 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002482 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002483 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002484 ret = wl12xx_croc(wl,
2485 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002486 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002487 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002488 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002489 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002490 if (ret < 0)
2491 wl1271_warning("cmd join on channel "
2492 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002493 } else {
2494 /*
2495 * change the ROC channel. do it only if we are
2496 * not idle. otherwise, CROC will be called
2497 * anyway.
2498 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002499 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002500 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002501 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002503 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002504
Eliad Peller679a6732011-10-11 11:55:44 +02002505 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002506 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002507 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002508 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002509 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002510 }
2511 }
2512
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002513 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002514
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002515 if ((conf->flags & IEEE80211_CONF_PS) &&
2516 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002517 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002518
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002519 int ps_mode;
2520 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002521
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002522 if (wl->conf.conn.forced_ps) {
2523 ps_mode = STATION_POWER_SAVE_MODE;
2524 ps_mode_str = "forced";
2525 } else {
2526 ps_mode = STATION_AUTO_PS_MODE;
2527 ps_mode_str = "auto";
2528 }
2529
2530 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2531
2532 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2533
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002534 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002535 wl1271_warning("enter %s ps failed %d",
2536 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002538 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002539 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002541 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2542
Eliad Peller0603d892011-10-05 11:55:51 +02002543 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002544 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002545 if (ret < 0)
2546 wl1271_warning("exit auto ps failed %d", ret);
2547 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002548 }
2549
Eliad Peller6bd65022011-10-10 10:13:11 +02002550 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002551 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002553 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
Eliad Peller6bd65022011-10-10 10:13:11 +02002555 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556 }
2557
Eliad Peller9f259c42011-10-10 10:13:12 +02002558 return 0;
2559}
2560
2561static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2562{
2563 struct wl1271 *wl = hw->priv;
2564 struct wl12xx_vif *wlvif;
2565 struct ieee80211_conf *conf = &hw->conf;
2566 int channel, ret = 0;
2567
2568 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2569
2570 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2571 " changed 0x%x",
2572 channel,
2573 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2574 conf->power_level,
2575 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2576 changed);
2577
2578 /*
2579 * mac80211 will go to idle nearly immediately after transmitting some
2580 * frames, such as the deauth. To make sure those frames reach the air,
2581 * wait here until the TX queue is fully flushed.
2582 */
2583 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2584 (conf->flags & IEEE80211_CONF_IDLE))
2585 wl1271_tx_flush(wl);
2586
2587 mutex_lock(&wl->mutex);
2588
2589 /* we support configuring the channel and band even while off */
2590 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2591 wl->band = conf->channel->band;
2592 wl->channel = channel;
2593 }
2594
2595 if (changed & IEEE80211_CONF_CHANGE_POWER)
2596 wl->power_level = conf->power_level;
2597
2598 if (unlikely(wl->state == WL1271_STATE_OFF))
2599 goto out;
2600
2601 ret = wl1271_ps_elp_wakeup(wl);
2602 if (ret < 0)
2603 goto out;
2604
2605 /* configure each interface */
2606 wl12xx_for_each_wlvif(wl, wlvif) {
2607 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2608 if (ret < 0)
2609 goto out_sleep;
2610 }
2611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002612out_sleep:
2613 wl1271_ps_elp_sleep(wl);
2614
2615out:
2616 mutex_unlock(&wl->mutex);
2617
2618 return ret;
2619}
2620
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002621struct wl1271_filter_params {
2622 bool enabled;
2623 int mc_list_length;
2624 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2625};
2626
Jiri Pirko22bedad2010-04-01 21:22:57 +00002627static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2628 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002630 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002631 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002632 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002633
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002634 if (unlikely(wl->state == WL1271_STATE_OFF))
2635 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002636
Juuso Oikarinen74441132009-10-13 12:47:53 +03002637 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002638 if (!fp) {
2639 wl1271_error("Out of memory setting filters.");
2640 return 0;
2641 }
2642
2643 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002645 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2646 fp->enabled = false;
2647 } else {
2648 fp->enabled = true;
2649 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002650 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002651 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002652 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002653 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002654 }
2655
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002656 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002659#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2660 FIF_ALLMULTI | \
2661 FIF_FCSFAIL | \
2662 FIF_BCN_PRBRESP_PROMISC | \
2663 FIF_CONTROL | \
2664 FIF_OTHER_BSS)
2665
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002666static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2667 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002669{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002670 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002672 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002673
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002674 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675
Arik Nemtsov7d057862010-10-16 19:25:35 +02002676 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2677 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002679 mutex_lock(&wl->mutex);
2680
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002681 *total &= WL1271_SUPPORTED_FILTERS;
2682 changed &= WL1271_SUPPORTED_FILTERS;
2683
2684 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002685 goto out;
2686
Ido Yariva6208652011-03-01 15:14:41 +02002687 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002688 if (ret < 0)
2689 goto out;
2690
Eliad Peller6e8cd332011-10-10 10:13:13 +02002691 wl12xx_for_each_wlvif(wl, wlvif) {
2692 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2693 if (*total & FIF_ALLMULTI)
2694 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2695 false,
2696 NULL, 0);
2697 else if (fp)
2698 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2699 fp->enabled,
2700 fp->mc_list,
2701 fp->mc_list_length);
2702 if (ret < 0)
2703 goto out_sleep;
2704 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002705 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002707 /*
2708 * the fw doesn't provide an api to configure the filters. instead,
2709 * the filters configuration is based on the active roles / ROC
2710 * state.
2711 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002712
2713out_sleep:
2714 wl1271_ps_elp_sleep(wl);
2715
2716out:
2717 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002718 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719}
2720
Eliad Peller170d0e62011-10-05 11:56:06 +02002721static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2722 u8 id, u8 key_type, u8 key_size,
2723 const u8 *key, u8 hlid, u32 tx_seq_32,
2724 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002725{
2726 struct wl1271_ap_key *ap_key;
2727 int i;
2728
2729 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2730
2731 if (key_size > MAX_KEY_SIZE)
2732 return -EINVAL;
2733
2734 /*
2735 * Find next free entry in ap_keys. Also check we are not replacing
2736 * an existing key.
2737 */
2738 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002739 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002740 break;
2741
Eliad Peller170d0e62011-10-05 11:56:06 +02002742 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002743 wl1271_warning("trying to record key replacement");
2744 return -EINVAL;
2745 }
2746 }
2747
2748 if (i == MAX_NUM_KEYS)
2749 return -EBUSY;
2750
2751 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2752 if (!ap_key)
2753 return -ENOMEM;
2754
2755 ap_key->id = id;
2756 ap_key->key_type = key_type;
2757 ap_key->key_size = key_size;
2758 memcpy(ap_key->key, key, key_size);
2759 ap_key->hlid = hlid;
2760 ap_key->tx_seq_32 = tx_seq_32;
2761 ap_key->tx_seq_16 = tx_seq_16;
2762
Eliad Peller170d0e62011-10-05 11:56:06 +02002763 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002764 return 0;
2765}
2766
Eliad Peller170d0e62011-10-05 11:56:06 +02002767static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002768{
2769 int i;
2770
2771 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 kfree(wlvif->ap.recorded_keys[i]);
2773 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002774 }
2775}
2776
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002777static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778{
2779 int i, ret = 0;
2780 struct wl1271_ap_key *key;
2781 bool wep_key_added = false;
2782
2783 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002784 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002785 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002786 break;
2787
Eliad Peller170d0e62011-10-05 11:56:06 +02002788 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002789 hlid = key->hlid;
2790 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002791 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002792
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002793 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794 key->id, key->key_type,
2795 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002796 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 key->tx_seq_16);
2798 if (ret < 0)
2799 goto out;
2800
2801 if (key->key_type == KEY_WEP)
2802 wep_key_added = true;
2803 }
2804
2805 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002806 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002807 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808 if (ret < 0)
2809 goto out;
2810 }
2811
2812out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002813 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 return ret;
2815}
2816
Eliad Peller536129c2011-10-05 11:55:45 +02002817static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2818 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002819 u8 key_size, const u8 *key, u32 tx_seq_32,
2820 u16 tx_seq_16, struct ieee80211_sta *sta)
2821{
2822 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002823 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824
2825 if (is_ap) {
2826 struct wl1271_station *wl_sta;
2827 u8 hlid;
2828
2829 if (sta) {
2830 wl_sta = (struct wl1271_station *)sta->drv_priv;
2831 hlid = wl_sta->hlid;
2832 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002833 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 }
2835
Eliad Peller53d40d02011-10-10 10:13:02 +02002836 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002837 /*
2838 * We do not support removing keys after AP shutdown.
2839 * Pretend we do to make mac80211 happy.
2840 */
2841 if (action != KEY_ADD_OR_REPLACE)
2842 return 0;
2843
Eliad Peller170d0e62011-10-05 11:56:06 +02002844 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002845 key_type, key_size,
2846 key, hlid, tx_seq_32,
2847 tx_seq_16);
2848 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002849 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 id, key_type, key_size,
2851 key, hlid, tx_seq_32,
2852 tx_seq_16);
2853 }
2854
2855 if (ret < 0)
2856 return ret;
2857 } else {
2858 const u8 *addr;
2859 static const u8 bcast_addr[ETH_ALEN] = {
2860 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2861 };
2862
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002863 /*
2864 * A STA set to GEM cipher requires 2 tx spare blocks.
2865 * Return to default value when GEM cipher key is removed
2866 */
2867 if (key_type == KEY_GEM) {
2868 if (action == KEY_ADD_OR_REPLACE)
2869 wl->tx_spare_blocks = 2;
2870 else if (action == KEY_REMOVE)
2871 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2872 }
2873
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002874 addr = sta ? sta->addr : bcast_addr;
2875
2876 if (is_zero_ether_addr(addr)) {
2877 /* We dont support TX only encryption */
2878 return -EOPNOTSUPP;
2879 }
2880
2881 /* The wl1271 does not allow to remove unicast keys - they
2882 will be cleared automatically on next CMD_JOIN. Ignore the
2883 request silently, as we dont want the mac80211 to emit
2884 an error message. */
2885 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2886 return 0;
2887
Eliad Peller010d3d32011-08-14 13:17:31 +03002888 /* don't remove key if hlid was already deleted */
2889 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002890 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002891 return 0;
2892
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002893 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002894 id, key_type, key_size,
2895 key, addr, tx_seq_32,
2896 tx_seq_16);
2897 if (ret < 0)
2898 return ret;
2899
2900 /* the default WEP key needs to be configured at least once */
2901 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002902 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002903 wlvif->default_key,
2904 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 if (ret < 0)
2906 return ret;
2907 }
2908 }
2909
2910 return 0;
2911}
2912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2914 struct ieee80211_vif *vif,
2915 struct ieee80211_sta *sta,
2916 struct ieee80211_key_conf *key_conf)
2917{
2918 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002919 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002921 u32 tx_seq_32 = 0;
2922 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 u8 key_type;
2924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2926
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002927 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002929 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 key_conf->keylen, key_conf->flags);
2931 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2932
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933 mutex_lock(&wl->mutex);
2934
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002935 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2936 ret = -EAGAIN;
2937 goto out_unlock;
2938 }
2939
Ido Yariva6208652011-03-01 15:14:41 +02002940 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 if (ret < 0)
2942 goto out_unlock;
2943
Johannes Berg97359d12010-08-10 09:46:38 +02002944 switch (key_conf->cipher) {
2945 case WLAN_CIPHER_SUITE_WEP40:
2946 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 key_type = KEY_WEP;
2948
2949 key_conf->hw_key_idx = key_conf->keyidx;
2950 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002951 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 key_type = KEY_TKIP;
2953
2954 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002955 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2956 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002958 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 key_type = KEY_AES;
2960
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002961 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002962 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2963 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002965 case WL1271_CIPHER_SUITE_GEM:
2966 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002967 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2968 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002969 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002971 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972
2973 ret = -EOPNOTSUPP;
2974 goto out_sleep;
2975 }
2976
2977 switch (cmd) {
2978 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002979 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002980 key_conf->keyidx, key_type,
2981 key_conf->keylen, key_conf->key,
2982 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 if (ret < 0) {
2984 wl1271_error("Could not add or replace key");
2985 goto out_sleep;
2986 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02002987
2988 /*
2989 * reconfiguring arp response if the unicast (or common)
2990 * encryption key type was changed
2991 */
2992 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
2993 (sta || key_type == KEY_WEP) &&
2994 wlvif->encryption_type != key_type) {
2995 wlvif->encryption_type = key_type;
2996 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
2997 if (ret < 0) {
2998 wl1271_warning("build arp rsp failed: %d", ret);
2999 goto out_sleep;
3000 }
3001 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002 break;
3003
3004 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003005 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003006 key_conf->keyidx, key_type,
3007 key_conf->keylen, key_conf->key,
3008 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 if (ret < 0) {
3010 wl1271_error("Could not remove key");
3011 goto out_sleep;
3012 }
3013 break;
3014
3015 default:
3016 wl1271_error("Unsupported key cmd 0x%x", cmd);
3017 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 break;
3019 }
3020
3021out_sleep:
3022 wl1271_ps_elp_sleep(wl);
3023
3024out_unlock:
3025 mutex_unlock(&wl->mutex);
3026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 return ret;
3028}
3029
3030static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003031 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 struct cfg80211_scan_request *req)
3033{
3034 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003035 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037 int ret;
3038 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003039 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040
3041 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3042
3043 if (req->n_ssids) {
3044 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003045 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 }
3047
3048 mutex_lock(&wl->mutex);
3049
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003050 if (wl->state == WL1271_STATE_OFF) {
3051 /*
3052 * We cannot return -EBUSY here because cfg80211 will expect
3053 * a call to ieee80211_scan_completed if we do - in this case
3054 * there won't be any call.
3055 */
3056 ret = -EAGAIN;
3057 goto out;
3058 }
3059
Ido Yariva6208652011-03-01 15:14:41 +02003060 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 if (ret < 0)
3062 goto out;
3063
Eliad Peller92e712d2011-12-18 20:25:43 +02003064 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3065 test_bit(wlvif->role_id, wl->roc_map)) {
3066 /* don't allow scanning right now */
3067 ret = -EBUSY;
3068 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003069 }
3070
Eliad Peller784f6942011-10-05 11:55:39 +02003071 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003072out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003073 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074out:
3075 mutex_unlock(&wl->mutex);
3076
3077 return ret;
3078}
3079
Eliad Peller73ecce32011-06-27 13:06:45 +03003080static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3081 struct ieee80211_vif *vif)
3082{
3083 struct wl1271 *wl = hw->priv;
3084 int ret;
3085
3086 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3087
3088 mutex_lock(&wl->mutex);
3089
3090 if (wl->state == WL1271_STATE_OFF)
3091 goto out;
3092
3093 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3094 goto out;
3095
3096 ret = wl1271_ps_elp_wakeup(wl);
3097 if (ret < 0)
3098 goto out;
3099
3100 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3101 ret = wl1271_scan_stop(wl);
3102 if (ret < 0)
3103 goto out_sleep;
3104 }
3105 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3106 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003107 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003108 wl->scan.req = NULL;
3109 ieee80211_scan_completed(wl->hw, true);
3110
3111out_sleep:
3112 wl1271_ps_elp_sleep(wl);
3113out:
3114 mutex_unlock(&wl->mutex);
3115
3116 cancel_delayed_work_sync(&wl->scan_complete_work);
3117}
3118
Luciano Coelho33c2c062011-05-10 14:46:02 +03003119static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3120 struct ieee80211_vif *vif,
3121 struct cfg80211_sched_scan_request *req,
3122 struct ieee80211_sched_scan_ies *ies)
3123{
3124 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003125 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003126 int ret;
3127
3128 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3129
3130 mutex_lock(&wl->mutex);
3131
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003132 if (wl->state == WL1271_STATE_OFF) {
3133 ret = -EAGAIN;
3134 goto out;
3135 }
3136
Luciano Coelho33c2c062011-05-10 14:46:02 +03003137 ret = wl1271_ps_elp_wakeup(wl);
3138 if (ret < 0)
3139 goto out;
3140
Eliad Peller536129c2011-10-05 11:55:45 +02003141 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003142 if (ret < 0)
3143 goto out_sleep;
3144
Eliad Peller536129c2011-10-05 11:55:45 +02003145 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003146 if (ret < 0)
3147 goto out_sleep;
3148
3149 wl->sched_scanning = true;
3150
3151out_sleep:
3152 wl1271_ps_elp_sleep(wl);
3153out:
3154 mutex_unlock(&wl->mutex);
3155 return ret;
3156}
3157
3158static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3159 struct ieee80211_vif *vif)
3160{
3161 struct wl1271 *wl = hw->priv;
3162 int ret;
3163
3164 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3165
3166 mutex_lock(&wl->mutex);
3167
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003168 if (wl->state == WL1271_STATE_OFF)
3169 goto out;
3170
Luciano Coelho33c2c062011-05-10 14:46:02 +03003171 ret = wl1271_ps_elp_wakeup(wl);
3172 if (ret < 0)
3173 goto out;
3174
3175 wl1271_scan_sched_scan_stop(wl);
3176
3177 wl1271_ps_elp_sleep(wl);
3178out:
3179 mutex_unlock(&wl->mutex);
3180}
3181
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003182static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3183{
3184 struct wl1271 *wl = hw->priv;
3185 int ret = 0;
3186
3187 mutex_lock(&wl->mutex);
3188
3189 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3190 ret = -EAGAIN;
3191 goto out;
3192 }
3193
Ido Yariva6208652011-03-01 15:14:41 +02003194 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003195 if (ret < 0)
3196 goto out;
3197
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003198 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003199 if (ret < 0)
3200 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3201
3202 wl1271_ps_elp_sleep(wl);
3203
3204out:
3205 mutex_unlock(&wl->mutex);
3206
3207 return ret;
3208}
3209
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003210static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3211{
3212 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003213 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003214 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003215
3216 mutex_lock(&wl->mutex);
3217
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003218 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3219 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003220 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003221 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003222
Ido Yariva6208652011-03-01 15:14:41 +02003223 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003224 if (ret < 0)
3225 goto out;
3226
Eliad Peller6e8cd332011-10-10 10:13:13 +02003227 wl12xx_for_each_wlvif(wl, wlvif) {
3228 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3229 if (ret < 0)
3230 wl1271_warning("set rts threshold failed: %d", ret);
3231 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003232 wl1271_ps_elp_sleep(wl);
3233
3234out:
3235 mutex_unlock(&wl->mutex);
3236
3237 return ret;
3238}
3239
Eliad Peller1fe9f162011-10-05 11:55:48 +02003240static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003241 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003242{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003243 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003244 u8 ssid_len;
3245 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3246 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003247
Eliad Peller889cb362011-05-01 09:56:45 +03003248 if (!ptr) {
3249 wl1271_error("No SSID in IEs!");
3250 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003251 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003252
Eliad Peller889cb362011-05-01 09:56:45 +03003253 ssid_len = ptr[1];
3254 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3255 wl1271_error("SSID is too long!");
3256 return -EINVAL;
3257 }
3258
Eliad Peller1fe9f162011-10-05 11:55:48 +02003259 wlvif->ssid_len = ssid_len;
3260 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003261 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003262}
3263
Eliad Pellerd48055d2011-09-15 12:07:04 +03003264static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3265{
3266 int len;
3267 const u8 *next, *end = skb->data + skb->len;
3268 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3269 skb->len - ieoffset);
3270 if (!ie)
3271 return;
3272 len = ie[1] + 2;
3273 next = ie + len;
3274 memmove(ie, next, end - next);
3275 skb_trim(skb, skb->len - len);
3276}
3277
Eliad Peller26b4bf22011-09-15 12:07:05 +03003278static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3279 unsigned int oui, u8 oui_type,
3280 int ieoffset)
3281{
3282 int len;
3283 const u8 *next, *end = skb->data + skb->len;
3284 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3285 skb->data + ieoffset,
3286 skb->len - ieoffset);
3287 if (!ie)
3288 return;
3289 len = ie[1] + 2;
3290 next = ie + len;
3291 memmove(ie, next, end - next);
3292 skb_trim(skb, skb->len - len);
3293}
3294
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003295static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3296 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003297{
Eliad Pellercdaac622012-01-31 11:57:16 +02003298 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003299 struct sk_buff *skb;
3300 int ret;
3301
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003302 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003303 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003304 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003305
Eliad Pellercdaac622012-01-31 11:57:16 +02003306 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003307 CMD_TEMPL_AP_PROBE_RESPONSE,
3308 skb->data,
3309 skb->len, 0,
3310 rates);
3311
3312 dev_kfree_skb(skb);
3313 return ret;
3314}
3315
3316static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3317 struct ieee80211_vif *vif,
3318 u8 *probe_rsp_data,
3319 size_t probe_rsp_len,
3320 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003321{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003322 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3323 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003324 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3325 int ssid_ie_offset, ie_offset, templ_len;
3326 const u8 *ptr;
3327
3328 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003329 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003330 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003331 CMD_TEMPL_AP_PROBE_RESPONSE,
3332 probe_rsp_data,
3333 probe_rsp_len, 0,
3334 rates);
3335
3336 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3337 wl1271_error("probe_rsp template too big");
3338 return -EINVAL;
3339 }
3340
3341 /* start searching from IE offset */
3342 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3343
3344 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3345 probe_rsp_len - ie_offset);
3346 if (!ptr) {
3347 wl1271_error("No SSID in beacon!");
3348 return -EINVAL;
3349 }
3350
3351 ssid_ie_offset = ptr - probe_rsp_data;
3352 ptr += (ptr[1] + 2);
3353
3354 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3355
3356 /* insert SSID from bss_conf */
3357 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3358 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3359 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3360 bss_conf->ssid, bss_conf->ssid_len);
3361 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3362
3363 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3364 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3365 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3366
Eliad Pellercdaac622012-01-31 11:57:16 +02003367 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003368 CMD_TEMPL_AP_PROBE_RESPONSE,
3369 probe_rsp_templ,
3370 templ_len, 0,
3371 rates);
3372}
3373
Arik Nemtsove78a2872010-10-16 19:07:21 +02003374static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003375 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003376 struct ieee80211_bss_conf *bss_conf,
3377 u32 changed)
3378{
Eliad Peller0603d892011-10-05 11:55:51 +02003379 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 int ret = 0;
3381
3382 if (changed & BSS_CHANGED_ERP_SLOT) {
3383 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003384 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003385 else
Eliad Peller0603d892011-10-05 11:55:51 +02003386 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003387 if (ret < 0) {
3388 wl1271_warning("Set slot time failed %d", ret);
3389 goto out;
3390 }
3391 }
3392
3393 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3394 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003395 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003396 else
Eliad Peller0603d892011-10-05 11:55:51 +02003397 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003398 }
3399
3400 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3401 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003402 ret = wl1271_acx_cts_protect(wl, wlvif,
3403 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 else
Eliad Peller0603d892011-10-05 11:55:51 +02003405 ret = wl1271_acx_cts_protect(wl, wlvif,
3406 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003407 if (ret < 0) {
3408 wl1271_warning("Set ctsprotect failed %d", ret);
3409 goto out;
3410 }
3411 }
3412
3413out:
3414 return ret;
3415}
3416
3417static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3418 struct ieee80211_vif *vif,
3419 struct ieee80211_bss_conf *bss_conf,
3420 u32 changed)
3421{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003422 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003423 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424 int ret = 0;
3425
3426 if ((changed & BSS_CHANGED_BEACON_INT)) {
3427 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3428 bss_conf->beacon_int);
3429
Eliad Peller6a899792011-10-05 11:55:58 +02003430 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003431 }
3432
Arik Nemtsov560f0022011-11-08 18:46:54 +02003433 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3434 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003435 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3436 wl1271_debug(DEBUG_AP, "probe response updated");
3437 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3438 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003439 }
3440
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441 if ((changed & BSS_CHANGED_BEACON)) {
3442 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003443 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003444 int ieoffset = offsetof(struct ieee80211_mgmt,
3445 u.beacon.variable);
3446 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3447 u16 tmpl_id;
3448
Arik Nemtsov560f0022011-11-08 18:46:54 +02003449 if (!beacon) {
3450 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003452 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003453
3454 wl1271_debug(DEBUG_MASTER, "beacon updated");
3455
Eliad Peller1fe9f162011-10-05 11:55:48 +02003456 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457 if (ret < 0) {
3458 dev_kfree_skb(beacon);
3459 goto out;
3460 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003461 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003462 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3463 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003464 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003465 beacon->data,
3466 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003467 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003468 if (ret < 0) {
3469 dev_kfree_skb(beacon);
3470 goto out;
3471 }
3472
Arik Nemtsov560f0022011-11-08 18:46:54 +02003473 /*
3474 * In case we already have a probe-resp beacon set explicitly
3475 * by usermode, don't use the beacon data.
3476 */
3477 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3478 goto end_bcn;
3479
Eliad Pellerd48055d2011-09-15 12:07:04 +03003480 /* remove TIM ie from probe response */
3481 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3482
Eliad Peller26b4bf22011-09-15 12:07:05 +03003483 /*
3484 * remove p2p ie from probe response.
3485 * the fw reponds to probe requests that don't include
3486 * the p2p ie. probe requests with p2p ie will be passed,
3487 * and will be responded by the supplicant (the spec
3488 * forbids including the p2p ie when responding to probe
3489 * requests that didn't include it).
3490 */
3491 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3492 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3493
Arik Nemtsove78a2872010-10-16 19:07:21 +02003494 hdr = (struct ieee80211_hdr *) beacon->data;
3495 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3496 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003497 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003498 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003499 beacon->data,
3500 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003501 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003502 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003503 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003504 CMD_TEMPL_PROBE_RESPONSE,
3505 beacon->data,
3506 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003507 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003508end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003509 dev_kfree_skb(beacon);
3510 if (ret < 0)
3511 goto out;
3512 }
3513
3514out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003515 if (ret != 0)
3516 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003517 return ret;
3518}
3519
3520/* AP mode changes */
3521static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003522 struct ieee80211_vif *vif,
3523 struct ieee80211_bss_conf *bss_conf,
3524 u32 changed)
3525{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003526 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003527 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003528
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3530 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003531
Eliad Peller87fbcb02011-10-05 11:55:41 +02003532 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003533 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003534 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003535 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003536
Eliad Peller87fbcb02011-10-05 11:55:41 +02003537 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003539 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003540 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003541 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003542
Eliad Peller784f6942011-10-05 11:55:39 +02003543 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003544 if (ret < 0)
3545 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003546 }
3547
Arik Nemtsove78a2872010-10-16 19:07:21 +02003548 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3549 if (ret < 0)
3550 goto out;
3551
3552 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3553 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003554 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003555 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003556 if (ret < 0)
3557 goto out;
3558
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003559 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003560 if (ret < 0)
3561 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003562
Eliad Peller53d40d02011-10-10 10:13:02 +02003563 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003564 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003565 }
3566 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003567 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003568 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003569 if (ret < 0)
3570 goto out;
3571
Eliad Peller53d40d02011-10-10 10:13:02 +02003572 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003573 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3574 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003575 wl1271_debug(DEBUG_AP, "stopped AP");
3576 }
3577 }
3578 }
3579
Eliad Peller0603d892011-10-05 11:55:51 +02003580 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581 if (ret < 0)
3582 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003583
3584 /* Handle HT information change */
3585 if ((changed & BSS_CHANGED_HT) &&
3586 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003587 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003588 bss_conf->ht_operation_mode);
3589 if (ret < 0) {
3590 wl1271_warning("Set ht information failed %d", ret);
3591 goto out;
3592 }
3593 }
3594
Arik Nemtsove78a2872010-10-16 19:07:21 +02003595out:
3596 return;
3597}
3598
3599/* STA/IBSS mode changes */
3600static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3601 struct ieee80211_vif *vif,
3602 struct ieee80211_bss_conf *bss_conf,
3603 u32 changed)
3604{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003605 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003606 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003607 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003608 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003609 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003611 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003612 bool sta_exists = false;
3613 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003614
3615 if (is_ibss) {
3616 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3617 changed);
3618 if (ret < 0)
3619 goto out;
3620 }
3621
Eliad Peller227e81e2011-08-14 13:17:26 +03003622 if (changed & BSS_CHANGED_IBSS) {
3623 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003624 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003625 ibss_joined = true;
3626 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003627 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3628 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003629 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003630 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003631 }
3632 }
3633 }
3634
3635 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003636 do_join = true;
3637
3638 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003639 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003640 do_join = true;
3641
Eliad Peller227e81e2011-08-14 13:17:26 +03003642 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003643 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3644 bss_conf->enable_beacon ? "enabled" : "disabled");
3645
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003646 do_join = true;
3647 }
3648
Eliad Pellerc31e4942011-10-23 08:21:55 +02003649 if (changed & BSS_CHANGED_IDLE) {
3650 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3651 if (ret < 0)
3652 wl1271_warning("idle mode change failed %d", ret);
3653 }
3654
Arik Nemtsove78a2872010-10-16 19:07:21 +02003655 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003656 bool enable = false;
3657 if (bss_conf->cqm_rssi_thold)
3658 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003659 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003660 bss_conf->cqm_rssi_thold,
3661 bss_conf->cqm_rssi_hyst);
3662 if (ret < 0)
3663 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003664 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003665 }
3666
Eliad Peller7db4ee62012-01-24 18:18:42 +02003667 if (changed & BSS_CHANGED_BSSID &&
3668 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003669 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003670 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003671 if (ret < 0)
3672 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003673
Eliad Peller784f6942011-10-05 11:55:39 +02003674 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003675 if (ret < 0)
3676 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003677
Eliad Pellerfa287b82010-12-26 09:27:50 +01003678 /* Need to update the BSSID (for filtering etc) */
3679 do_join = true;
3680 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003681
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003682 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3683 rcu_read_lock();
3684 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3685 if (!sta)
3686 goto sta_not_found;
3687
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003688 /* save the supp_rates of the ap */
3689 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3690 if (sta->ht_cap.ht_supported)
3691 sta_rate_set |=
3692 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003693 sta_ht_cap = sta->ht_cap;
3694 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003695
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003696sta_not_found:
3697 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003698 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699
Arik Nemtsove78a2872010-10-16 19:07:21 +02003700 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003701 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003702 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003703 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003704 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003705 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003706
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003707 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003708 * use basic rates from AP, and determine lowest rate
3709 * to use with control frames.
3710 */
3711 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003712 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003713 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003714 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003715 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003716 wl1271_tx_min_rate_get(wl,
3717 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003718 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003719 wlvif->rate_set =
3720 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003721 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003722 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003723 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003724 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003725 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003726
3727 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003728 * with wl1271, we don't need to update the
3729 * beacon_int and dtim_period, because the firmware
3730 * updates it by itself when the first beacon is
3731 * received after a join.
3732 */
Eliad Peller6840e372011-10-05 11:55:50 +02003733 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003734 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003735 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003736
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003737 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003738 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003739 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003740 dev_kfree_skb(wlvif->probereq);
3741 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003742 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003743 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003744 ieoffset = offsetof(struct ieee80211_mgmt,
3745 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003746 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003747
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003748 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003749 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003750 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003751 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003752 } else {
3753 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003754 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003755 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3756 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003757 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003758 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3759 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003760 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003761
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003762 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003763 dev_kfree_skb(wlvif->probereq);
3764 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003765
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003766 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003767 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003768 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003769 wl1271_tx_min_rate_get(wl,
3770 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003771 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003772 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003773 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003774
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003775 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003776 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003777
3778 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003779 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003780 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003781 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003782
3783 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003784 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003785 u32 conf_flags = wl->hw->conf.flags;
3786 /*
3787 * we might have to disable roc, if there was
3788 * no IF_OPER_UP notification.
3789 */
3790 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003791 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003792 if (ret < 0)
3793 goto out;
3794 }
3795 /*
3796 * (we also need to disable roc in case of
3797 * roaming on the same channel. until we will
3798 * have a better flow...)
3799 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003800 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3801 ret = wl12xx_croc(wl,
3802 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003803 if (ret < 0)
3804 goto out;
3805 }
3806
Eliad Peller0603d892011-10-05 11:55:51 +02003807 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003808 if (!(conf_flags & IEEE80211_CONF_IDLE))
3809 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003810 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003811 }
3812 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003813
Eliad Pellerd192d262011-05-24 14:33:08 +03003814 if (changed & BSS_CHANGED_IBSS) {
3815 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3816 bss_conf->ibss_joined);
3817
3818 if (bss_conf->ibss_joined) {
3819 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003820 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003821 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003822 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003823 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003824 wl1271_tx_min_rate_get(wl,
3825 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003826
Shahar Levi06b660e2011-09-05 13:54:36 +03003827 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003828 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3829 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003830 if (ret < 0)
3831 goto out;
3832 }
3833 }
3834
Eliad Peller0603d892011-10-05 11:55:51 +02003835 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003836 if (ret < 0)
3837 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003838
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003839 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003840 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003841 if (ret < 0) {
3842 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003843 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003844 }
Eliad Peller251c1772011-08-14 13:17:17 +03003845
3846 /* ROC until connected (after EAPOL exchange) */
3847 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003848 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003849 if (ret < 0)
3850 goto out;
3851
Eliad Pellerba8447f2011-10-10 10:13:00 +02003852 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003853 ieee80211_get_operstate(vif));
3854 }
3855 /*
3856 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003857 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003858 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003859 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003860 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003861 if (ret < 0)
3862 goto out;
3863 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003864 }
3865
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003866 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003867 if (sta_exists) {
3868 if ((changed & BSS_CHANGED_HT) &&
3869 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003870 ret = wl1271_acx_set_ht_capabilities(wl,
3871 &sta_ht_cap,
3872 true,
Eliad Peller154da672011-10-05 11:55:53 +02003873 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003874 if (ret < 0) {
3875 wl1271_warning("Set ht cap true failed %d",
3876 ret);
3877 goto out;
3878 }
3879 }
3880 /* handle new association without HT and disassociation */
3881 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003882 ret = wl1271_acx_set_ht_capabilities(wl,
3883 &sta_ht_cap,
3884 false,
Eliad Peller154da672011-10-05 11:55:53 +02003885 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003886 if (ret < 0) {
3887 wl1271_warning("Set ht cap false failed %d",
3888 ret);
3889 goto out;
3890 }
3891 }
3892 }
3893
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003894 /* Handle HT information change. Done after join. */
3895 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003896 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003897 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003898 bss_conf->ht_operation_mode);
3899 if (ret < 0) {
3900 wl1271_warning("Set ht information failed %d", ret);
3901 goto out;
3902 }
3903 }
3904
Eliad Peller76a74c82012-02-02 12:22:11 +02003905 /* Handle arp filtering. Done after join. */
3906 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3907 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3908 __be32 addr = bss_conf->arp_addr_list[0];
3909 wlvif->sta.qos = bss_conf->qos;
3910 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3911
3912 if (bss_conf->arp_addr_cnt == 1 &&
3913 bss_conf->arp_filter_enabled) {
3914 wlvif->ip_addr = addr;
3915 /*
3916 * The template should have been configured only upon
3917 * association. however, it seems that the correct ip
3918 * isn't being set (when sending), so we have to
3919 * reconfigure the template upon every ip change.
3920 */
3921 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3922 if (ret < 0) {
3923 wl1271_warning("build arp rsp failed: %d", ret);
3924 goto out;
3925 }
3926
3927 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3928 (ACX_ARP_FILTER_ARP_FILTERING |
3929 ACX_ARP_FILTER_AUTO_ARP),
3930 addr);
3931 } else {
3932 wlvif->ip_addr = 0;
3933 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
3934 }
3935
3936 if (ret < 0)
3937 goto out;
3938 }
3939
Arik Nemtsove78a2872010-10-16 19:07:21 +02003940out:
3941 return;
3942}
3943
3944static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3945 struct ieee80211_vif *vif,
3946 struct ieee80211_bss_conf *bss_conf,
3947 u32 changed)
3948{
3949 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003950 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3951 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003952 int ret;
3953
3954 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3955 (int)changed);
3956
3957 mutex_lock(&wl->mutex);
3958
3959 if (unlikely(wl->state == WL1271_STATE_OFF))
3960 goto out;
3961
Eliad Peller10c8cd02011-10-10 10:13:06 +02003962 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3963 goto out;
3964
Ido Yariva6208652011-03-01 15:14:41 +02003965 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003966 if (ret < 0)
3967 goto out;
3968
3969 if (is_ap)
3970 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3971 else
3972 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3973
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003974 wl1271_ps_elp_sleep(wl);
3975
3976out:
3977 mutex_unlock(&wl->mutex);
3978}
3979
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003980static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3981 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003982 const struct ieee80211_tx_queue_params *params)
3983{
3984 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003985 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003986 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003987 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003988
3989 mutex_lock(&wl->mutex);
3990
3991 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3992
Kalle Valo4695dc92010-03-18 12:26:38 +02003993 if (params->uapsd)
3994 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3995 else
3996 ps_scheme = CONF_PS_SCHEME_LEGACY;
3997
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003998 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003999 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004000
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004001 ret = wl1271_ps_elp_wakeup(wl);
4002 if (ret < 0)
4003 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004004
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004005 /*
4006 * the txop is confed in units of 32us by the mac80211,
4007 * we need us
4008 */
Eliad Peller0603d892011-10-05 11:55:51 +02004009 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004010 params->cw_min, params->cw_max,
4011 params->aifs, params->txop << 5);
4012 if (ret < 0)
4013 goto out_sleep;
4014
Eliad Peller0603d892011-10-05 11:55:51 +02004015 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004016 CONF_CHANNEL_TYPE_EDCF,
4017 wl1271_tx_get_queue(queue),
4018 ps_scheme, CONF_ACK_POLICY_LEGACY,
4019 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004020
4021out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004022 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004023
4024out:
4025 mutex_unlock(&wl->mutex);
4026
4027 return ret;
4028}
4029
Eliad Peller37a41b42011-09-21 14:06:11 +03004030static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4031 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004032{
4033
4034 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004035 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004036 u64 mactime = ULLONG_MAX;
4037 int ret;
4038
4039 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4040
4041 mutex_lock(&wl->mutex);
4042
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004043 if (unlikely(wl->state == WL1271_STATE_OFF))
4044 goto out;
4045
Ido Yariva6208652011-03-01 15:14:41 +02004046 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004047 if (ret < 0)
4048 goto out;
4049
Eliad Peller9c531142012-01-31 11:57:18 +02004050 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004051 if (ret < 0)
4052 goto out_sleep;
4053
4054out_sleep:
4055 wl1271_ps_elp_sleep(wl);
4056
4057out:
4058 mutex_unlock(&wl->mutex);
4059 return mactime;
4060}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004061
John W. Linvilleece550d2010-07-28 16:41:06 -04004062static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4063 struct survey_info *survey)
4064{
4065 struct wl1271 *wl = hw->priv;
4066 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004067
John W. Linvilleece550d2010-07-28 16:41:06 -04004068 if (idx != 0)
4069 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004070
John W. Linvilleece550d2010-07-28 16:41:06 -04004071 survey->channel = conf->channel;
4072 survey->filled = SURVEY_INFO_NOISE_DBM;
4073 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004074
John W. Linvilleece550d2010-07-28 16:41:06 -04004075 return 0;
4076}
4077
Arik Nemtsov409622e2011-02-23 00:22:29 +02004078static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004079 struct wl12xx_vif *wlvif,
4080 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004081{
4082 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004083 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004084
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085
4086 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004087 wl1271_warning("could not allocate HLID - too much stations");
4088 return -EBUSY;
4089 }
4090
4091 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004092 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4093 if (ret < 0) {
4094 wl1271_warning("could not allocate HLID - too many links");
4095 return -EBUSY;
4096 }
4097
4098 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004099 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004100 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004101 return 0;
4102}
4103
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004104void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004106 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004107 return;
4108
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004109 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004110 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004111 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004112 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004113 __clear_bit(hlid, &wl->ap_ps_map);
4114 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004115 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004116 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117}
4118
4119static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4120 struct ieee80211_vif *vif,
4121 struct ieee80211_sta *sta)
4122{
4123 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004124 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004125 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 int ret = 0;
4127 u8 hlid;
4128
4129 mutex_lock(&wl->mutex);
4130
4131 if (unlikely(wl->state == WL1271_STATE_OFF))
4132 goto out;
4133
Eliad Peller536129c2011-10-05 11:55:45 +02004134 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004135 goto out;
4136
4137 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4138
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004139 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004140 if (ret < 0)
4141 goto out;
4142
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004143 wl_sta = (struct wl1271_station *)sta->drv_priv;
4144 hlid = wl_sta->hlid;
4145
Ido Yariva6208652011-03-01 15:14:41 +02004146 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004147 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004148 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149
Eliad Peller1b92f152011-10-10 10:13:09 +02004150 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151 if (ret < 0)
4152 goto out_sleep;
4153
Eliad Pellerb67476e2011-08-14 13:17:23 +03004154 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4155 if (ret < 0)
4156 goto out_sleep;
4157
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004158 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4159 if (ret < 0)
4160 goto out_sleep;
4161
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162out_sleep:
4163 wl1271_ps_elp_sleep(wl);
4164
Arik Nemtsov409622e2011-02-23 00:22:29 +02004165out_free_sta:
4166 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004167 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004168
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004169out:
4170 mutex_unlock(&wl->mutex);
4171 return ret;
4172}
4173
4174static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4175 struct ieee80211_vif *vif,
4176 struct ieee80211_sta *sta)
4177{
4178 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004179 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004180 struct wl1271_station *wl_sta;
4181 int ret = 0, id;
4182
4183 mutex_lock(&wl->mutex);
4184
4185 if (unlikely(wl->state == WL1271_STATE_OFF))
4186 goto out;
4187
Eliad Peller536129c2011-10-05 11:55:45 +02004188 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004189 goto out;
4190
4191 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4192
4193 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004194 id = wl_sta->hlid;
4195 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004196 goto out;
4197
Ido Yariva6208652011-03-01 15:14:41 +02004198 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004199 if (ret < 0)
4200 goto out;
4201
Eliad Pellerc690ec82011-08-14 13:17:07 +03004202 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004203 if (ret < 0)
4204 goto out_sleep;
4205
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004206 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004207
4208out_sleep:
4209 wl1271_ps_elp_sleep(wl);
4210
4211out:
4212 mutex_unlock(&wl->mutex);
4213 return ret;
4214}
4215
Luciano Coelho4623ec72011-03-21 19:26:41 +02004216static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4217 struct ieee80211_vif *vif,
4218 enum ieee80211_ampdu_mlme_action action,
4219 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4220 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004221{
4222 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004223 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004224 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004225 u8 hlid, *ba_bitmap;
4226
4227 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4228 tid);
4229
4230 /* sanity check - the fields in FW are only 8bits wide */
4231 if (WARN_ON(tid > 0xFF))
4232 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004233
4234 mutex_lock(&wl->mutex);
4235
4236 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4237 ret = -EAGAIN;
4238 goto out;
4239 }
4240
Eliad Peller536129c2011-10-05 11:55:45 +02004241 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004242 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004243 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004244 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004245 struct wl1271_station *wl_sta;
4246
4247 wl_sta = (struct wl1271_station *)sta->drv_priv;
4248 hlid = wl_sta->hlid;
4249 ba_bitmap = &wl->links[hlid].ba_bitmap;
4250 } else {
4251 ret = -EINVAL;
4252 goto out;
4253 }
4254
Ido Yariva6208652011-03-01 15:14:41 +02004255 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004256 if (ret < 0)
4257 goto out;
4258
Shahar Levi70559a02011-05-22 16:10:22 +03004259 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4260 tid, action);
4261
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004262 switch (action) {
4263 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004264 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004265 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004266 break;
4267 }
4268
4269 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4270 ret = -EBUSY;
4271 wl1271_error("exceeded max RX BA sessions");
4272 break;
4273 }
4274
4275 if (*ba_bitmap & BIT(tid)) {
4276 ret = -EINVAL;
4277 wl1271_error("cannot enable RX BA session on active "
4278 "tid: %d", tid);
4279 break;
4280 }
4281
4282 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4283 hlid);
4284 if (!ret) {
4285 *ba_bitmap |= BIT(tid);
4286 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004287 }
4288 break;
4289
4290 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004291 if (!(*ba_bitmap & BIT(tid))) {
4292 ret = -EINVAL;
4293 wl1271_error("no active RX BA session on tid: %d",
4294 tid);
4295 break;
4296 }
4297
4298 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4299 hlid);
4300 if (!ret) {
4301 *ba_bitmap &= ~BIT(tid);
4302 wl->ba_rx_session_count--;
4303 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004304 break;
4305
4306 /*
4307 * The BA initiator session management in FW independently.
4308 * Falling break here on purpose for all TX APDU commands.
4309 */
4310 case IEEE80211_AMPDU_TX_START:
4311 case IEEE80211_AMPDU_TX_STOP:
4312 case IEEE80211_AMPDU_TX_OPERATIONAL:
4313 ret = -EINVAL;
4314 break;
4315
4316 default:
4317 wl1271_error("Incorrect ampdu action id=%x\n", action);
4318 ret = -EINVAL;
4319 }
4320
4321 wl1271_ps_elp_sleep(wl);
4322
4323out:
4324 mutex_unlock(&wl->mutex);
4325
4326 return ret;
4327}
4328
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004329static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4330 struct ieee80211_vif *vif,
4331 const struct cfg80211_bitrate_mask *mask)
4332{
Eliad Peller83587502011-10-10 10:12:53 +02004333 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004334 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004335 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336
4337 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4338 mask->control[NL80211_BAND_2GHZ].legacy,
4339 mask->control[NL80211_BAND_5GHZ].legacy);
4340
4341 mutex_lock(&wl->mutex);
4342
4343 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004344 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004345 wl1271_tx_enabled_rates_get(wl,
4346 mask->control[i].legacy,
4347 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004348
4349 if (unlikely(wl->state == WL1271_STATE_OFF))
4350 goto out;
4351
4352 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4353 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4354
4355 ret = wl1271_ps_elp_wakeup(wl);
4356 if (ret < 0)
4357 goto out;
4358
4359 wl1271_set_band_rate(wl, wlvif);
4360 wlvif->basic_rate =
4361 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4362 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4363
4364 wl1271_ps_elp_sleep(wl);
4365 }
4366out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004367 mutex_unlock(&wl->mutex);
4368
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004369 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004370}
4371
Shahar Levi6d158ff2011-09-08 13:01:33 +03004372static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4373 struct ieee80211_channel_switch *ch_switch)
4374{
4375 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004376 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004377 int ret;
4378
4379 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4380
4381 mutex_lock(&wl->mutex);
4382
4383 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004384 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4385 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4386 ieee80211_chswitch_done(vif, false);
4387 }
4388 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004389 }
4390
4391 ret = wl1271_ps_elp_wakeup(wl);
4392 if (ret < 0)
4393 goto out;
4394
Eliad Peller52630c52011-10-10 10:13:08 +02004395 /* TODO: change mac80211 to pass vif as param */
4396 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004397 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004398
Eliad Peller52630c52011-10-10 10:13:08 +02004399 if (!ret)
4400 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4401 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004402
4403 wl1271_ps_elp_sleep(wl);
4404
4405out:
4406 mutex_unlock(&wl->mutex);
4407}
4408
Arik Nemtsov33437892011-04-26 23:35:39 +03004409static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4410{
4411 struct wl1271 *wl = hw->priv;
4412 bool ret = false;
4413
4414 mutex_lock(&wl->mutex);
4415
4416 if (unlikely(wl->state == WL1271_STATE_OFF))
4417 goto out;
4418
4419 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004420 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004421out:
4422 mutex_unlock(&wl->mutex);
4423
4424 return ret;
4425}
4426
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004427/* can't be const, mac80211 writes to this */
4428static struct ieee80211_rate wl1271_rates[] = {
4429 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4436 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004437 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4438 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004439 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4440 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004441 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4442 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004443 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4444 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004448 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4449 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004451 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4452 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004454 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4455 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004456 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004457 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4458 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004459 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004460 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4461 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004462 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004463 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4464 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004466 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4467 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004468};
4469
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004470/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004471static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004472 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004473 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004474 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4475 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4476 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004477 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004478 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4479 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4480 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004481 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004482 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4483 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4484 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004485 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004486};
4487
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004488/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004489static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004490 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004491 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004492 7, /* CONF_HW_RXTX_RATE_MCS7 */
4493 6, /* CONF_HW_RXTX_RATE_MCS6 */
4494 5, /* CONF_HW_RXTX_RATE_MCS5 */
4495 4, /* CONF_HW_RXTX_RATE_MCS4 */
4496 3, /* CONF_HW_RXTX_RATE_MCS3 */
4497 2, /* CONF_HW_RXTX_RATE_MCS2 */
4498 1, /* CONF_HW_RXTX_RATE_MCS1 */
4499 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004500
4501 11, /* CONF_HW_RXTX_RATE_54 */
4502 10, /* CONF_HW_RXTX_RATE_48 */
4503 9, /* CONF_HW_RXTX_RATE_36 */
4504 8, /* CONF_HW_RXTX_RATE_24 */
4505
4506 /* TI-specific rate */
4507 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4508
4509 7, /* CONF_HW_RXTX_RATE_18 */
4510 6, /* CONF_HW_RXTX_RATE_12 */
4511 3, /* CONF_HW_RXTX_RATE_11 */
4512 5, /* CONF_HW_RXTX_RATE_9 */
4513 4, /* CONF_HW_RXTX_RATE_6 */
4514 2, /* CONF_HW_RXTX_RATE_5_5 */
4515 1, /* CONF_HW_RXTX_RATE_2 */
4516 0 /* CONF_HW_RXTX_RATE_1 */
4517};
4518
Shahar Levie8b03a22010-10-13 16:09:39 +02004519/* 11n STA capabilities */
4520#define HW_RX_HIGHEST_RATE 72
4521
Shahar Levi00d20102010-11-08 11:20:10 +00004522#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004523 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4524 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004525 .ht_supported = true, \
4526 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4527 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4528 .mcs = { \
4529 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4530 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4531 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4532 }, \
4533}
4534
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004535/* can't be const, mac80211 writes to this */
4536static struct ieee80211_supported_band wl1271_band_2ghz = {
4537 .channels = wl1271_channels,
4538 .n_channels = ARRAY_SIZE(wl1271_channels),
4539 .bitrates = wl1271_rates,
4540 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004541 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004542};
4543
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004544/* 5 GHz data rates for WL1273 */
4545static struct ieee80211_rate wl1271_rates_5ghz[] = {
4546 { .bitrate = 60,
4547 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4548 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4549 { .bitrate = 90,
4550 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4551 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4552 { .bitrate = 120,
4553 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4554 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4555 { .bitrate = 180,
4556 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4557 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4558 { .bitrate = 240,
4559 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4560 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4561 { .bitrate = 360,
4562 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4563 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4564 { .bitrate = 480,
4565 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4566 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4567 { .bitrate = 540,
4568 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4569 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4570};
4571
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004572/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004573static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004574 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4575 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4576 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4577 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4578 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4579 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4580 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4581 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4582 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4583 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4584 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4585 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4586 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4587 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4588 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4589 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4590 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4591 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4592 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4593 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4594 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4595 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4596 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4597 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4598 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4599 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4600 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4601 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4602 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4603 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4604 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4605 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4606 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4607 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004608};
4609
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004610/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004611static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004612 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004613 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004614 7, /* CONF_HW_RXTX_RATE_MCS7 */
4615 6, /* CONF_HW_RXTX_RATE_MCS6 */
4616 5, /* CONF_HW_RXTX_RATE_MCS5 */
4617 4, /* CONF_HW_RXTX_RATE_MCS4 */
4618 3, /* CONF_HW_RXTX_RATE_MCS3 */
4619 2, /* CONF_HW_RXTX_RATE_MCS2 */
4620 1, /* CONF_HW_RXTX_RATE_MCS1 */
4621 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004622
4623 7, /* CONF_HW_RXTX_RATE_54 */
4624 6, /* CONF_HW_RXTX_RATE_48 */
4625 5, /* CONF_HW_RXTX_RATE_36 */
4626 4, /* CONF_HW_RXTX_RATE_24 */
4627
4628 /* TI-specific rate */
4629 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4630
4631 3, /* CONF_HW_RXTX_RATE_18 */
4632 2, /* CONF_HW_RXTX_RATE_12 */
4633 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4634 1, /* CONF_HW_RXTX_RATE_9 */
4635 0, /* CONF_HW_RXTX_RATE_6 */
4636 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4637 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4638 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4639};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004640
4641static struct ieee80211_supported_band wl1271_band_5ghz = {
4642 .channels = wl1271_channels_5ghz,
4643 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4644 .bitrates = wl1271_rates_5ghz,
4645 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004646 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004647};
4648
Tobias Klausera0ea9492010-05-20 10:38:11 +02004649static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004650 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4651 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4652};
4653
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004654static const struct ieee80211_ops wl1271_ops = {
4655 .start = wl1271_op_start,
4656 .stop = wl1271_op_stop,
4657 .add_interface = wl1271_op_add_interface,
4658 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004659 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004660#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004661 .suspend = wl1271_op_suspend,
4662 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004663#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004664 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004665 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666 .configure_filter = wl1271_op_configure_filter,
4667 .tx = wl1271_op_tx,
4668 .set_key = wl1271_op_set_key,
4669 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004670 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004671 .sched_scan_start = wl1271_op_sched_scan_start,
4672 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004673 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004674 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004675 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004676 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004677 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004678 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004679 .sta_add = wl1271_op_sta_add,
4680 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004681 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004682 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004683 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004684 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004685 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004686};
4687
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004688
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004689u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004690{
4691 u8 idx;
4692
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004693 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004694
4695 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4696 wl1271_error("Illegal RX rate from HW: %d", rate);
4697 return 0;
4698 }
4699
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004700 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004701 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4702 wl1271_error("Unsupported RX rate from HW: %d", rate);
4703 return 0;
4704 }
4705
4706 return idx;
4707}
4708
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004709static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4710 struct device_attribute *attr,
4711 char *buf)
4712{
4713 struct wl1271 *wl = dev_get_drvdata(dev);
4714 ssize_t len;
4715
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004716 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004717
4718 mutex_lock(&wl->mutex);
4719 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4720 wl->sg_enabled);
4721 mutex_unlock(&wl->mutex);
4722
4723 return len;
4724
4725}
4726
4727static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4728 struct device_attribute *attr,
4729 const char *buf, size_t count)
4730{
4731 struct wl1271 *wl = dev_get_drvdata(dev);
4732 unsigned long res;
4733 int ret;
4734
Luciano Coelho6277ed62011-04-01 17:49:54 +03004735 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004736 if (ret < 0) {
4737 wl1271_warning("incorrect value written to bt_coex_mode");
4738 return count;
4739 }
4740
4741 mutex_lock(&wl->mutex);
4742
4743 res = !!res;
4744
4745 if (res == wl->sg_enabled)
4746 goto out;
4747
4748 wl->sg_enabled = res;
4749
4750 if (wl->state == WL1271_STATE_OFF)
4751 goto out;
4752
Ido Yariva6208652011-03-01 15:14:41 +02004753 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004754 if (ret < 0)
4755 goto out;
4756
4757 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4758 wl1271_ps_elp_sleep(wl);
4759
4760 out:
4761 mutex_unlock(&wl->mutex);
4762 return count;
4763}
4764
4765static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4766 wl1271_sysfs_show_bt_coex_state,
4767 wl1271_sysfs_store_bt_coex_state);
4768
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004769static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4770 struct device_attribute *attr,
4771 char *buf)
4772{
4773 struct wl1271 *wl = dev_get_drvdata(dev);
4774 ssize_t len;
4775
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004776 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004777
4778 mutex_lock(&wl->mutex);
4779 if (wl->hw_pg_ver >= 0)
4780 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4781 else
4782 len = snprintf(buf, len, "n/a\n");
4783 mutex_unlock(&wl->mutex);
4784
4785 return len;
4786}
4787
Gery Kahn6f07b722011-07-18 14:21:49 +03004788static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004789 wl1271_sysfs_show_hw_pg_ver, NULL);
4790
Ido Yariv95dac04f2011-06-06 14:57:06 +03004791static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4792 struct bin_attribute *bin_attr,
4793 char *buffer, loff_t pos, size_t count)
4794{
4795 struct device *dev = container_of(kobj, struct device, kobj);
4796 struct wl1271 *wl = dev_get_drvdata(dev);
4797 ssize_t len;
4798 int ret;
4799
4800 ret = mutex_lock_interruptible(&wl->mutex);
4801 if (ret < 0)
4802 return -ERESTARTSYS;
4803
4804 /* Let only one thread read the log at a time, blocking others */
4805 while (wl->fwlog_size == 0) {
4806 DEFINE_WAIT(wait);
4807
4808 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4809 &wait,
4810 TASK_INTERRUPTIBLE);
4811
4812 if (wl->fwlog_size != 0) {
4813 finish_wait(&wl->fwlog_waitq, &wait);
4814 break;
4815 }
4816
4817 mutex_unlock(&wl->mutex);
4818
4819 schedule();
4820 finish_wait(&wl->fwlog_waitq, &wait);
4821
4822 if (signal_pending(current))
4823 return -ERESTARTSYS;
4824
4825 ret = mutex_lock_interruptible(&wl->mutex);
4826 if (ret < 0)
4827 return -ERESTARTSYS;
4828 }
4829
4830 /* Check if the fwlog is still valid */
4831 if (wl->fwlog_size < 0) {
4832 mutex_unlock(&wl->mutex);
4833 return 0;
4834 }
4835
4836 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4837 len = min(count, (size_t)wl->fwlog_size);
4838 wl->fwlog_size -= len;
4839 memcpy(buffer, wl->fwlog, len);
4840
4841 /* Make room for new messages */
4842 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4843
4844 mutex_unlock(&wl->mutex);
4845
4846 return len;
4847}
4848
4849static struct bin_attribute fwlog_attr = {
4850 .attr = {.name = "fwlog", .mode = S_IRUSR},
4851 .read = wl1271_sysfs_read_fwlog,
4852};
4853
Luciano Coelho5e037e72011-12-23 09:32:17 +02004854static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4855{
4856 bool supported = false;
4857 u8 major, minor;
4858
4859 if (wl->chip.id == CHIP_ID_1283_PG20) {
4860 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4861 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4862
4863 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4864 if (major > 2 || (major == 2 && minor >= 1))
4865 supported = true;
4866 } else {
4867 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4868 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4869
4870 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4871 if (major == 3 && minor >= 1)
4872 supported = true;
4873 }
4874
4875 wl1271_debug(DEBUG_PROBE,
4876 "PG Ver major = %d minor = %d, MAC %s present",
4877 major, minor, supported ? "is" : "is not");
4878
4879 return supported;
4880}
4881
4882static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4883 u32 oui, u32 nic, int n)
4884{
4885 int i;
4886
4887 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4888 oui, nic, n);
4889
4890 if (nic + n - 1 > 0xffffff)
4891 wl1271_warning("NIC part of the MAC address wraps around!");
4892
4893 for (i = 0; i < n; i++) {
4894 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4895 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4896 wl->addresses[i].addr[2] = (u8) oui;
4897 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4898 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4899 wl->addresses[i].addr[5] = (u8) nic;
4900 nic++;
4901 }
4902
4903 wl->hw->wiphy->n_addresses = n;
4904 wl->hw->wiphy->addresses = wl->addresses;
4905}
4906
4907static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4908{
4909 u32 mac1, mac2;
4910
4911 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4912
4913 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4914 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4915
4916 /* these are the two parts of the BD_ADDR */
4917 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4918 ((mac1 & 0xff000000) >> 24);
4919 wl->fuse_nic_addr = mac1 & 0xffffff;
4920
4921 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4922}
4923
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004924static int wl12xx_get_hw_info(struct wl1271 *wl)
4925{
4926 int ret;
4927 u32 die_info;
4928
4929 ret = wl12xx_set_power_on(wl);
4930 if (ret < 0)
4931 goto out;
4932
4933 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4934
4935 if (wl->chip.id == CHIP_ID_1283_PG20)
4936 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4937 else
4938 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4939
4940 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4941
Luciano Coelho5e037e72011-12-23 09:32:17 +02004942 if (!wl12xx_mac_in_fuse(wl)) {
4943 wl->fuse_oui_addr = 0;
4944 wl->fuse_nic_addr = 0;
4945 } else {
4946 wl12xx_get_fuse_mac(wl);
4947 }
4948
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004949 wl1271_power_off(wl);
4950out:
4951 return ret;
4952}
4953
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004954static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004955{
4956 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004957 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004958
4959 if (wl->mac80211_registered)
4960 return 0;
4961
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004962 ret = wl12xx_get_hw_info(wl);
4963 if (ret < 0) {
4964 wl1271_error("couldn't get hw info");
4965 goto out;
4966 }
4967
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004968 ret = wl1271_fetch_nvs(wl);
4969 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004970 /* NOTE: The wl->nvs->nvs element must be first, in
4971 * order to simplify the casting, we assume it is at
4972 * the beginning of the wl->nvs structure.
4973 */
4974 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004975
Luciano Coelho5e037e72011-12-23 09:32:17 +02004976 oui_addr =
4977 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4978 nic_addr =
4979 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004980 }
4981
Luciano Coelho5e037e72011-12-23 09:32:17 +02004982 /* if the MAC address is zeroed in the NVS derive from fuse */
4983 if (oui_addr == 0 && nic_addr == 0) {
4984 oui_addr = wl->fuse_oui_addr;
4985 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4986 nic_addr = wl->fuse_nic_addr + 1;
4987 }
4988
4989 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004990
4991 ret = ieee80211_register_hw(wl->hw);
4992 if (ret < 0) {
4993 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004994 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004995 }
4996
4997 wl->mac80211_registered = true;
4998
Eliad Pellerd60080a2010-11-24 12:53:16 +02004999 wl1271_debugfs_init(wl);
5000
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005001 register_netdevice_notifier(&wl1271_dev_notifier);
5002
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005003 wl1271_notice("loaded");
5004
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005005out:
5006 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005007}
5008
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005009static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005010{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005011 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02005012 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005013
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005014 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005015 ieee80211_unregister_hw(wl->hw);
5016 wl->mac80211_registered = false;
5017
5018}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005019
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005020static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005021{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005022 static const u32 cipher_suites[] = {
5023 WLAN_CIPHER_SUITE_WEP40,
5024 WLAN_CIPHER_SUITE_WEP104,
5025 WLAN_CIPHER_SUITE_TKIP,
5026 WLAN_CIPHER_SUITE_CCMP,
5027 WL1271_CIPHER_SUITE_GEM,
5028 };
5029
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005030 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02005031 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005032 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005033
5034 /* unit us */
5035 /* FIXME: find a proper value */
5036 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005037 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005038
5039 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005040 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005041 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005042 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005043 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005044 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005045 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005046 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005047 IEEE80211_HW_AP_LINK_PS |
5048 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005049 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
5050 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005051
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005052 wl->hw->wiphy->cipher_suites = cipher_suites;
5053 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5054
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005055 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005056 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5057 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005058 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005059 wl->hw->wiphy->max_sched_scan_ssids = 16;
5060 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005061 /*
5062 * Maximum length of elements in scanning probe request templates
5063 * should be the maximum length possible for a template, without
5064 * the IEEE80211 header of the template
5065 */
Ido Reisc08e3712012-02-02 13:54:27 +02005066 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005067 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005068
Ido Reisc08e3712012-02-02 13:54:27 +02005069 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005070 sizeof(struct ieee80211_header);
5071
Eliad Peller1ec23f72011-08-25 14:26:54 +03005072 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5073
Luciano Coelho4a31c112011-03-21 23:16:14 +02005074 /* make sure all our channels fit in the scanned_ch bitmask */
5075 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5076 ARRAY_SIZE(wl1271_channels_5ghz) >
5077 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005078 /*
5079 * We keep local copies of the band structs because we need to
5080 * modify them on a per-device basis.
5081 */
5082 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5083 sizeof(wl1271_band_2ghz));
5084 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5085 sizeof(wl1271_band_5ghz));
5086
5087 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5088 &wl->bands[IEEE80211_BAND_2GHZ];
5089 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5090 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005091
Kalle Valo12bd8942010-03-18 12:26:33 +02005092 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005093 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005094
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005095 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5096
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005097 /* the FW answers probe-requests in AP-mode */
5098 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5099 wl->hw->wiphy->probe_resp_offload =
5100 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5101 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5102 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5103
Felipe Balbia390e852011-10-06 10:07:44 +03005104 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005105
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005106 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005107 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005108
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005109 wl->hw->max_rx_aggregation_subframes = 8;
5110
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005111 return 0;
5112}
5113
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005114#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005115
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005116static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005117{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005118 struct ieee80211_hw *hw;
5119 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005120 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005121 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005122
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005123 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005124
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005125 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5126 if (!hw) {
5127 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005128 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005129 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005130 }
5131
5132 wl = hw->priv;
5133 memset(wl, 0, sizeof(*wl));
5134
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005135 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005136 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005137
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005138 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005139
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005140 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005141 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005142 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5143
Ido Yariva6208652011-03-01 15:14:41 +02005144 skb_queue_head_init(&wl->deferred_rx_queue);
5145 skb_queue_head_init(&wl->deferred_tx_queue);
5146
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005147 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005148 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005149 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5150 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5151 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005152
Eliad Peller92ef8962011-06-07 12:50:46 +03005153 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5154 if (!wl->freezable_wq) {
5155 ret = -ENOMEM;
5156 goto err_hw;
5157 }
5158
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005159 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005160 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005161 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005162 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005163 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005164 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005165 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005166 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005167 wl->ap_ps_map = 0;
5168 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005169 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005170 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005171 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005172 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005173 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005174 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005175 wl->fwlog_size = 0;
5176 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005177
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005178 /* The system link is always allocated */
5179 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5180
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005181 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005182 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005183 wl->tx_frames[i] = NULL;
5184
5185 spin_lock_init(&wl->wl_lock);
5186
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005187 wl->state = WL1271_STATE_OFF;
5188 mutex_init(&wl->mutex);
5189
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005190 /* Apply default driver configuration. */
5191 wl1271_conf_init(wl);
5192
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005193 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5194 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5195 if (!wl->aggr_buf) {
5196 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005197 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005198 }
5199
Ido Yariv990f5de2011-03-31 10:06:59 +02005200 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5201 if (!wl->dummy_packet) {
5202 ret = -ENOMEM;
5203 goto err_aggr;
5204 }
5205
Ido Yariv95dac04f2011-06-06 14:57:06 +03005206 /* Allocate one page for the FW log */
5207 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5208 if (!wl->fwlog) {
5209 ret = -ENOMEM;
5210 goto err_dummy_packet;
5211 }
5212
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005213 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005214
Ido Yariv990f5de2011-03-31 10:06:59 +02005215err_dummy_packet:
5216 dev_kfree_skb(wl->dummy_packet);
5217
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005218err_aggr:
5219 free_pages((unsigned long)wl->aggr_buf, order);
5220
Eliad Peller92ef8962011-06-07 12:50:46 +03005221err_wq:
5222 destroy_workqueue(wl->freezable_wq);
5223
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005224err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005225 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005226 ieee80211_free_hw(hw);
5227
5228err_hw_alloc:
5229
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005230 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005231}
5232
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005233static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005234{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005235 /* Unblock any fwlog readers */
5236 mutex_lock(&wl->mutex);
5237 wl->fwlog_size = -1;
5238 wake_up_interruptible_all(&wl->fwlog_waitq);
5239 mutex_unlock(&wl->mutex);
5240
Felipe Balbif79f8902011-10-06 13:05:25 +03005241 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005242
Felipe Balbif79f8902011-10-06 13:05:25 +03005243 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005244
Felipe Balbif79f8902011-10-06 13:05:25 +03005245 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005246 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005247 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005248 free_pages((unsigned long)wl->aggr_buf,
5249 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005250
5251 wl1271_debugfs_exit(wl);
5252
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005253 vfree(wl->fw);
5254 wl->fw = NULL;
5255 kfree(wl->nvs);
5256 wl->nvs = NULL;
5257
5258 kfree(wl->fw_status);
5259 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005260 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005261
5262 ieee80211_free_hw(wl->hw);
5263
5264 return 0;
5265}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005266
Felipe Balbia390e852011-10-06 10:07:44 +03005267static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5268{
5269 struct wl1271 *wl = cookie;
5270 unsigned long flags;
5271
5272 wl1271_debug(DEBUG_IRQ, "IRQ");
5273
5274 /* complete the ELP completion */
5275 spin_lock_irqsave(&wl->wl_lock, flags);
5276 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5277 if (wl->elp_compl) {
5278 complete(wl->elp_compl);
5279 wl->elp_compl = NULL;
5280 }
5281
5282 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5283 /* don't enqueue a work right now. mark it as pending */
5284 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5285 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5286 disable_irq_nosync(wl->irq);
5287 pm_wakeup_event(wl->dev, 0);
5288 spin_unlock_irqrestore(&wl->wl_lock, flags);
5289 return IRQ_HANDLED;
5290 }
5291 spin_unlock_irqrestore(&wl->wl_lock, flags);
5292
5293 return IRQ_WAKE_THREAD;
5294}
5295
Felipe Balbice2a2172011-10-05 14:12:55 +03005296static int __devinit wl12xx_probe(struct platform_device *pdev)
5297{
Felipe Balbia390e852011-10-06 10:07:44 +03005298 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5299 struct ieee80211_hw *hw;
5300 struct wl1271 *wl;
5301 unsigned long irqflags;
5302 int ret = -ENODEV;
5303
5304 hw = wl1271_alloc_hw();
5305 if (IS_ERR(hw)) {
5306 wl1271_error("can't allocate hw");
5307 ret = PTR_ERR(hw);
5308 goto out;
5309 }
5310
5311 wl = hw->priv;
5312 wl->irq = platform_get_irq(pdev, 0);
5313 wl->ref_clock = pdata->board_ref_clock;
5314 wl->tcxo_clock = pdata->board_tcxo_clock;
5315 wl->platform_quirks = pdata->platform_quirks;
5316 wl->set_power = pdata->set_power;
5317 wl->dev = &pdev->dev;
5318 wl->if_ops = pdata->ops;
5319
5320 platform_set_drvdata(pdev, wl);
5321
5322 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5323 irqflags = IRQF_TRIGGER_RISING;
5324 else
5325 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5326
5327 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5328 irqflags,
5329 pdev->name, wl);
5330 if (ret < 0) {
5331 wl1271_error("request_irq() failed: %d", ret);
5332 goto out_free_hw;
5333 }
5334
5335 ret = enable_irq_wake(wl->irq);
5336 if (!ret) {
5337 wl->irq_wake_enabled = true;
5338 device_init_wakeup(wl->dev, 1);
5339 if (pdata->pwr_in_suspend)
5340 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5341
5342 }
5343 disable_irq(wl->irq);
5344
5345 ret = wl1271_init_ieee80211(wl);
5346 if (ret)
5347 goto out_irq;
5348
5349 ret = wl1271_register_hw(wl);
5350 if (ret)
5351 goto out_irq;
5352
Felipe Balbif79f8902011-10-06 13:05:25 +03005353 /* Create sysfs file to control bt coex state */
5354 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5355 if (ret < 0) {
5356 wl1271_error("failed to create sysfs file bt_coex_state");
5357 goto out_irq;
5358 }
5359
5360 /* Create sysfs file to get HW PG version */
5361 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5362 if (ret < 0) {
5363 wl1271_error("failed to create sysfs file hw_pg_ver");
5364 goto out_bt_coex_state;
5365 }
5366
5367 /* Create sysfs file for the FW log */
5368 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5369 if (ret < 0) {
5370 wl1271_error("failed to create sysfs file fwlog");
5371 goto out_hw_pg_ver;
5372 }
5373
Felipe Balbice2a2172011-10-05 14:12:55 +03005374 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005375
Felipe Balbif79f8902011-10-06 13:05:25 +03005376out_hw_pg_ver:
5377 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5378
5379out_bt_coex_state:
5380 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5381
Felipe Balbia390e852011-10-06 10:07:44 +03005382out_irq:
5383 free_irq(wl->irq, wl);
5384
5385out_free_hw:
5386 wl1271_free_hw(wl);
5387
5388out:
5389 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005390}
5391
5392static int __devexit wl12xx_remove(struct platform_device *pdev)
5393{
Felipe Balbia390e852011-10-06 10:07:44 +03005394 struct wl1271 *wl = platform_get_drvdata(pdev);
5395
5396 if (wl->irq_wake_enabled) {
5397 device_init_wakeup(wl->dev, 0);
5398 disable_irq_wake(wl->irq);
5399 }
5400 wl1271_unregister_hw(wl);
5401 free_irq(wl->irq, wl);
5402 wl1271_free_hw(wl);
5403
Felipe Balbice2a2172011-10-05 14:12:55 +03005404 return 0;
5405}
5406
5407static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005408 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005409 { } /* Terminating Entry */
5410};
5411MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5412
5413static struct platform_driver wl12xx_driver = {
5414 .probe = wl12xx_probe,
5415 .remove = __devexit_p(wl12xx_remove),
5416 .id_table = wl12xx_id_table,
5417 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005418 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005419 .owner = THIS_MODULE,
5420 }
5421};
5422
5423static int __init wl12xx_init(void)
5424{
5425 return platform_driver_register(&wl12xx_driver);
5426}
5427module_init(wl12xx_init);
5428
5429static void __exit wl12xx_exit(void)
5430{
5431 platform_driver_unregister(&wl12xx_driver);
5432}
5433module_exit(wl12xx_exit);
5434
Guy Eilam491bbd62011-01-12 10:33:29 +01005435u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005436EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005437module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005438MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5439
Ido Yariv95dac04f2011-06-06 14:57:06 +03005440module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005441MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005442 "FW logger options: continuous, ondemand, dbgpins or disable");
5443
Eliad Peller2a5bff02011-08-25 18:10:59 +03005444module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5445MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5446
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005447MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005448MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005449MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");