blob: 723df48ed44730d67fa2663fd6b51119ee36a5ac [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
3 * This file is part of wl1271
4 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03006 *
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/firmware.h>
27#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
29#include <linux/crc32.h>
30#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030031#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020034#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030035#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030036#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030039#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030040#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000041#include "reg.h"
42#include "io.h"
43#include "event.h"
44#include "tx.h"
45#include "rx.h"
46#include "ps.h"
47#include "init.h"
48#include "debugfs.h"
49#include "cmd.h"
50#include "boot.h"
51#include "testmode.h"
52#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030053
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020054#define WL1271_BOOT_RETRIES 3
55
Juuso Oikarinen8a080482009-10-13 12:47:44 +030056static struct conf_drv_settings default_conf = {
57 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030058 .params = {
59 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
62 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
63 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
65 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
66 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
67 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
69 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
70 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
76 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
78 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
80 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
83 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
84 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
85 /* active scan params */
86 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
88 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
89 /* passive scan params */
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
92 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
93 /* passive scan in dual antenna params */
94 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
96 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
97 /* general params */
98 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
99 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
100 [CONF_SG_BEACON_MISS_PERCENT] = 60,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_RXT] = 1200,
103 [CONF_SG_TXT] = 1000,
104 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
105 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
106 [CONF_SG_HV3_MAX_SERVED] = 6,
107 [CONF_SG_PS_POLL_TIMEOUT] = 10,
108 [CONF_SG_UPSD_TIMEOUT] = 10,
109 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
110 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
111 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
112 /* AP params */
113 [CONF_AP_BEACON_MISS_TX] = 3,
114 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
115 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
116 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
117 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
118 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Eliad Peller26612c42012-01-31 17:54:43 +0200119 /* CTS Diluting params */
120 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
121 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300122 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200123 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .rx = {
126 .rx_msdu_life_time = 512000,
127 .packet_detection_threshold = 0,
128 .ps_poll_timeout = 15,
129 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300130 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200131 .rx_cca_threshold = 0,
132 .irq_blk_threshold = 0xFFFF,
133 .irq_pkt_threshold = 0,
134 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
136 },
137 .tx = {
138 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300140 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300141 .short_retry_limit = 10,
142 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200143 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 },
145 .ac_conf_count = 4,
146 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200147 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300148 .ac = CONF_TX_AC_BE,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = 3,
152 .tx_op_limit = 0,
153 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200154 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300155 .ac = CONF_TX_AC_BK,
156 .cw_min = 15,
157 .cw_max = 63,
158 .aifsn = 7,
159 .tx_op_limit = 0,
160 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200161 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300162 .ac = CONF_TX_AC_VI,
163 .cw_min = 15,
164 .cw_max = 63,
165 .aifsn = CONF_TX_AIFS_PIFS,
166 .tx_op_limit = 3008,
167 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200168 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300169 .ac = CONF_TX_AC_VO,
170 .cw_min = 15,
171 .cw_max = 63,
172 .aifsn = CONF_TX_AIFS_PIFS,
173 .tx_op_limit = 1504,
174 },
175 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300176 .max_tx_retries = 100,
177 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200178 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200180 [CONF_TX_AC_BE] = {
181 .queue_id = CONF_TX_AC_BE,
182 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300183 .tsid = CONF_TX_AC_BE,
184 .ps_scheme = CONF_PS_SCHEME_LEGACY,
185 .ack_policy = CONF_ACK_POLICY_LEGACY,
186 .apsd_conf = {0, 0},
187 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200188 [CONF_TX_AC_BK] = {
189 .queue_id = CONF_TX_AC_BK,
190 .channel_type = CONF_CHANNEL_TYPE_EDCF,
191 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ps_scheme = CONF_PS_SCHEME_LEGACY,
193 .ack_policy = CONF_ACK_POLICY_LEGACY,
194 .apsd_conf = {0, 0},
195 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200196 [CONF_TX_AC_VI] = {
197 .queue_id = CONF_TX_AC_VI,
198 .channel_type = CONF_CHANNEL_TYPE_EDCF,
199 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .ps_scheme = CONF_PS_SCHEME_LEGACY,
201 .ack_policy = CONF_ACK_POLICY_LEGACY,
202 .apsd_conf = {0, 0},
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
205 .queue_id = CONF_TX_AC_VO,
206 .channel_type = CONF_CHANNEL_TYPE_EDCF,
207 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 .ps_scheme = CONF_PS_SCHEME_LEGACY,
209 .ack_policy = CONF_ACK_POLICY_LEGACY,
210 .apsd_conf = {0, 0},
211 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300212 },
213 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200214 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300215 .tx_compl_threshold = 4,
216 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
217 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200218 .tmpl_short_retry_limit = 10,
219 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Eyal Shapiradae728f2012-02-02 12:03:39 +0200224 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
225 .suspend_listen_interval = 3,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300227 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 .bcn_filt_ie = {
229 [0] = {
230 .ie = WLAN_EID_CHANNEL_SWITCH,
231 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300232 },
233 [1] = {
234 .ie = WLAN_EID_HT_INFORMATION,
235 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
236 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200238 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 .bss_lose_timeout = 100,
240 .beacon_rx_timeout = 10000,
241 .broadcast_timeout = 20000,
242 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300243 .ps_poll_threshold = 10,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300244 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200245 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300246 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300247 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200248 .psm_entry_nullfunc_retries = 3,
Eyal Shapiraf1d63a52012-01-31 11:57:21 +0200249 .dynamic_ps_timeout = 100,
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +0200250 .forced_ps = false,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300251 .keep_alive_interval = 55000,
252 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200254 .itrim = {
255 .enable = false,
256 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200257 },
258 .pm_config = {
259 .host_clk_settling_time = 5000,
260 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300261 },
262 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300263 .trigger_pacing = 1,
264 .avg_weight_rssi_beacon = 20,
265 .avg_weight_rssi_data = 10,
266 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100267 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200268 },
269 .scan = {
270 .min_dwell_time_active = 7500,
271 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100272 .min_dwell_time_passive = 100000,
273 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200274 .num_probe_reqs = 2,
Eyal Shapirad647f2d2012-02-02 13:54:28 +0200275 .split_scan_timeout = 50000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200276 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300277 .sched_scan = {
278 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300279 .min_dwell_time_active = 30,
280 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300281 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300282 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300283 .num_probe_reqs = 2,
284 .rssi_threshold = -90,
285 .snr_threshold = 0,
286 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200287 .rf = {
288 .tx_per_channel_power_compensation_2 = {
289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 .tx_per_channel_power_compensation_5 = {
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 },
296 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300298 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100299 .tx_ba_win_size = 64,
300 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300301 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100302 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200303 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200304 .num_stations = 1,
305 .ssid_profiles = 1,
306 .rx_block_num = 70,
307 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300308 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200309 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200310 .min_req_rx_blocks = 22,
311 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200312 },
313 .mem_wl128x = {
314 .num_stations = 1,
315 .ssid_profiles = 1,
316 .rx_block_num = 40,
317 .tx_min_block_num = 40,
318 .dynamic_memory = 1,
319 .min_req_tx_blocks = 45,
320 .min_req_rx_blocks = 22,
321 .tx_min = 27,
322 },
Shahar Leviff868432011-04-11 15:41:46 +0300323 .fm_coex = {
324 .enable = true,
325 .swallow_period = 5,
326 .n_divider_fref_set_1 = 0xff, /* default */
327 .n_divider_fref_set_2 = 12,
328 .m_divider_fref_set_1 = 148,
329 .m_divider_fref_set_2 = 0xffff, /* default */
330 .coex_pll_stabilization_time = 0xffffffff, /* default */
331 .ldo_stabilization_time = 0xffff, /* default */
332 .fm_disturbed_band_margin = 0xff, /* default */
333 .swallow_clk_diff = 0xff, /* default */
334 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300335 .rx_streaming = {
336 .duration = 150,
337 .queues = 0x1,
338 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300339 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300340 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300341 .fwlog = {
342 .mode = WL12XX_FWLOG_ON_DEMAND,
343 .mem_blocks = 2,
344 .severity = 0,
345 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
346 .output = WL12XX_FWLOG_OUTPUT_HOST,
347 .threshold = 0,
348 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300349 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300350 .rate = {
351 .rate_retry_score = 32000,
352 .per_add = 8192,
353 .per_th1 = 2048,
354 .per_th2 = 4096,
355 .max_per = 8100,
356 .inverse_curiosity_factor = 5,
357 .tx_fail_low_th = 4,
358 .tx_fail_high_th = 10,
359 .per_alpha_shift = 4,
360 .per_add_shift = 13,
361 .per_beta1_shift = 10,
362 .per_beta2_shift = 8,
363 .rate_check_up = 2,
364 .rate_check_down = 12,
365 .rate_retry_policy = {
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00,
369 },
370 },
Eliad Peller94877752011-08-28 15:11:56 +0300371 .hangover = {
372 .recover_time = 0,
373 .hangover_period = 20,
374 .dynamic_mode = 1,
375 .early_termination_mode = 1,
376 .max_period = 20,
377 .min_period = 1,
378 .increase_delta = 1,
379 .decrease_delta = 2,
380 .quiet_time = 4,
381 .increase_time = 1,
382 .window_size = 16,
383 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300384};
385
Ido Yariv95dac04f2011-06-06 14:57:06 +0300386static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300387static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300388
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300389static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200390 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300391 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200392static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200393static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200394
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200395static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300396static LIST_HEAD(wl_list);
397
Eliad Pellerba8447f2011-10-10 10:13:00 +0200398static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
399 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300400{
401 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200402
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300403 if (operstate != IF_OPER_UP)
404 return 0;
405
Eliad Peller8181aec2011-10-10 10:13:04 +0200406 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 return 0;
408
Eliad Peller154da672011-10-05 11:55:53 +0200409 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300410 if (ret < 0)
411 return ret;
412
Eliad Peller0603d892011-10-05 11:55:51 +0200413 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300414
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300415 wl1271_info("Association completed.");
416 return 0;
417}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300418static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
419 void *arg)
420{
421 struct net_device *dev = arg;
422 struct wireless_dev *wdev;
423 struct wiphy *wiphy;
424 struct ieee80211_hw *hw;
425 struct wl1271 *wl;
426 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200427 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300428 int ret = 0;
429
430 /* Check that this notification is for us. */
431 if (what != NETDEV_CHANGE)
432 return NOTIFY_DONE;
433
434 wdev = dev->ieee80211_ptr;
435 if (wdev == NULL)
436 return NOTIFY_DONE;
437
438 wiphy = wdev->wiphy;
439 if (wiphy == NULL)
440 return NOTIFY_DONE;
441
442 hw = wiphy_priv(wiphy);
443 if (hw == NULL)
444 return NOTIFY_DONE;
445
446 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200447 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300448 list_for_each_entry(wl, &wl_list, list) {
449 if (wl == wl_temp)
450 break;
451 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200452 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300453 if (wl != wl_temp)
454 return NOTIFY_DONE;
455
456 mutex_lock(&wl->mutex);
457
458 if (wl->state == WL1271_STATE_OFF)
459 goto out;
460
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 if (dev->operstate != IF_OPER_UP)
462 goto out;
463 /*
464 * The correct behavior should be just getting the appropriate wlvif
465 * from the given dev, but currently we don't have a mac80211
466 * interface for it.
467 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200468 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200469 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
470
Eliad Pellerba8447f2011-10-10 10:13:00 +0200471 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
472 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300473
Eliad Pellerba8447f2011-10-10 10:13:00 +0200474 ret = wl1271_ps_elp_wakeup(wl);
475 if (ret < 0)
476 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300477
Eliad Peller6ab70912011-12-18 20:25:45 +0200478 wl1271_check_operstate(wl, wlvif,
479 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300480
Eliad Pellerba8447f2011-10-10 10:13:00 +0200481 wl1271_ps_elp_sleep(wl);
482 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300483out:
484 mutex_unlock(&wl->mutex);
485
486 return NOTIFY_OK;
487}
488
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100489static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200490 struct regulatory_request *request)
491{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100492 struct ieee80211_supported_band *band;
493 struct ieee80211_channel *ch;
494 int i;
495
496 band = wiphy->bands[IEEE80211_BAND_5GHZ];
497 for (i = 0; i < band->n_channels; i++) {
498 ch = &band->channels[i];
499 if (ch->flags & IEEE80211_CHAN_DISABLED)
500 continue;
501
502 if (ch->flags & IEEE80211_CHAN_RADAR)
503 ch->flags |= IEEE80211_CHAN_NO_IBSS |
504 IEEE80211_CHAN_PASSIVE_SCAN;
505
506 }
507
508 return 0;
509}
510
Eliad Peller9eb599e2011-10-10 10:12:59 +0200511static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
512 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300513{
514 int ret = 0;
515
516 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200517 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300518 if (ret < 0)
519 goto out;
520
521 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200522 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300523 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200524 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300525out:
526 return ret;
527}
528
529/*
530 * this function is being called when the rx_streaming interval
531 * has beed changed or rx_streaming should be disabled
532 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200533int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300534{
535 int ret = 0;
536 int period = wl->conf.rx_streaming.interval;
537
538 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200539 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 goto out;
541
542 /* reconfigure/disable according to new streaming_period */
543 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200544 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300545 (wl->conf.rx_streaming.always ||
546 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200547 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300548 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200549 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200551 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300552 }
553out:
554 return ret;
555}
556
557static void wl1271_rx_streaming_enable_work(struct work_struct *work)
558{
559 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200560 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
561 rx_streaming_enable_work);
562 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300563
564 mutex_lock(&wl->mutex);
565
Eliad Peller0744bdb2011-10-10 10:13:05 +0200566 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200567 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300568 (!wl->conf.rx_streaming.always &&
569 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
570 goto out;
571
572 if (!wl->conf.rx_streaming.interval)
573 goto out;
574
575 ret = wl1271_ps_elp_wakeup(wl);
576 if (ret < 0)
577 goto out;
578
Eliad Peller9eb599e2011-10-10 10:12:59 +0200579 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300580 if (ret < 0)
581 goto out_sleep;
582
583 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200584 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300585 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
586
587out_sleep:
588 wl1271_ps_elp_sleep(wl);
589out:
590 mutex_unlock(&wl->mutex);
591}
592
593static void wl1271_rx_streaming_disable_work(struct work_struct *work)
594{
595 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200596 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
597 rx_streaming_disable_work);
598 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300599
600 mutex_lock(&wl->mutex);
601
Eliad Peller0744bdb2011-10-10 10:13:05 +0200602 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300603 goto out;
604
605 ret = wl1271_ps_elp_wakeup(wl);
606 if (ret < 0)
607 goto out;
608
Eliad Peller9eb599e2011-10-10 10:12:59 +0200609 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300610 if (ret)
611 goto out_sleep;
612
613out_sleep:
614 wl1271_ps_elp_sleep(wl);
615out:
616 mutex_unlock(&wl->mutex);
617}
618
619static void wl1271_rx_streaming_timer(unsigned long data)
620{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200621 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
622 struct wl1271 *wl = wlvif->wl;
623 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300624}
625
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300626static void wl1271_conf_init(struct wl1271 *wl)
627{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300628
629 /*
630 * This function applies the default configuration to the driver. This
631 * function is invoked upon driver load (spi probe.)
632 *
633 * The configuration is stored in a run-time structure in order to
634 * facilitate for run-time adjustment of any of the parameters. Making
635 * changes to the configuration structure will apply the new values on
636 * the next interface up (wl1271_op_start.)
637 */
638
639 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300640 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300641
Ido Yariv95dac04f2011-06-06 14:57:06 +0300642 /* Adjust settings according to optional module parameters */
643 if (fwlog_param) {
644 if (!strcmp(fwlog_param, "continuous")) {
645 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
646 } else if (!strcmp(fwlog_param, "ondemand")) {
647 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
648 } else if (!strcmp(fwlog_param, "dbgpins")) {
649 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
650 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
651 } else if (!strcmp(fwlog_param, "disable")) {
652 wl->conf.fwlog.mem_blocks = 0;
653 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
654 } else {
655 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
656 }
657 }
658}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300659
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300660static int wl1271_plt_init(struct wl1271 *wl)
661{
Eliad Peller188e7f52011-12-06 12:15:06 +0200662 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300663
Shahar Levi49d750ca2011-03-06 16:32:09 +0200664 if (wl->chip.id == CHIP_ID_1283_PG20)
665 ret = wl128x_cmd_general_parms(wl);
666 else
667 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200668 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200669 return ret;
670
Shahar Levi49d750ca2011-03-06 16:32:09 +0200671 if (wl->chip.id == CHIP_ID_1283_PG20)
672 ret = wl128x_cmd_radio_parms(wl);
673 else
674 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200675 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200676 return ret;
677
Shahar Levi49d750ca2011-03-06 16:32:09 +0200678 if (wl->chip.id != CHIP_ID_1283_PG20) {
679 ret = wl1271_cmd_ext_radio_parms(wl);
680 if (ret < 0)
681 return ret;
682 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200683 if (ret < 0)
684 return ret;
685
Shahar Levi48a61472011-03-06 16:32:08 +0200686 /* Chip-specific initializations */
687 ret = wl1271_chip_specific_init(wl);
688 if (ret < 0)
689 return ret;
690
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300691 ret = wl1271_acx_init_mem_config(wl);
692 if (ret < 0)
693 return ret;
694
Eliad Peller7f0979882011-08-14 13:17:06 +0300695 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600696 if (ret < 0)
697 goto out_free_memmap;
698
Luciano Coelho12419cc2010-02-18 13:25:44 +0200699 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200700 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300701 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200702 goto out_free_memmap;
703
704 /* Configure for CAM power saving (ie. always active) */
705 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
706 if (ret < 0)
707 goto out_free_memmap;
708
709 /* configure PM */
710 ret = wl1271_acx_pm_config(wl);
711 if (ret < 0)
712 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713
714 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200715
716 out_free_memmap:
717 kfree(wl->target_mem_map);
718 wl->target_mem_map = NULL;
719
720 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300721}
722
Eliad Peller6e8cd332011-10-10 10:13:13 +0200723static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
724 struct wl12xx_vif *wlvif,
725 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200726{
Arik Nemtsovda032092011-08-25 12:43:15 +0300727 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728
Arik Nemtsovb622d992011-02-23 00:22:31 +0200729 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300730 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200731
732 /*
733 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300734 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200735 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300736 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738
Arik Nemtsovda032092011-08-25 12:43:15 +0300739 /*
740 * Start high-level PS if the STA is asleep with enough blocks in FW.
741 * Make an exception if this is the only connected station. In this
742 * case FW-memory congestion is not a problem.
743 */
744 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200745 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200746}
747
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300748static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200749 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300750 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200751{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200752 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200753 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300754 u8 hlid, cnt;
755
756 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200757
758 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
759 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
760 wl1271_debug(DEBUG_PSM,
761 "link ps prev 0x%x cur 0x%x changed 0x%x",
762 wl->ap_fw_ps_map, cur_fw_ps_map,
763 wl->ap_fw_ps_map ^ cur_fw_ps_map);
764
765 wl->ap_fw_ps_map = cur_fw_ps_map;
766 }
767
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200768 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
769 lnk = &wl->links[hlid];
770 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200771
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200772 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
773 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200774
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
776 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200777 }
778}
779
Eliad Peller4d56ad92011-08-14 13:17:05 +0300780static void wl12xx_fw_status(struct wl1271 *wl,
781 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300782{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200783 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200784 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200785 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300786 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300787 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300788
Eliad Peller4d56ad92011-08-14 13:17:05 +0300789 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200790
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300791 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
792 "drv_rx_counter = %d, tx_results_counter = %d)",
793 status->intr,
794 status->fw_rx_counter,
795 status->drv_rx_counter,
796 status->tx_results_counter);
797
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300798 for (i = 0; i < NUM_TX_QUEUES; i++) {
799 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300800 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300801 (status->tx_released_pkts[i] -
802 wl->tx_pkts_freed[i]) & 0xff;
803
804 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
805 }
806
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300807 /* prevent wrap-around in total blocks counter */
808 if (likely(wl->tx_blocks_freed <=
809 le32_to_cpu(status->total_released_blks)))
810 freed_blocks = le32_to_cpu(status->total_released_blks) -
811 wl->tx_blocks_freed;
812 else
813 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
814 le32_to_cpu(status->total_released_blks);
815
Eliad Peller4d56ad92011-08-14 13:17:05 +0300816 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200817
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300818 wl->tx_allocated_blocks -= freed_blocks;
819
Eliad Peller4d56ad92011-08-14 13:17:05 +0300820 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200821
Eliad Peller4d56ad92011-08-14 13:17:05 +0300822 /*
823 * The FW might change the total number of TX memblocks before
824 * we get a notification about blocks being released. Thus, the
825 * available blocks calculation might yield a temporary result
826 * which is lower than the actual available blocks. Keeping in
827 * mind that only blocks that were allocated can be moved from
828 * TX to RX, tx_blocks_available should never decrease here.
829 */
830 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
831 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300832
Ido Yariva5225502010-10-12 14:49:10 +0200833 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200834 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200835 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300836
Eliad Peller4d56ad92011-08-14 13:17:05 +0300837 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200838 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200839 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200840 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300841
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300842 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200843 getnstimeofday(&ts);
844 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
845 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300846}
847
Ido Yariva6208652011-03-01 15:14:41 +0200848static void wl1271_flush_deferred_work(struct wl1271 *wl)
849{
850 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200851
Ido Yariva6208652011-03-01 15:14:41 +0200852 /* Pass all received frames to the network stack */
853 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
854 ieee80211_rx_ni(wl->hw, skb);
855
856 /* Return sent skbs to the network stack */
857 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300858 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200859}
860
861static void wl1271_netstack_work(struct work_struct *work)
862{
863 struct wl1271 *wl =
864 container_of(work, struct wl1271, netstack_work);
865
866 do {
867 wl1271_flush_deferred_work(wl);
868 } while (skb_queue_len(&wl->deferred_rx_queue));
869}
870
871#define WL1271_IRQ_MAX_LOOPS 256
872
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300873static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300875 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300876 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200877 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200878 struct wl1271 *wl = (struct wl1271 *)cookie;
879 bool done = false;
880 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200881 unsigned long flags;
882
883 /* TX might be handled here, avoid redundant work */
884 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
885 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886
Ido Yariv341b7cd2011-03-31 10:07:01 +0200887 /*
888 * In case edge triggered interrupt must be used, we cannot iterate
889 * more than once without introducing race conditions with the hardirq.
890 */
891 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
892 loopcount = 1;
893
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 mutex_lock(&wl->mutex);
895
896 wl1271_debug(DEBUG_IRQ, "IRQ work");
897
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200898 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300899 goto out;
900
Ido Yariva6208652011-03-01 15:14:41 +0200901 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300902 if (ret < 0)
903 goto out;
904
Ido Yariva6208652011-03-01 15:14:41 +0200905 while (!done && loopcount--) {
906 /*
907 * In order to avoid a race with the hardirq, clear the flag
908 * before acknowledging the chip. Since the mutex is held,
909 * wl1271_ps_elp_wakeup cannot be called concurrently.
910 */
911 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
912 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200913
Eliad Peller4d56ad92011-08-14 13:17:05 +0300914 wl12xx_fw_status(wl, wl->fw_status);
915 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200916 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200917 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200918 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200919 continue;
920 }
921
Eliad Pellerccc83b02010-10-27 14:09:57 +0200922 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
923 wl1271_error("watchdog interrupt received! "
924 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300925 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200926
927 /* restarting the chip. ignore any other interrupt. */
928 goto out;
929 }
930
Ido Yariva6208652011-03-01 15:14:41 +0200931 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200932 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
933
Eliad Peller4d56ad92011-08-14 13:17:05 +0300934 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200935
Ido Yariva5225502010-10-12 14:49:10 +0200936 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200937 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200938 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300939 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200940 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200941 /*
942 * In order to avoid starvation of the TX path,
943 * call the work function directly.
944 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200945 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200946 } else {
947 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200948 }
949
Ido Yariv8aad2462011-03-01 15:14:38 +0200950 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300951 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200952 (wl->tx_results_count & 0xff))
953 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200954
955 /* Make sure the deferred queues don't get too long */
956 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
957 skb_queue_len(&wl->deferred_rx_queue);
958 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
959 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200960 }
961
962 if (intr & WL1271_ACX_INTR_EVENT_A) {
963 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
964 wl1271_event_handle(wl, 0);
965 }
966
967 if (intr & WL1271_ACX_INTR_EVENT_B) {
968 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
969 wl1271_event_handle(wl, 1);
970 }
971
972 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
973 wl1271_debug(DEBUG_IRQ,
974 "WL1271_ACX_INTR_INIT_COMPLETE");
975
976 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
977 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 }
979
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300980 wl1271_ps_elp_sleep(wl);
981
982out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200983 spin_lock_irqsave(&wl->wl_lock, flags);
984 /* In case TX was not handled here, queue TX work */
985 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
986 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300987 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200988 ieee80211_queue_work(wl->hw, &wl->tx_work);
989 spin_unlock_irqrestore(&wl->wl_lock, flags);
990
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300991 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200992
993 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994}
995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300996static int wl1271_fetch_firmware(struct wl1271 *wl)
997{
998 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200999 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001000 int ret;
1001
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001002 if (wl->chip.id == CHIP_ID_1283_PG20)
1003 fw_name = WL128X_FW_NAME;
1004 else
1005 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001006
1007 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1008
Felipe Balbia390e852011-10-06 10:07:44 +03001009 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001010
1011 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001012 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001013 return ret;
1014 }
1015
1016 if (fw->size % 4) {
1017 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1018 fw->size);
1019 ret = -EILSEQ;
1020 goto out;
1021 }
1022
Arik Nemtsov166d5042010-10-16 21:44:57 +02001023 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001025 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026
1027 if (!wl->fw) {
1028 wl1271_error("could not allocate memory for the firmware");
1029 ret = -ENOMEM;
1030 goto out;
1031 }
1032
1033 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001034 ret = 0;
1035
1036out:
1037 release_firmware(fw);
1038
1039 return ret;
1040}
1041
1042static int wl1271_fetch_nvs(struct wl1271 *wl)
1043{
1044 const struct firmware *fw;
1045 int ret;
1046
Felipe Balbia390e852011-10-06 10:07:44 +03001047 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001050 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1051 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001052 return ret;
1053 }
1054
Shahar Levibc765bf2011-03-06 16:32:10 +02001055 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001056
1057 if (!wl->nvs) {
1058 wl1271_error("could not allocate memory for the nvs file");
1059 ret = -ENOMEM;
1060 goto out;
1061 }
1062
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001063 wl->nvs_len = fw->size;
1064
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001065out:
1066 release_firmware(fw);
1067
1068 return ret;
1069}
1070
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001071void wl12xx_queue_recovery_work(struct wl1271 *wl)
1072{
1073 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1074 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1075}
1076
Ido Yariv95dac04f2011-06-06 14:57:06 +03001077size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1078{
1079 size_t len = 0;
1080
1081 /* The FW log is a length-value list, find where the log end */
1082 while (len < maxlen) {
1083 if (memblock[len] == 0)
1084 break;
1085 if (len + memblock[len] + 1 > maxlen)
1086 break;
1087 len += memblock[len] + 1;
1088 }
1089
1090 /* Make sure we have enough room */
1091 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1092
1093 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1094 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1095 wl->fwlog_size += len;
1096
1097 return len;
1098}
1099
1100static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1101{
1102 u32 addr;
1103 u32 first_addr;
1104 u8 *block;
1105
1106 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1107 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1108 (wl->conf.fwlog.mem_blocks == 0))
1109 return;
1110
1111 wl1271_info("Reading FW panic log");
1112
1113 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1114 if (!block)
1115 return;
1116
1117 /*
1118 * Make sure the chip is awake and the logger isn't active.
1119 * This might fail if the firmware hanged.
1120 */
1121 if (!wl1271_ps_elp_wakeup(wl))
1122 wl12xx_cmd_stop_fwlog(wl);
1123
1124 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001125 wl12xx_fw_status(wl, wl->fw_status);
1126 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001127 if (!first_addr)
1128 goto out;
1129
1130 /* Traverse the memory blocks linked list */
1131 addr = first_addr;
1132 do {
1133 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1134 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1135 false);
1136
1137 /*
1138 * Memory blocks are linked to one another. The first 4 bytes
1139 * of each memory block hold the hardware address of the next
1140 * one. The last memory block points to the first one.
1141 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001142 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001143 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1144 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1145 break;
1146 } while (addr && (addr != first_addr));
1147
1148 wake_up_interruptible(&wl->fwlog_waitq);
1149
1150out:
1151 kfree(block);
1152}
1153
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001154static void wl1271_recovery_work(struct work_struct *work)
1155{
1156 struct wl1271 *wl =
1157 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001158 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001159 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001160
1161 mutex_lock(&wl->mutex);
1162
1163 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001164 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001166 /* Avoid a recursive recovery */
1167 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1168
Ido Yariv95dac04f2011-06-06 14:57:06 +03001169 wl12xx_read_fwlog_panic(wl);
1170
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001171 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1172 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001173
Eliad Peller2a5bff02011-08-25 18:10:59 +03001174 BUG_ON(bug_on_recovery);
1175
Oz Krakowskib992c682011-06-26 10:36:02 +03001176 /*
1177 * Advance security sequence number to overcome potential progress
1178 * in the firmware during recovery. This doens't hurt if the network is
1179 * not encrypted.
1180 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001181 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001182 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001183 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001184 wlvif->tx_security_seq +=
1185 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1186 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001187
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001188 /* Prevent spurious TX during FW restart */
1189 ieee80211_stop_queues(wl->hw);
1190
Luciano Coelho33c2c062011-05-10 14:46:02 +03001191 if (wl->sched_scanning) {
1192 ieee80211_sched_scan_stopped(wl->hw);
1193 wl->sched_scanning = false;
1194 }
1195
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001196 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001197 while (!list_empty(&wl->wlvif_list)) {
1198 wlvif = list_first_entry(&wl->wlvif_list,
1199 struct wl12xx_vif, list);
1200 vif = wl12xx_wlvif_to_vif(wlvif);
1201 __wl1271_op_remove_interface(wl, vif, false);
1202 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001203 mutex_unlock(&wl->mutex);
1204 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001205
1206 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1207
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001208 ieee80211_restart_hw(wl->hw);
1209
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001210 /*
1211 * Its safe to enable TX now - the queues are stopped after a request
1212 * to restart the HW.
1213 */
1214 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001215 return;
1216out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001217 mutex_unlock(&wl->mutex);
1218}
1219
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001220static void wl1271_fw_wakeup(struct wl1271 *wl)
1221{
1222 u32 elp_reg;
1223
1224 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001225 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001226}
1227
1228static int wl1271_setup(struct wl1271 *wl)
1229{
1230 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1231 if (!wl->fw_status)
1232 return -ENOMEM;
1233
1234 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1235 if (!wl->tx_res_if) {
1236 kfree(wl->fw_status);
1237 return -ENOMEM;
1238 }
1239
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001240 return 0;
1241}
1242
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001243static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001245 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001247 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001248 ret = wl1271_power_on(wl);
1249 if (ret < 0)
1250 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001251 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001252 wl1271_io_reset(wl);
1253 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001255 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001256
1257 /* ELP module wake up */
1258 wl1271_fw_wakeup(wl);
1259
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001260out:
1261 return ret;
1262}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001264static int wl1271_chip_wakeup(struct wl1271 *wl)
1265{
1266 int ret = 0;
1267
1268 ret = wl12xx_set_power_on(wl);
1269 if (ret < 0)
1270 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001271
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001272 /*
1273 * For wl127x based devices we could use the default block
1274 * size (512 bytes), but due to a bug in the sdio driver, we
1275 * need to set it explicitly after the chip is powered on. To
1276 * simplify the code and since the performance impact is
1277 * negligible, we use the same block size for all different
1278 * chip types.
1279 */
1280 if (!wl1271_set_block_size(wl))
1281 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001282
1283 switch (wl->chip.id) {
1284 case CHIP_ID_1271_PG10:
1285 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1286 wl->chip.id);
1287
1288 ret = wl1271_setup(wl);
1289 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001290 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001291 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001293
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 case CHIP_ID_1271_PG20:
1295 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1296 wl->chip.id);
1297
1298 ret = wl1271_setup(wl);
1299 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001300 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001301 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001302 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001303
Shahar Levi0830cee2011-03-06 16:32:20 +02001304 case CHIP_ID_1283_PG20:
1305 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1306 wl->chip.id);
1307
1308 ret = wl1271_setup(wl);
1309 if (ret < 0)
1310 goto out;
1311 break;
1312 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001314 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001316 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001317 }
1318
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001319 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001320 ret = wl1271_fetch_firmware(wl);
1321 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001322 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001323 }
1324
1325 /* No NVS from netlink, try to get it from the filesystem */
1326 if (wl->nvs == NULL) {
1327 ret = wl1271_fetch_nvs(wl);
1328 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001329 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001330 }
1331
1332out:
1333 return ret;
1334}
1335
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001336int wl1271_plt_start(struct wl1271 *wl)
1337{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001338 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001339 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001340 int ret;
1341
1342 mutex_lock(&wl->mutex);
1343
1344 wl1271_notice("power up");
1345
1346 if (wl->state != WL1271_STATE_OFF) {
1347 wl1271_error("cannot go into PLT state because not "
1348 "in off state: %d", wl->state);
1349 ret = -EBUSY;
1350 goto out;
1351 }
1352
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001353 while (retries) {
1354 retries--;
1355 ret = wl1271_chip_wakeup(wl);
1356 if (ret < 0)
1357 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001358
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 ret = wl1271_boot(wl);
1360 if (ret < 0)
1361 goto power_off;
1362
1363 ret = wl1271_plt_init(wl);
1364 if (ret < 0)
1365 goto irq_disable;
1366
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001367 wl->state = WL1271_STATE_PLT;
1368 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001369 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001370
Gery Kahn6f07b722011-07-18 14:21:49 +03001371 /* update hw/fw version info in wiphy struct */
1372 wiphy->hw_version = wl->chip.id;
1373 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1374 sizeof(wiphy->fw_version));
1375
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001376 goto out;
1377
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001378irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001379 mutex_unlock(&wl->mutex);
1380 /* Unlocking the mutex in the middle of handling is
1381 inherently unsafe. In this case we deem it safe to do,
1382 because we need to let any possibly pending IRQ out of
1383 the system (and while we are WL1271_STATE_OFF the IRQ
1384 work function will not do anything.) Also, any other
1385 possible concurrent operations will fail due to the
1386 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001387 wl1271_disable_interrupts(wl);
1388 wl1271_flush_deferred_work(wl);
1389 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001390 mutex_lock(&wl->mutex);
1391power_off:
1392 wl1271_power_off(wl);
1393 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001394
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001395 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1396 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001397out:
1398 mutex_unlock(&wl->mutex);
1399
1400 return ret;
1401}
1402
Ido Yarivf3df1332012-01-11 09:42:39 +02001403int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001404{
1405 int ret = 0;
1406
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001407 wl1271_notice("power down");
1408
Ido Yariv46b0cc92012-01-11 09:42:41 +02001409 /*
1410 * Interrupts must be disabled before setting the state to OFF.
1411 * Otherwise, the interrupt handler might be called and exit without
1412 * reading the interrupt status.
1413 */
1414 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001415 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001416 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001417 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001418
1419 /*
1420 * This will not necessarily enable interrupts as interrupts
1421 * may have been disabled when op_stop was called. It will,
1422 * however, balance the above call to disable_interrupts().
1423 */
1424 wl1271_enable_interrupts(wl);
1425
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001426 wl1271_error("cannot power down because not in PLT "
1427 "state: %d", wl->state);
1428 ret = -EBUSY;
1429 goto out;
1430 }
1431
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001432 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001433
Ido Yariva6208652011-03-01 15:14:41 +02001434 wl1271_flush_deferred_work(wl);
1435 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001436 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001437 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001438
1439 mutex_lock(&wl->mutex);
1440 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001441 wl->flags = 0;
1442 wl->state = WL1271_STATE_OFF;
1443 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001444 mutex_unlock(&wl->mutex);
1445
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001446out:
1447 return ret;
1448}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001449
Johannes Berg7bb45682011-02-24 14:42:06 +01001450static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451{
1452 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001453 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1454 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001455 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001456 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001457 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001458 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001459
Eliad Peller0f168012011-10-11 13:52:25 +02001460 if (vif)
1461 wlvif = wl12xx_vif_to_data(vif);
1462
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001463 mapping = skb_get_queue_mapping(skb);
1464 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001465
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001466 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001467
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001468 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001469
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001470 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001471 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001472 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001473 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001474 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001475 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001476 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001477
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001478 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1479 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1480
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001481 wl->tx_queue_count[q]++;
1482
1483 /*
1484 * The workqueue is slow to process the tx_queue and we need stop
1485 * the queue here, otherwise the queue will get too long.
1486 */
1487 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1488 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1489 ieee80211_stop_queue(wl->hw, mapping);
1490 set_bit(q, &wl->stopped_queues_map);
1491 }
1492
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001493 /*
1494 * The chip specific setup must run before the first TX packet -
1495 * before that, the tx_work will not be initialized!
1496 */
1497
Ido Yarivb07d4032011-03-01 15:14:43 +02001498 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1499 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001500 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001501
Arik Nemtsov04216da2011-08-14 13:17:38 +03001502out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001503 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001504}
1505
Shahar Leviae47c452011-03-06 16:32:14 +02001506int wl1271_tx_dummy_packet(struct wl1271 *wl)
1507{
Ido Yariv990f5de2011-03-31 10:06:59 +02001508 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001509 int q;
1510
1511 /* no need to queue a new dummy packet if one is already pending */
1512 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1513 return 0;
1514
1515 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001516
Ido Yariv990f5de2011-03-31 10:06:59 +02001517 spin_lock_irqsave(&wl->wl_lock, flags);
1518 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001519 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001520 spin_unlock_irqrestore(&wl->wl_lock, flags);
1521
1522 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1523 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001524 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001525
1526 /*
1527 * If the FW TX is busy, TX work will be scheduled by the threaded
1528 * interrupt handler function
1529 */
1530 return 0;
1531}
1532
1533/*
1534 * The size of the dummy packet should be at least 1400 bytes. However, in
1535 * order to minimize the number of bus transactions, aligning it to 512 bytes
1536 * boundaries could be beneficial, performance wise
1537 */
1538#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1539
Luciano Coelhocf27d862011-04-01 21:08:23 +03001540static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001541{
1542 struct sk_buff *skb;
1543 struct ieee80211_hdr_3addr *hdr;
1544 unsigned int dummy_packet_size;
1545
1546 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1547 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1548
1549 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001550 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001551 wl1271_warning("Failed to allocate a dummy packet skb");
1552 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001553 }
1554
1555 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1556
1557 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1558 memset(hdr, 0, sizeof(*hdr));
1559 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001560 IEEE80211_STYPE_NULLFUNC |
1561 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001562
Ido Yariv990f5de2011-03-31 10:06:59 +02001563 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001564
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001565 /* Dummy packets require the TID to be management */
1566 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001567
1568 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001569 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001570 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001571
Ido Yariv990f5de2011-03-31 10:06:59 +02001572 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001573}
1574
Ido Yariv990f5de2011-03-31 10:06:59 +02001575
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001576static struct notifier_block wl1271_dev_notifier = {
1577 .notifier_call = wl1271_dev_notify,
1578};
1579
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001580#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001581static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1582 struct wl12xx_vif *wlvif)
1583{
1584 int ret = 0;
1585
1586 mutex_lock(&wl->mutex);
1587
1588 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1589 goto out_unlock;
1590
1591 ret = wl1271_ps_elp_wakeup(wl);
1592 if (ret < 0)
1593 goto out_unlock;
1594
1595 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1596 wl->conf.conn.suspend_wake_up_event,
1597 wl->conf.conn.suspend_listen_interval);
1598
1599 if (ret < 0)
1600 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1601
1602
1603 wl1271_ps_elp_sleep(wl);
1604
1605out_unlock:
1606 mutex_unlock(&wl->mutex);
1607 return ret;
1608
1609}
Eliad Peller94390642011-05-13 11:57:13 +03001610
Eliad Peller0603d892011-10-05 11:55:51 +02001611static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1612 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001613{
Eliad Pellere85d1622011-06-27 13:06:43 +03001614 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001615
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001616 mutex_lock(&wl->mutex);
1617
Eliad Peller53d40d02011-10-10 10:13:02 +02001618 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001619 goto out_unlock;
1620
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001621 ret = wl1271_ps_elp_wakeup(wl);
1622 if (ret < 0)
1623 goto out_unlock;
1624
Eliad Peller0603d892011-10-05 11:55:51 +02001625 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001626
1627 wl1271_ps_elp_sleep(wl);
1628out_unlock:
1629 mutex_unlock(&wl->mutex);
1630 return ret;
1631
1632}
1633
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001634static int wl1271_configure_suspend(struct wl1271 *wl,
1635 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001636{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001637 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1638 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001639 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001640 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001641 return 0;
1642}
1643
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001644static void wl1271_configure_resume(struct wl1271 *wl,
1645 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001646{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001647 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001648 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001649 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650
Eyal Shapiradae728f2012-02-02 12:03:39 +02001651 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001652 return;
1653
1654 mutex_lock(&wl->mutex);
1655 ret = wl1271_ps_elp_wakeup(wl);
1656 if (ret < 0)
1657 goto out;
1658
Eyal Shapiradae728f2012-02-02 12:03:39 +02001659 if (is_sta) {
1660 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1661 wl->conf.conn.wake_up_event,
1662 wl->conf.conn.listen_interval);
1663
1664 if (ret < 0)
1665 wl1271_error("resume: wake up conditions failed: %d",
1666 ret);
1667
1668 } else if (is_ap) {
1669 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1670 }
Eliad Peller94390642011-05-13 11:57:13 +03001671
1672 wl1271_ps_elp_sleep(wl);
1673out:
1674 mutex_unlock(&wl->mutex);
1675}
1676
Eliad Peller402e48612011-05-13 11:57:09 +03001677static int wl1271_op_suspend(struct ieee80211_hw *hw,
1678 struct cfg80211_wowlan *wow)
1679{
1680 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001681 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001682 int ret;
1683
Eliad Peller402e48612011-05-13 11:57:09 +03001684 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001686
Eliad Peller4a859df2011-06-06 12:21:52 +03001687 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001688 wl12xx_for_each_wlvif(wl, wlvif) {
1689 ret = wl1271_configure_suspend(wl, wlvif);
1690 if (ret < 0) {
1691 wl1271_warning("couldn't prepare device to suspend");
1692 return ret;
1693 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001694 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 /* flush any remaining work */
1696 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001697
1698 /*
1699 * disable and re-enable interrupts in order to flush
1700 * the threaded_irq
1701 */
1702 wl1271_disable_interrupts(wl);
1703
1704 /*
1705 * set suspended flag to avoid triggering a new threaded_irq
1706 * work. no need for spinlock as interrupts are disabled.
1707 */
1708 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1709
1710 wl1271_enable_interrupts(wl);
1711 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001712 flush_delayed_work(&wl->elp_work);
1713
Eliad Peller402e48612011-05-13 11:57:09 +03001714 return 0;
1715}
1716
1717static int wl1271_op_resume(struct ieee80211_hw *hw)
1718{
1719 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001720 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001721 unsigned long flags;
1722 bool run_irq_work = false;
1723
Eliad Peller402e48612011-05-13 11:57:09 +03001724 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1725 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001726 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001727
1728 /*
1729 * re-enable irq_work enqueuing, and call irq_work directly if
1730 * there is a pending work.
1731 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001732 spin_lock_irqsave(&wl->wl_lock, flags);
1733 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1734 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1735 run_irq_work = true;
1736 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001737
Eliad Peller4a859df2011-06-06 12:21:52 +03001738 if (run_irq_work) {
1739 wl1271_debug(DEBUG_MAC80211,
1740 "run postponed irq_work directly");
1741 wl1271_irq(0, wl);
1742 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001743 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001744 wl12xx_for_each_wlvif(wl, wlvif) {
1745 wl1271_configure_resume(wl, wlvif);
1746 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001747 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001748
Eliad Peller402e48612011-05-13 11:57:09 +03001749 return 0;
1750}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001751#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001752
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001753static int wl1271_op_start(struct ieee80211_hw *hw)
1754{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001755 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1756
1757 /*
1758 * We have to delay the booting of the hardware because
1759 * we need to know the local MAC address before downloading and
1760 * initializing the firmware. The MAC address cannot be changed
1761 * after boot, and without the proper MAC address, the firmware
1762 * will not function properly.
1763 *
1764 * The MAC address is first known when the corresponding interface
1765 * is added. That is where we will initialize the hardware.
1766 */
1767
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001768 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001769}
1770
1771static void wl1271_op_stop(struct ieee80211_hw *hw)
1772{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001773 struct wl1271 *wl = hw->priv;
1774 int i;
1775
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001776 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001777
Ido Yariv46b0cc92012-01-11 09:42:41 +02001778 /*
1779 * Interrupts must be disabled before setting the state to OFF.
1780 * Otherwise, the interrupt handler might be called and exit without
1781 * reading the interrupt status.
1782 */
1783 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001784 mutex_lock(&wl->mutex);
1785 if (wl->state == WL1271_STATE_OFF) {
1786 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001787
1788 /*
1789 * This will not necessarily enable interrupts as interrupts
1790 * may have been disabled when op_stop was called. It will,
1791 * however, balance the above call to disable_interrupts().
1792 */
1793 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001794 return;
1795 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001796
Eliad Pellerbaf62772011-10-10 10:12:52 +02001797 /*
1798 * this must be before the cancel_work calls below, so that the work
1799 * functions don't perform further work.
1800 */
1801 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001802 mutex_unlock(&wl->mutex);
1803
1804 mutex_lock(&wl_list_mutex);
1805 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001806 mutex_unlock(&wl_list_mutex);
1807
Eliad Pellerbaf62772011-10-10 10:12:52 +02001808 wl1271_flush_deferred_work(wl);
1809 cancel_delayed_work_sync(&wl->scan_complete_work);
1810 cancel_work_sync(&wl->netstack_work);
1811 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001812 cancel_delayed_work_sync(&wl->elp_work);
1813
1814 /* let's notify MAC80211 about the remaining pending TX frames */
1815 wl12xx_tx_reset(wl, true);
1816 mutex_lock(&wl->mutex);
1817
1818 wl1271_power_off(wl);
1819
1820 wl->band = IEEE80211_BAND_2GHZ;
1821
1822 wl->rx_counter = 0;
1823 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1824 wl->tx_blocks_available = 0;
1825 wl->tx_allocated_blocks = 0;
1826 wl->tx_results_count = 0;
1827 wl->tx_packets_count = 0;
1828 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001829 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1830 wl->ap_fw_ps_map = 0;
1831 wl->ap_ps_map = 0;
1832 wl->sched_scanning = false;
1833 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1834 memset(wl->links_map, 0, sizeof(wl->links_map));
1835 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1836 wl->active_sta_count = 0;
1837
1838 /* The system link is always allocated */
1839 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1840
1841 /*
1842 * this is performed after the cancel_work calls and the associated
1843 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1844 * get executed before all these vars have been reset.
1845 */
1846 wl->flags = 0;
1847
1848 wl->tx_blocks_freed = 0;
1849
1850 for (i = 0; i < NUM_TX_QUEUES; i++) {
1851 wl->tx_pkts_freed[i] = 0;
1852 wl->tx_allocated_pkts[i] = 0;
1853 }
1854
1855 wl1271_debugfs_reset(wl);
1856
1857 kfree(wl->fw_status);
1858 wl->fw_status = NULL;
1859 kfree(wl->tx_res_if);
1860 wl->tx_res_if = NULL;
1861 kfree(wl->target_mem_map);
1862 wl->target_mem_map = NULL;
1863
1864 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001865}
1866
Eliad Pellere5a359f2011-10-10 10:13:15 +02001867static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1868{
1869 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1870 WL12XX_MAX_RATE_POLICIES);
1871 if (policy >= WL12XX_MAX_RATE_POLICIES)
1872 return -EBUSY;
1873
1874 __set_bit(policy, wl->rate_policies_map);
1875 *idx = policy;
1876 return 0;
1877}
1878
1879static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1880{
1881 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1882 return;
1883
1884 __clear_bit(*idx, wl->rate_policies_map);
1885 *idx = WL12XX_MAX_RATE_POLICIES;
1886}
1887
Eliad Peller536129c2011-10-05 11:55:45 +02001888static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001889{
Eliad Peller536129c2011-10-05 11:55:45 +02001890 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001891 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001892 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001893 return WL1271_ROLE_P2P_GO;
1894 else
1895 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001896
1897 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001898 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001899 return WL1271_ROLE_P2P_CL;
1900 else
1901 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001902
Eliad Peller227e81e2011-08-14 13:17:26 +03001903 case BSS_TYPE_IBSS:
1904 return WL1271_ROLE_IBSS;
1905
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001907 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001908 }
1909 return WL12XX_INVALID_ROLE_TYPE;
1910}
1911
Eliad Peller83587502011-10-10 10:12:53 +02001912static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001913{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001914 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001915 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001916
Eliad Peller48e93e42011-10-10 10:12:58 +02001917 /* clear everything but the persistent data */
1918 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001919
1920 switch (ieee80211_vif_type_p2p(vif)) {
1921 case NL80211_IFTYPE_P2P_CLIENT:
1922 wlvif->p2p = 1;
1923 /* fall-through */
1924 case NL80211_IFTYPE_STATION:
1925 wlvif->bss_type = BSS_TYPE_STA_BSS;
1926 break;
1927 case NL80211_IFTYPE_ADHOC:
1928 wlvif->bss_type = BSS_TYPE_IBSS;
1929 break;
1930 case NL80211_IFTYPE_P2P_GO:
1931 wlvif->p2p = 1;
1932 /* fall-through */
1933 case NL80211_IFTYPE_AP:
1934 wlvif->bss_type = BSS_TYPE_AP_BSS;
1935 break;
1936 default:
1937 wlvif->bss_type = MAX_BSS_TYPE;
1938 return -EOPNOTSUPP;
1939 }
1940
Eliad Peller0603d892011-10-05 11:55:51 +02001941 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001942 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001943 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001944
Eliad Pellere936bbe2011-10-05 11:55:56 +02001945 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1946 wlvif->bss_type == BSS_TYPE_IBSS) {
1947 /* init sta/ibss data */
1948 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001949 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1950 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1951 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001952 } else {
1953 /* init ap data */
1954 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1955 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001956 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1957 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1958 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1959 wl12xx_allocate_rate_policy(wl,
1960 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001961 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001962
Eliad Peller83587502011-10-10 10:12:53 +02001963 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1964 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001965 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001966 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001967 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001968 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1969
Eliad Peller1b92f152011-10-10 10:13:09 +02001970 /*
1971 * mac80211 configures some values globally, while we treat them
1972 * per-interface. thus, on init, we have to copy them from wl
1973 */
1974 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001975 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001976 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001977
Eliad Peller9eb599e2011-10-10 10:12:59 +02001978 INIT_WORK(&wlvif->rx_streaming_enable_work,
1979 wl1271_rx_streaming_enable_work);
1980 INIT_WORK(&wlvif->rx_streaming_disable_work,
1981 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001982 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001983
Eliad Peller9eb599e2011-10-10 10:12:59 +02001984 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1985 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001986 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001987}
1988
Eliad Peller1d095472011-10-10 10:12:49 +02001989static bool wl12xx_init_fw(struct wl1271 *wl)
1990{
1991 int retries = WL1271_BOOT_RETRIES;
1992 bool booted = false;
1993 struct wiphy *wiphy = wl->hw->wiphy;
1994 int ret;
1995
1996 while (retries) {
1997 retries--;
1998 ret = wl1271_chip_wakeup(wl);
1999 if (ret < 0)
2000 goto power_off;
2001
2002 ret = wl1271_boot(wl);
2003 if (ret < 0)
2004 goto power_off;
2005
2006 ret = wl1271_hw_init(wl);
2007 if (ret < 0)
2008 goto irq_disable;
2009
2010 booted = true;
2011 break;
2012
2013irq_disable:
2014 mutex_unlock(&wl->mutex);
2015 /* Unlocking the mutex in the middle of handling is
2016 inherently unsafe. In this case we deem it safe to do,
2017 because we need to let any possibly pending IRQ out of
2018 the system (and while we are WL1271_STATE_OFF the IRQ
2019 work function will not do anything.) Also, any other
2020 possible concurrent operations will fail due to the
2021 current state, hence the wl1271 struct should be safe. */
2022 wl1271_disable_interrupts(wl);
2023 wl1271_flush_deferred_work(wl);
2024 cancel_work_sync(&wl->netstack_work);
2025 mutex_lock(&wl->mutex);
2026power_off:
2027 wl1271_power_off(wl);
2028 }
2029
2030 if (!booted) {
2031 wl1271_error("firmware boot failed despite %d retries",
2032 WL1271_BOOT_RETRIES);
2033 goto out;
2034 }
2035
2036 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2037
2038 /* update hw/fw version info in wiphy struct */
2039 wiphy->hw_version = wl->chip.id;
2040 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2041 sizeof(wiphy->fw_version));
2042
2043 /*
2044 * Now we know if 11a is supported (info from the NVS), so disable
2045 * 11a channels if not supported
2046 */
2047 if (!wl->enable_11a)
2048 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2049
2050 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2051 wl->enable_11a ? "" : "not ");
2052
2053 wl->state = WL1271_STATE_ON;
2054out:
2055 return booted;
2056}
2057
Eliad Peller92e712d2011-12-18 20:25:43 +02002058static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2059{
2060 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2061}
2062
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002063static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2064 struct ieee80211_vif *vif)
2065{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002066 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002067 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002068 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002069 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002070 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002071
Johannes Bergea086352012-01-19 09:29:58 +01002072 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2073 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002074
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002075 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002076 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002077
2078 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002079 ret = wl1271_ps_elp_wakeup(wl);
2080 if (ret < 0)
2081 goto out_unlock;
2082
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002083 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002084 wl1271_debug(DEBUG_MAC80211,
2085 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002086 ret = -EBUSY;
2087 goto out;
2088 }
2089
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002090 /*
2091 * in some very corner case HW recovery scenarios its possible to
2092 * get here before __wl1271_op_remove_interface is complete, so
2093 * opt out if that is the case.
2094 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002095 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2096 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002097 ret = -EBUSY;
2098 goto out;
2099 }
2100
Eliad Peller83587502011-10-10 10:12:53 +02002101 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002102 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002103 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002104
Eliad Peller252efa42011-10-05 11:56:00 +02002105 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002106 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002107 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2108 ret = -EINVAL;
2109 goto out;
2110 }
Eliad Peller1d095472011-10-10 10:12:49 +02002111
Eliad Peller784f6942011-10-05 11:55:39 +02002112 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002113 * TODO: after the nvs issue will be solved, move this block
2114 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002115 */
Eliad Peller1d095472011-10-10 10:12:49 +02002116 if (wl->state == WL1271_STATE_OFF) {
2117 /*
2118 * we still need this in order to configure the fw
2119 * while uploading the nvs
2120 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002121 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002122
Eliad Peller1d095472011-10-10 10:12:49 +02002123 booted = wl12xx_init_fw(wl);
2124 if (!booted) {
2125 ret = -EINVAL;
2126 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002127 }
Eliad Peller1d095472011-10-10 10:12:49 +02002128 }
Eliad Peller04e80792011-08-14 13:17:09 +03002129
Eliad Peller1d095472011-10-10 10:12:49 +02002130 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2131 wlvif->bss_type == BSS_TYPE_IBSS) {
2132 /*
2133 * The device role is a special role used for
2134 * rx and tx frames prior to association (as
2135 * the STA role can get packets only from
2136 * its associated bssid)
2137 */
Eliad Peller784f6942011-10-05 11:55:39 +02002138 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002139 WL1271_ROLE_DEVICE,
2140 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002141 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002142 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002143 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002144
Eliad Peller1d095472011-10-10 10:12:49 +02002145 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2146 role_type, &wlvif->role_id);
2147 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002148 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002149
2150 ret = wl1271_init_vif_specific(wl, vif);
2151 if (ret < 0)
2152 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002153
2154 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002155 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002156 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002157
2158 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2159 wl->ap_count++;
2160 else
2161 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002162out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002163 wl1271_ps_elp_sleep(wl);
2164out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002165 mutex_unlock(&wl->mutex);
2166
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002167 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002168 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002169 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002170 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002171
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002172 return ret;
2173}
2174
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002175static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002176 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002177 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002178{
Eliad Peller536129c2011-10-05 11:55:45 +02002179 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002180 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002182 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002183
Eliad Peller10c8cd02011-10-10 10:13:06 +02002184 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2185 return;
2186
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002187 wl->vif = NULL;
2188
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002189 /* because of hardware recovery, we may get here twice */
2190 if (wl->state != WL1271_STATE_ON)
2191 return;
2192
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002193 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194
Eliad Pellerbaf62772011-10-10 10:12:52 +02002195 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2196 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002197 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002198 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002199 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002200 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002201 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002202 }
2203
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002204 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2205 /* disable active roles */
2206 ret = wl1271_ps_elp_wakeup(wl);
2207 if (ret < 0)
2208 goto deinit;
2209
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002210 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2211 wlvif->bss_type == BSS_TYPE_IBSS) {
2212 if (wl12xx_dev_role_started(wlvif))
2213 wl12xx_stop_dev(wl, wlvif);
2214
Eliad Peller7edebf52011-10-05 11:55:52 +02002215 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002216 if (ret < 0)
2217 goto deinit;
2218 }
2219
Eliad Peller0603d892011-10-05 11:55:51 +02002220 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002221 if (ret < 0)
2222 goto deinit;
2223
2224 wl1271_ps_elp_sleep(wl);
2225 }
2226deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002227 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002228 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002229
2230 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2231 wlvif->bss_type == BSS_TYPE_IBSS) {
2232 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2233 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2234 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2235 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2236 } else {
2237 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2238 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2239 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2240 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2241 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2242 wl12xx_free_rate_policy(wl,
2243 &wlvif->ap.ucast_rate_idx[i]);
2244 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002245
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002246 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002247 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002248 if (wl->last_wlvif == wlvif)
2249 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002250 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002251 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002252 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002253 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002254
Eliad Pellera4e41302011-10-11 11:49:15 +02002255 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2256 wl->ap_count--;
2257 else
2258 wl->sta_count--;
2259
Eliad Pellerbaf62772011-10-10 10:12:52 +02002260 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002261
Eliad Peller9eb599e2011-10-10 10:12:59 +02002262 del_timer_sync(&wlvif->rx_streaming_timer);
2263 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2264 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002265
Eliad Pellerbaf62772011-10-10 10:12:52 +02002266 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002267}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002268
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002269static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2270 struct ieee80211_vif *vif)
2271{
2272 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002273 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002274 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002275
2276 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002277
2278 if (wl->state == WL1271_STATE_OFF ||
2279 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2280 goto out;
2281
Juuso Oikarinen67353292010-11-18 15:19:02 +02002282 /*
2283 * wl->vif can be null here if someone shuts down the interface
2284 * just when hardware recovery has been started.
2285 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002286 wl12xx_for_each_wlvif(wl, iter) {
2287 if (iter != wlvif)
2288 continue;
2289
Eliad Peller536129c2011-10-05 11:55:45 +02002290 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002291 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002292 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002293 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002294out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002295 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002296 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002297}
2298
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002299static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2300 struct ieee80211_vif *vif,
2301 enum nl80211_iftype new_type, bool p2p)
2302{
2303 wl1271_op_remove_interface(hw, vif);
2304
2305 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2306 vif->p2p = p2p;
2307 return wl1271_op_add_interface(hw, vif);
2308}
2309
Eliad Peller87fbcb02011-10-05 11:55:41 +02002310static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2311 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002312{
2313 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002314 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002315
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002316 /*
2317 * One of the side effects of the JOIN command is that is clears
2318 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2319 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002320 * Currently the only valid scenario for JOIN during association
2321 * is on roaming, in which case we will also be given new keys.
2322 * Keep the below message for now, unless it starts bothering
2323 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002324 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002325 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002326 wl1271_info("JOIN while associated.");
2327
Eliad Peller5ec8a442012-02-02 12:22:09 +02002328 /* clear encryption type */
2329 wlvif->encryption_type = KEY_NONE;
2330
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002331 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002332 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002333
Eliad Peller227e81e2011-08-14 13:17:26 +03002334 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002335 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002336 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002337 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338 if (ret < 0)
2339 goto out;
2340
Eliad Pellerba8447f2011-10-10 10:13:00 +02002341 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002342 goto out;
2343
2344 /*
2345 * The join command disable the keep-alive mode, shut down its process,
2346 * and also clear the template config, so we need to reset it all after
2347 * the join. The acx_aid starts the keep-alive process, and the order
2348 * of the commands below is relevant.
2349 */
Eliad Peller0603d892011-10-05 11:55:51 +02002350 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002351 if (ret < 0)
2352 goto out;
2353
Eliad Peller0603d892011-10-05 11:55:51 +02002354 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355 if (ret < 0)
2356 goto out;
2357
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002358 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002359 if (ret < 0)
2360 goto out;
2361
Eliad Peller0603d892011-10-05 11:55:51 +02002362 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2363 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002364 ACX_KEEP_ALIVE_TPL_VALID);
2365 if (ret < 0)
2366 goto out;
2367
2368out:
2369 return ret;
2370}
2371
Eliad Peller0603d892011-10-05 11:55:51 +02002372static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002373{
2374 int ret;
2375
Eliad Peller52630c52011-10-10 10:13:08 +02002376 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002377 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2378
Shahar Levi6d158ff2011-09-08 13:01:33 +03002379 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002380 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002381 }
2382
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002383 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002384 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002385 if (ret < 0)
2386 goto out;
2387
Oz Krakowskib992c682011-06-26 10:36:02 +03002388 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002389 wlvif->tx_security_last_seq_lsb = 0;
2390 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002391
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002392out:
2393 return ret;
2394}
2395
Eliad Peller87fbcb02011-10-05 11:55:41 +02002396static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002397{
Eliad Peller1b92f152011-10-10 10:13:09 +02002398 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002399 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002400}
2401
Eliad Peller87fbcb02011-10-05 11:55:41 +02002402static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2403 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002404{
2405 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002406 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2407
2408 if (idle == cur_idle)
2409 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002410
2411 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002412 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002413 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002414 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002415 if (ret < 0)
2416 goto out;
2417 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002418 wlvif->rate_set =
2419 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2420 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002421 if (ret < 0)
2422 goto out;
2423 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002424 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002425 ACX_KEEP_ALIVE_TPL_INVALID);
2426 if (ret < 0)
2427 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002428 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002429 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002430 /* The current firmware only supports sched_scan in idle */
2431 if (wl->sched_scanning) {
2432 wl1271_scan_sched_scan_stop(wl);
2433 ieee80211_sched_scan_stopped(wl->hw);
2434 }
2435
Eliad Peller679a6732011-10-11 11:55:44 +02002436 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002437 if (ret < 0)
2438 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002439 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002440 }
2441
2442out:
2443 return ret;
2444}
2445
Eliad Peller9f259c42011-10-10 10:13:12 +02002446static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2447 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002448{
Eliad Peller9f259c42011-10-10 10:13:12 +02002449 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2450 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002451
2452 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2453
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002454 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002455 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002456 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002457 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002458 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002459 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002460 wlvif->band = conf->channel->band;
2461 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002462
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002463 if (!is_ap) {
2464 /*
2465 * FIXME: the mac80211 should really provide a fixed
2466 * rate to use here. for now, just use the smallest
2467 * possible rate for the band as a fixed rate for
2468 * association frames and other control messages.
2469 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002470 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002471 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002472
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002473 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002474 wl1271_tx_min_rate_get(wl,
2475 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002476 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002477 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002478 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002479 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002480
Eliad Pellerba8447f2011-10-10 10:13:00 +02002481 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2482 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002483 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002484 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002485 ret = wl12xx_croc(wl,
2486 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002487 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002488 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002489 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002490 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002491 if (ret < 0)
2492 wl1271_warning("cmd join on channel "
2493 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002494 } else {
2495 /*
2496 * change the ROC channel. do it only if we are
2497 * not idle. otherwise, CROC will be called
2498 * anyway.
2499 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002500 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002501 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002502 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002503 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002504 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002505
Eliad Peller679a6732011-10-11 11:55:44 +02002506 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002507 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002508 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002509 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002510 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002511 }
2512 }
2513
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002514 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002515
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002516 if ((conf->flags & IEEE80211_CONF_PS) &&
2517 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002518 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002519
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002520 int ps_mode;
2521 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002522
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002523 if (wl->conf.conn.forced_ps) {
2524 ps_mode = STATION_POWER_SAVE_MODE;
2525 ps_mode_str = "forced";
2526 } else {
2527 ps_mode = STATION_AUTO_PS_MODE;
2528 ps_mode_str = "auto";
2529 }
2530
2531 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2532
2533 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2534
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002535 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002536 wl1271_warning("enter %s ps failed %d",
2537 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002539 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002540 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002542 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2543
Eliad Peller0603d892011-10-05 11:55:51 +02002544 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002545 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002546 if (ret < 0)
2547 wl1271_warning("exit auto ps failed %d", ret);
2548 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 }
2550
Eliad Peller6bd65022011-10-10 10:13:11 +02002551 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002552 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002554 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002555
Eliad Peller6bd65022011-10-10 10:13:11 +02002556 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002557 }
2558
Eliad Peller9f259c42011-10-10 10:13:12 +02002559 return 0;
2560}
2561
2562static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2563{
2564 struct wl1271 *wl = hw->priv;
2565 struct wl12xx_vif *wlvif;
2566 struct ieee80211_conf *conf = &hw->conf;
2567 int channel, ret = 0;
2568
2569 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2570
2571 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2572 " changed 0x%x",
2573 channel,
2574 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2575 conf->power_level,
2576 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2577 changed);
2578
2579 /*
2580 * mac80211 will go to idle nearly immediately after transmitting some
2581 * frames, such as the deauth. To make sure those frames reach the air,
2582 * wait here until the TX queue is fully flushed.
2583 */
2584 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2585 (conf->flags & IEEE80211_CONF_IDLE))
2586 wl1271_tx_flush(wl);
2587
2588 mutex_lock(&wl->mutex);
2589
2590 /* we support configuring the channel and band even while off */
2591 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2592 wl->band = conf->channel->band;
2593 wl->channel = channel;
2594 }
2595
2596 if (changed & IEEE80211_CONF_CHANGE_POWER)
2597 wl->power_level = conf->power_level;
2598
2599 if (unlikely(wl->state == WL1271_STATE_OFF))
2600 goto out;
2601
2602 ret = wl1271_ps_elp_wakeup(wl);
2603 if (ret < 0)
2604 goto out;
2605
2606 /* configure each interface */
2607 wl12xx_for_each_wlvif(wl, wlvif) {
2608 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2609 if (ret < 0)
2610 goto out_sleep;
2611 }
2612
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002613out_sleep:
2614 wl1271_ps_elp_sleep(wl);
2615
2616out:
2617 mutex_unlock(&wl->mutex);
2618
2619 return ret;
2620}
2621
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002622struct wl1271_filter_params {
2623 bool enabled;
2624 int mc_list_length;
2625 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2626};
2627
Jiri Pirko22bedad2010-04-01 21:22:57 +00002628static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2629 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002630{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002631 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002632 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002633 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002634
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002635 if (unlikely(wl->state == WL1271_STATE_OFF))
2636 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002637
Juuso Oikarinen74441132009-10-13 12:47:53 +03002638 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002639 if (!fp) {
2640 wl1271_error("Out of memory setting filters.");
2641 return 0;
2642 }
2643
2644 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002645 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002646 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2647 fp->enabled = false;
2648 } else {
2649 fp->enabled = true;
2650 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002651 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002652 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002653 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002654 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002655 }
2656
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002657 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002658}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002660#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2661 FIF_ALLMULTI | \
2662 FIF_FCSFAIL | \
2663 FIF_BCN_PRBRESP_PROMISC | \
2664 FIF_CONTROL | \
2665 FIF_OTHER_BSS)
2666
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002667static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2668 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002669 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002670{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002671 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002672 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002673 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002674
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002675 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002676
Arik Nemtsov7d057862010-10-16 19:25:35 +02002677 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2678 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002679
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002680 mutex_lock(&wl->mutex);
2681
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002682 *total &= WL1271_SUPPORTED_FILTERS;
2683 changed &= WL1271_SUPPORTED_FILTERS;
2684
2685 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002686 goto out;
2687
Ido Yariva6208652011-03-01 15:14:41 +02002688 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002689 if (ret < 0)
2690 goto out;
2691
Eliad Peller6e8cd332011-10-10 10:13:13 +02002692 wl12xx_for_each_wlvif(wl, wlvif) {
2693 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2694 if (*total & FIF_ALLMULTI)
2695 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2696 false,
2697 NULL, 0);
2698 else if (fp)
2699 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2700 fp->enabled,
2701 fp->mc_list,
2702 fp->mc_list_length);
2703 if (ret < 0)
2704 goto out_sleep;
2705 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002706 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002707
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002708 /*
2709 * the fw doesn't provide an api to configure the filters. instead,
2710 * the filters configuration is based on the active roles / ROC
2711 * state.
2712 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002713
2714out_sleep:
2715 wl1271_ps_elp_sleep(wl);
2716
2717out:
2718 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002719 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002720}
2721
Eliad Peller170d0e62011-10-05 11:56:06 +02002722static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2723 u8 id, u8 key_type, u8 key_size,
2724 const u8 *key, u8 hlid, u32 tx_seq_32,
2725 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002726{
2727 struct wl1271_ap_key *ap_key;
2728 int i;
2729
2730 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2731
2732 if (key_size > MAX_KEY_SIZE)
2733 return -EINVAL;
2734
2735 /*
2736 * Find next free entry in ap_keys. Also check we are not replacing
2737 * an existing key.
2738 */
2739 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002740 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002741 break;
2742
Eliad Peller170d0e62011-10-05 11:56:06 +02002743 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002744 wl1271_warning("trying to record key replacement");
2745 return -EINVAL;
2746 }
2747 }
2748
2749 if (i == MAX_NUM_KEYS)
2750 return -EBUSY;
2751
2752 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2753 if (!ap_key)
2754 return -ENOMEM;
2755
2756 ap_key->id = id;
2757 ap_key->key_type = key_type;
2758 ap_key->key_size = key_size;
2759 memcpy(ap_key->key, key, key_size);
2760 ap_key->hlid = hlid;
2761 ap_key->tx_seq_32 = tx_seq_32;
2762 ap_key->tx_seq_16 = tx_seq_16;
2763
Eliad Peller170d0e62011-10-05 11:56:06 +02002764 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002765 return 0;
2766}
2767
Eliad Peller170d0e62011-10-05 11:56:06 +02002768static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002769{
2770 int i;
2771
2772 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002773 kfree(wlvif->ap.recorded_keys[i]);
2774 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002775 }
2776}
2777
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002778static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779{
2780 int i, ret = 0;
2781 struct wl1271_ap_key *key;
2782 bool wep_key_added = false;
2783
2784 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002785 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002786 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002787 break;
2788
Eliad Peller170d0e62011-10-05 11:56:06 +02002789 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002790 hlid = key->hlid;
2791 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002792 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002793
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002794 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002795 key->id, key->key_type,
2796 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002797 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798 key->tx_seq_16);
2799 if (ret < 0)
2800 goto out;
2801
2802 if (key->key_type == KEY_WEP)
2803 wep_key_added = true;
2804 }
2805
2806 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002807 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002808 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809 if (ret < 0)
2810 goto out;
2811 }
2812
2813out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002814 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002815 return ret;
2816}
2817
Eliad Peller536129c2011-10-05 11:55:45 +02002818static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2819 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002820 u8 key_size, const u8 *key, u32 tx_seq_32,
2821 u16 tx_seq_16, struct ieee80211_sta *sta)
2822{
2823 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002824 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002825
2826 if (is_ap) {
2827 struct wl1271_station *wl_sta;
2828 u8 hlid;
2829
2830 if (sta) {
2831 wl_sta = (struct wl1271_station *)sta->drv_priv;
2832 hlid = wl_sta->hlid;
2833 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002834 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002835 }
2836
Eliad Peller53d40d02011-10-10 10:13:02 +02002837 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002838 /*
2839 * We do not support removing keys after AP shutdown.
2840 * Pretend we do to make mac80211 happy.
2841 */
2842 if (action != KEY_ADD_OR_REPLACE)
2843 return 0;
2844
Eliad Peller170d0e62011-10-05 11:56:06 +02002845 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002846 key_type, key_size,
2847 key, hlid, tx_seq_32,
2848 tx_seq_16);
2849 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002850 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002851 id, key_type, key_size,
2852 key, hlid, tx_seq_32,
2853 tx_seq_16);
2854 }
2855
2856 if (ret < 0)
2857 return ret;
2858 } else {
2859 const u8 *addr;
2860 static const u8 bcast_addr[ETH_ALEN] = {
2861 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2862 };
2863
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002864 /*
2865 * A STA set to GEM cipher requires 2 tx spare blocks.
2866 * Return to default value when GEM cipher key is removed
2867 */
2868 if (key_type == KEY_GEM) {
2869 if (action == KEY_ADD_OR_REPLACE)
2870 wl->tx_spare_blocks = 2;
2871 else if (action == KEY_REMOVE)
2872 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2873 }
2874
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002875 addr = sta ? sta->addr : bcast_addr;
2876
2877 if (is_zero_ether_addr(addr)) {
2878 /* We dont support TX only encryption */
2879 return -EOPNOTSUPP;
2880 }
2881
2882 /* The wl1271 does not allow to remove unicast keys - they
2883 will be cleared automatically on next CMD_JOIN. Ignore the
2884 request silently, as we dont want the mac80211 to emit
2885 an error message. */
2886 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2887 return 0;
2888
Eliad Peller010d3d32011-08-14 13:17:31 +03002889 /* don't remove key if hlid was already deleted */
2890 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002891 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002892 return 0;
2893
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002894 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002895 id, key_type, key_size,
2896 key, addr, tx_seq_32,
2897 tx_seq_16);
2898 if (ret < 0)
2899 return ret;
2900
2901 /* the default WEP key needs to be configured at least once */
2902 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002903 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002904 wlvif->default_key,
2905 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002906 if (ret < 0)
2907 return ret;
2908 }
2909 }
2910
2911 return 0;
2912}
2913
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2915 struct ieee80211_vif *vif,
2916 struct ieee80211_sta *sta,
2917 struct ieee80211_key_conf *key_conf)
2918{
2919 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002920 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002921 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002922 u32 tx_seq_32 = 0;
2923 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002924 u8 key_type;
2925
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002926 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2927
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002928 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002929 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002930 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 key_conf->keylen, key_conf->flags);
2932 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2933
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002934 mutex_lock(&wl->mutex);
2935
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002936 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2937 ret = -EAGAIN;
2938 goto out_unlock;
2939 }
2940
Ido Yariva6208652011-03-01 15:14:41 +02002941 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002942 if (ret < 0)
2943 goto out_unlock;
2944
Johannes Berg97359d12010-08-10 09:46:38 +02002945 switch (key_conf->cipher) {
2946 case WLAN_CIPHER_SUITE_WEP40:
2947 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 key_type = KEY_WEP;
2949
2950 key_conf->hw_key_idx = key_conf->keyidx;
2951 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002952 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002953 key_type = KEY_TKIP;
2954
2955 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002956 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2957 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002958 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002959 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002960 key_type = KEY_AES;
2961
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002962 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002963 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2964 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002965 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002966 case WL1271_CIPHER_SUITE_GEM:
2967 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002968 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2969 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002970 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002971 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002972 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002973
2974 ret = -EOPNOTSUPP;
2975 goto out_sleep;
2976 }
2977
2978 switch (cmd) {
2979 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002980 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002981 key_conf->keyidx, key_type,
2982 key_conf->keylen, key_conf->key,
2983 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002984 if (ret < 0) {
2985 wl1271_error("Could not add or replace key");
2986 goto out_sleep;
2987 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02002988
2989 /*
2990 * reconfiguring arp response if the unicast (or common)
2991 * encryption key type was changed
2992 */
2993 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
2994 (sta || key_type == KEY_WEP) &&
2995 wlvif->encryption_type != key_type) {
2996 wlvif->encryption_type = key_type;
2997 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
2998 if (ret < 0) {
2999 wl1271_warning("build arp rsp failed: %d", ret);
3000 goto out_sleep;
3001 }
3002 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003003 break;
3004
3005 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003006 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003007 key_conf->keyidx, key_type,
3008 key_conf->keylen, key_conf->key,
3009 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003010 if (ret < 0) {
3011 wl1271_error("Could not remove key");
3012 goto out_sleep;
3013 }
3014 break;
3015
3016 default:
3017 wl1271_error("Unsupported key cmd 0x%x", cmd);
3018 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 break;
3020 }
3021
3022out_sleep:
3023 wl1271_ps_elp_sleep(wl);
3024
3025out_unlock:
3026 mutex_unlock(&wl->mutex);
3027
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 return ret;
3029}
3030
3031static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003032 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003033 struct cfg80211_scan_request *req)
3034{
3035 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003036 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3037
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003038 int ret;
3039 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003040 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003041
3042 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3043
3044 if (req->n_ssids) {
3045 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003046 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047 }
3048
3049 mutex_lock(&wl->mutex);
3050
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003051 if (wl->state == WL1271_STATE_OFF) {
3052 /*
3053 * We cannot return -EBUSY here because cfg80211 will expect
3054 * a call to ieee80211_scan_completed if we do - in this case
3055 * there won't be any call.
3056 */
3057 ret = -EAGAIN;
3058 goto out;
3059 }
3060
Ido Yariva6208652011-03-01 15:14:41 +02003061 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003062 if (ret < 0)
3063 goto out;
3064
Eliad Peller92e712d2011-12-18 20:25:43 +02003065 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3066 test_bit(wlvif->role_id, wl->roc_map)) {
3067 /* don't allow scanning right now */
3068 ret = -EBUSY;
3069 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003070 }
3071
Eliad Peller784f6942011-10-05 11:55:39 +02003072 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003073out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003074 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003075out:
3076 mutex_unlock(&wl->mutex);
3077
3078 return ret;
3079}
3080
Eliad Peller73ecce32011-06-27 13:06:45 +03003081static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3082 struct ieee80211_vif *vif)
3083{
3084 struct wl1271 *wl = hw->priv;
3085 int ret;
3086
3087 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3088
3089 mutex_lock(&wl->mutex);
3090
3091 if (wl->state == WL1271_STATE_OFF)
3092 goto out;
3093
3094 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3095 goto out;
3096
3097 ret = wl1271_ps_elp_wakeup(wl);
3098 if (ret < 0)
3099 goto out;
3100
3101 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3102 ret = wl1271_scan_stop(wl);
3103 if (ret < 0)
3104 goto out_sleep;
3105 }
3106 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3107 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003108 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003109 wl->scan.req = NULL;
3110 ieee80211_scan_completed(wl->hw, true);
3111
3112out_sleep:
3113 wl1271_ps_elp_sleep(wl);
3114out:
3115 mutex_unlock(&wl->mutex);
3116
3117 cancel_delayed_work_sync(&wl->scan_complete_work);
3118}
3119
Luciano Coelho33c2c062011-05-10 14:46:02 +03003120static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3121 struct ieee80211_vif *vif,
3122 struct cfg80211_sched_scan_request *req,
3123 struct ieee80211_sched_scan_ies *ies)
3124{
3125 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003126 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003127 int ret;
3128
3129 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3130
3131 mutex_lock(&wl->mutex);
3132
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003133 if (wl->state == WL1271_STATE_OFF) {
3134 ret = -EAGAIN;
3135 goto out;
3136 }
3137
Luciano Coelho33c2c062011-05-10 14:46:02 +03003138 ret = wl1271_ps_elp_wakeup(wl);
3139 if (ret < 0)
3140 goto out;
3141
Eliad Peller536129c2011-10-05 11:55:45 +02003142 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003143 if (ret < 0)
3144 goto out_sleep;
3145
Eliad Peller536129c2011-10-05 11:55:45 +02003146 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003147 if (ret < 0)
3148 goto out_sleep;
3149
3150 wl->sched_scanning = true;
3151
3152out_sleep:
3153 wl1271_ps_elp_sleep(wl);
3154out:
3155 mutex_unlock(&wl->mutex);
3156 return ret;
3157}
3158
3159static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3160 struct ieee80211_vif *vif)
3161{
3162 struct wl1271 *wl = hw->priv;
3163 int ret;
3164
3165 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3166
3167 mutex_lock(&wl->mutex);
3168
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003169 if (wl->state == WL1271_STATE_OFF)
3170 goto out;
3171
Luciano Coelho33c2c062011-05-10 14:46:02 +03003172 ret = wl1271_ps_elp_wakeup(wl);
3173 if (ret < 0)
3174 goto out;
3175
3176 wl1271_scan_sched_scan_stop(wl);
3177
3178 wl1271_ps_elp_sleep(wl);
3179out:
3180 mutex_unlock(&wl->mutex);
3181}
3182
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003183static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3184{
3185 struct wl1271 *wl = hw->priv;
3186 int ret = 0;
3187
3188 mutex_lock(&wl->mutex);
3189
3190 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3191 ret = -EAGAIN;
3192 goto out;
3193 }
3194
Ido Yariva6208652011-03-01 15:14:41 +02003195 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003196 if (ret < 0)
3197 goto out;
3198
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003199 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003200 if (ret < 0)
3201 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3202
3203 wl1271_ps_elp_sleep(wl);
3204
3205out:
3206 mutex_unlock(&wl->mutex);
3207
3208 return ret;
3209}
3210
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003211static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3212{
3213 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003214 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003215 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003216
3217 mutex_lock(&wl->mutex);
3218
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003219 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3220 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003221 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003222 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003223
Ido Yariva6208652011-03-01 15:14:41 +02003224 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003225 if (ret < 0)
3226 goto out;
3227
Eliad Peller6e8cd332011-10-10 10:13:13 +02003228 wl12xx_for_each_wlvif(wl, wlvif) {
3229 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3230 if (ret < 0)
3231 wl1271_warning("set rts threshold failed: %d", ret);
3232 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003233 wl1271_ps_elp_sleep(wl);
3234
3235out:
3236 mutex_unlock(&wl->mutex);
3237
3238 return ret;
3239}
3240
Eliad Peller1fe9f162011-10-05 11:55:48 +02003241static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003242 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003243{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003244 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003245 u8 ssid_len;
3246 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3247 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003248
Eliad Peller889cb362011-05-01 09:56:45 +03003249 if (!ptr) {
3250 wl1271_error("No SSID in IEs!");
3251 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003252 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003253
Eliad Peller889cb362011-05-01 09:56:45 +03003254 ssid_len = ptr[1];
3255 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3256 wl1271_error("SSID is too long!");
3257 return -EINVAL;
3258 }
3259
Eliad Peller1fe9f162011-10-05 11:55:48 +02003260 wlvif->ssid_len = ssid_len;
3261 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003262 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003263}
3264
Eliad Pellerd48055d2011-09-15 12:07:04 +03003265static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3266{
3267 int len;
3268 const u8 *next, *end = skb->data + skb->len;
3269 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3270 skb->len - ieoffset);
3271 if (!ie)
3272 return;
3273 len = ie[1] + 2;
3274 next = ie + len;
3275 memmove(ie, next, end - next);
3276 skb_trim(skb, skb->len - len);
3277}
3278
Eliad Peller26b4bf22011-09-15 12:07:05 +03003279static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3280 unsigned int oui, u8 oui_type,
3281 int ieoffset)
3282{
3283 int len;
3284 const u8 *next, *end = skb->data + skb->len;
3285 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3286 skb->data + ieoffset,
3287 skb->len - ieoffset);
3288 if (!ie)
3289 return;
3290 len = ie[1] + 2;
3291 next = ie + len;
3292 memmove(ie, next, end - next);
3293 skb_trim(skb, skb->len - len);
3294}
3295
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003296static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3297 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003298{
Eliad Pellercdaac622012-01-31 11:57:16 +02003299 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003300 struct sk_buff *skb;
3301 int ret;
3302
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003303 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003304 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003305 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003306
Eliad Pellercdaac622012-01-31 11:57:16 +02003307 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003308 CMD_TEMPL_AP_PROBE_RESPONSE,
3309 skb->data,
3310 skb->len, 0,
3311 rates);
3312
3313 dev_kfree_skb(skb);
3314 return ret;
3315}
3316
3317static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3318 struct ieee80211_vif *vif,
3319 u8 *probe_rsp_data,
3320 size_t probe_rsp_len,
3321 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003322{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003323 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3324 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003325 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3326 int ssid_ie_offset, ie_offset, templ_len;
3327 const u8 *ptr;
3328
3329 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003330 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003331 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003332 CMD_TEMPL_AP_PROBE_RESPONSE,
3333 probe_rsp_data,
3334 probe_rsp_len, 0,
3335 rates);
3336
3337 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3338 wl1271_error("probe_rsp template too big");
3339 return -EINVAL;
3340 }
3341
3342 /* start searching from IE offset */
3343 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3344
3345 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3346 probe_rsp_len - ie_offset);
3347 if (!ptr) {
3348 wl1271_error("No SSID in beacon!");
3349 return -EINVAL;
3350 }
3351
3352 ssid_ie_offset = ptr - probe_rsp_data;
3353 ptr += (ptr[1] + 2);
3354
3355 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3356
3357 /* insert SSID from bss_conf */
3358 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3359 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3360 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3361 bss_conf->ssid, bss_conf->ssid_len);
3362 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3363
3364 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3365 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3366 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3367
Eliad Pellercdaac622012-01-31 11:57:16 +02003368 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003369 CMD_TEMPL_AP_PROBE_RESPONSE,
3370 probe_rsp_templ,
3371 templ_len, 0,
3372 rates);
3373}
3374
Arik Nemtsove78a2872010-10-16 19:07:21 +02003375static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003376 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 struct ieee80211_bss_conf *bss_conf,
3378 u32 changed)
3379{
Eliad Peller0603d892011-10-05 11:55:51 +02003380 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003381 int ret = 0;
3382
3383 if (changed & BSS_CHANGED_ERP_SLOT) {
3384 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003385 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003386 else
Eliad Peller0603d892011-10-05 11:55:51 +02003387 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003388 if (ret < 0) {
3389 wl1271_warning("Set slot time failed %d", ret);
3390 goto out;
3391 }
3392 }
3393
3394 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3395 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003396 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 else
Eliad Peller0603d892011-10-05 11:55:51 +02003398 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003399 }
3400
3401 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3402 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003403 ret = wl1271_acx_cts_protect(wl, wlvif,
3404 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003405 else
Eliad Peller0603d892011-10-05 11:55:51 +02003406 ret = wl1271_acx_cts_protect(wl, wlvif,
3407 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 if (ret < 0) {
3409 wl1271_warning("Set ctsprotect failed %d", ret);
3410 goto out;
3411 }
3412 }
3413
3414out:
3415 return ret;
3416}
3417
3418static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3419 struct ieee80211_vif *vif,
3420 struct ieee80211_bss_conf *bss_conf,
3421 u32 changed)
3422{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003423 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003424 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003425 int ret = 0;
3426
3427 if ((changed & BSS_CHANGED_BEACON_INT)) {
3428 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3429 bss_conf->beacon_int);
3430
Eliad Peller6a899792011-10-05 11:55:58 +02003431 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003432 }
3433
Arik Nemtsov560f0022011-11-08 18:46:54 +02003434 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3435 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003436 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3437 wl1271_debug(DEBUG_AP, "probe response updated");
3438 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3439 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003440 }
3441
Arik Nemtsove78a2872010-10-16 19:07:21 +02003442 if ((changed & BSS_CHANGED_BEACON)) {
3443 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003444 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003445 int ieoffset = offsetof(struct ieee80211_mgmt,
3446 u.beacon.variable);
3447 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3448 u16 tmpl_id;
3449
Arik Nemtsov560f0022011-11-08 18:46:54 +02003450 if (!beacon) {
3451 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003452 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003453 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454
3455 wl1271_debug(DEBUG_MASTER, "beacon updated");
3456
Eliad Peller1fe9f162011-10-05 11:55:48 +02003457 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003458 if (ret < 0) {
3459 dev_kfree_skb(beacon);
3460 goto out;
3461 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003462 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003463 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3464 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003465 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466 beacon->data,
3467 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003468 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 if (ret < 0) {
3470 dev_kfree_skb(beacon);
3471 goto out;
3472 }
3473
Arik Nemtsov560f0022011-11-08 18:46:54 +02003474 /*
3475 * In case we already have a probe-resp beacon set explicitly
3476 * by usermode, don't use the beacon data.
3477 */
3478 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3479 goto end_bcn;
3480
Eliad Pellerd48055d2011-09-15 12:07:04 +03003481 /* remove TIM ie from probe response */
3482 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3483
Eliad Peller26b4bf22011-09-15 12:07:05 +03003484 /*
3485 * remove p2p ie from probe response.
3486 * the fw reponds to probe requests that don't include
3487 * the p2p ie. probe requests with p2p ie will be passed,
3488 * and will be responded by the supplicant (the spec
3489 * forbids including the p2p ie when responding to probe
3490 * requests that didn't include it).
3491 */
3492 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3493 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3494
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 hdr = (struct ieee80211_hdr *) beacon->data;
3496 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3497 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003498 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003499 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003500 beacon->data,
3501 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003502 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003503 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003504 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003505 CMD_TEMPL_PROBE_RESPONSE,
3506 beacon->data,
3507 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003508 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003509end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003510 dev_kfree_skb(beacon);
3511 if (ret < 0)
3512 goto out;
3513 }
3514
3515out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003516 if (ret != 0)
3517 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003518 return ret;
3519}
3520
3521/* AP mode changes */
3522static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003523 struct ieee80211_vif *vif,
3524 struct ieee80211_bss_conf *bss_conf,
3525 u32 changed)
3526{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003527 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003528 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003529
Arik Nemtsove78a2872010-10-16 19:07:21 +02003530 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3531 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
Eliad Peller87fbcb02011-10-05 11:55:41 +02003533 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003534 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003535 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003537
Eliad Peller87fbcb02011-10-05 11:55:41 +02003538 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003539 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003540 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003541 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003542 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003543
Eliad Peller784f6942011-10-05 11:55:39 +02003544 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003545 if (ret < 0)
3546 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003547 }
3548
Arik Nemtsove78a2872010-10-16 19:07:21 +02003549 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3550 if (ret < 0)
3551 goto out;
3552
3553 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3554 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003555 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003556 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003557 if (ret < 0)
3558 goto out;
3559
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003560 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003561 if (ret < 0)
3562 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003563
Eliad Peller53d40d02011-10-10 10:13:02 +02003564 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003565 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003566 }
3567 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003568 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003569 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003570 if (ret < 0)
3571 goto out;
3572
Eliad Peller53d40d02011-10-10 10:13:02 +02003573 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003574 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3575 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003576 wl1271_debug(DEBUG_AP, "stopped AP");
3577 }
3578 }
3579 }
3580
Eliad Peller0603d892011-10-05 11:55:51 +02003581 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003582 if (ret < 0)
3583 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003584
3585 /* Handle HT information change */
3586 if ((changed & BSS_CHANGED_HT) &&
3587 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003588 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003589 bss_conf->ht_operation_mode);
3590 if (ret < 0) {
3591 wl1271_warning("Set ht information failed %d", ret);
3592 goto out;
3593 }
3594 }
3595
Arik Nemtsove78a2872010-10-16 19:07:21 +02003596out:
3597 return;
3598}
3599
3600/* STA/IBSS mode changes */
3601static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3602 struct ieee80211_vif *vif,
3603 struct ieee80211_bss_conf *bss_conf,
3604 u32 changed)
3605{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003606 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003607 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003608 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003609 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003610 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003611 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003612 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003613 bool sta_exists = false;
3614 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003615
3616 if (is_ibss) {
3617 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3618 changed);
3619 if (ret < 0)
3620 goto out;
3621 }
3622
Eliad Peller227e81e2011-08-14 13:17:26 +03003623 if (changed & BSS_CHANGED_IBSS) {
3624 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003625 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003626 ibss_joined = true;
3627 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003628 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3629 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003630 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003631 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003632 }
3633 }
3634 }
3635
3636 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003637 do_join = true;
3638
3639 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003640 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003641 do_join = true;
3642
Eliad Peller227e81e2011-08-14 13:17:26 +03003643 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003644 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3645 bss_conf->enable_beacon ? "enabled" : "disabled");
3646
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003647 do_join = true;
3648 }
3649
Eliad Pellerc31e4942011-10-23 08:21:55 +02003650 if (changed & BSS_CHANGED_IDLE) {
3651 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3652 if (ret < 0)
3653 wl1271_warning("idle mode change failed %d", ret);
3654 }
3655
Arik Nemtsove78a2872010-10-16 19:07:21 +02003656 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003657 bool enable = false;
3658 if (bss_conf->cqm_rssi_thold)
3659 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003660 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003661 bss_conf->cqm_rssi_thold,
3662 bss_conf->cqm_rssi_hyst);
3663 if (ret < 0)
3664 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003665 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003666 }
3667
Eliad Peller7db4ee62012-01-24 18:18:42 +02003668 if (changed & BSS_CHANGED_BSSID &&
3669 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003670 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003671 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003672 if (ret < 0)
3673 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003674
Eliad Peller784f6942011-10-05 11:55:39 +02003675 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003676 if (ret < 0)
3677 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003678
Eliad Pellerfa287b82010-12-26 09:27:50 +01003679 /* Need to update the BSSID (for filtering etc) */
3680 do_join = true;
3681 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003682
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003683 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3684 rcu_read_lock();
3685 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3686 if (!sta)
3687 goto sta_not_found;
3688
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003689 /* save the supp_rates of the ap */
3690 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3691 if (sta->ht_cap.ht_supported)
3692 sta_rate_set |=
3693 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003694 sta_ht_cap = sta->ht_cap;
3695 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003696
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003697sta_not_found:
3698 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003700
Arik Nemtsove78a2872010-10-16 19:07:21 +02003701 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003702 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003703 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003704 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003705 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003706 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003707
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003708 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003709 * use basic rates from AP, and determine lowest rate
3710 * to use with control frames.
3711 */
3712 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003713 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003714 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003715 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003716 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003717 wl1271_tx_min_rate_get(wl,
3718 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003719 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003720 wlvif->rate_set =
3721 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003722 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003723 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003724 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003725 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003726 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003727
3728 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003729 * with wl1271, we don't need to update the
3730 * beacon_int and dtim_period, because the firmware
3731 * updates it by itself when the first beacon is
3732 * received after a join.
3733 */
Eliad Peller6840e372011-10-05 11:55:50 +02003734 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003735 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003736 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003737
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003738 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003739 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003740 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003741 dev_kfree_skb(wlvif->probereq);
3742 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003743 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003744 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003745 ieoffset = offsetof(struct ieee80211_mgmt,
3746 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003747 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003748
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003749 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003750 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003751 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003752 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003753 } else {
3754 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003755 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003756 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3757 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003758 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003759 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3760 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003761 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003762
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003763 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003764 dev_kfree_skb(wlvif->probereq);
3765 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003766
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003767 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003768 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003769 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003770 wl1271_tx_min_rate_get(wl,
3771 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003772 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003773 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003774 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003775
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003776 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003777 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003778
3779 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003780 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003781 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003782 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003783
3784 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003785 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003786 u32 conf_flags = wl->hw->conf.flags;
3787 /*
3788 * we might have to disable roc, if there was
3789 * no IF_OPER_UP notification.
3790 */
3791 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003792 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003793 if (ret < 0)
3794 goto out;
3795 }
3796 /*
3797 * (we also need to disable roc in case of
3798 * roaming on the same channel. until we will
3799 * have a better flow...)
3800 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003801 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3802 ret = wl12xx_croc(wl,
3803 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003804 if (ret < 0)
3805 goto out;
3806 }
3807
Eliad Peller0603d892011-10-05 11:55:51 +02003808 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003809 if (!(conf_flags & IEEE80211_CONF_IDLE))
3810 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003811 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003812 }
3813 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003814
Eliad Pellerd192d262011-05-24 14:33:08 +03003815 if (changed & BSS_CHANGED_IBSS) {
3816 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3817 bss_conf->ibss_joined);
3818
3819 if (bss_conf->ibss_joined) {
3820 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003821 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003822 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003823 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003824 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003825 wl1271_tx_min_rate_get(wl,
3826 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003827
Shahar Levi06b660e2011-09-05 13:54:36 +03003828 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003829 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3830 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003831 if (ret < 0)
3832 goto out;
3833 }
3834 }
3835
Eliad Peller0603d892011-10-05 11:55:51 +02003836 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003837 if (ret < 0)
3838 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003839
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003840 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003841 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003842 if (ret < 0) {
3843 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003844 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003845 }
Eliad Peller251c1772011-08-14 13:17:17 +03003846
3847 /* ROC until connected (after EAPOL exchange) */
3848 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003849 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003850 if (ret < 0)
3851 goto out;
3852
Eliad Pellerba8447f2011-10-10 10:13:00 +02003853 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003854 ieee80211_get_operstate(vif));
3855 }
3856 /*
3857 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003858 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003859 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003860 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003861 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003862 if (ret < 0)
3863 goto out;
3864 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003865 }
3866
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003867 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003868 if (sta_exists) {
3869 if ((changed & BSS_CHANGED_HT) &&
3870 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003871 ret = wl1271_acx_set_ht_capabilities(wl,
3872 &sta_ht_cap,
3873 true,
Eliad Peller154da672011-10-05 11:55:53 +02003874 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003875 if (ret < 0) {
3876 wl1271_warning("Set ht cap true failed %d",
3877 ret);
3878 goto out;
3879 }
3880 }
3881 /* handle new association without HT and disassociation */
3882 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003883 ret = wl1271_acx_set_ht_capabilities(wl,
3884 &sta_ht_cap,
3885 false,
Eliad Peller154da672011-10-05 11:55:53 +02003886 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003887 if (ret < 0) {
3888 wl1271_warning("Set ht cap false failed %d",
3889 ret);
3890 goto out;
3891 }
3892 }
3893 }
3894
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003895 /* Handle HT information change. Done after join. */
3896 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003897 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003898 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003899 bss_conf->ht_operation_mode);
3900 if (ret < 0) {
3901 wl1271_warning("Set ht information failed %d", ret);
3902 goto out;
3903 }
3904 }
3905
Eliad Peller76a74c82012-02-02 12:22:11 +02003906 /* Handle arp filtering. Done after join. */
3907 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3908 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
3909 __be32 addr = bss_conf->arp_addr_list[0];
3910 wlvif->sta.qos = bss_conf->qos;
3911 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
3912
3913 if (bss_conf->arp_addr_cnt == 1 &&
3914 bss_conf->arp_filter_enabled) {
3915 wlvif->ip_addr = addr;
3916 /*
3917 * The template should have been configured only upon
3918 * association. however, it seems that the correct ip
3919 * isn't being set (when sending), so we have to
3920 * reconfigure the template upon every ip change.
3921 */
3922 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
3923 if (ret < 0) {
3924 wl1271_warning("build arp rsp failed: %d", ret);
3925 goto out;
3926 }
3927
3928 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
3929 (ACX_ARP_FILTER_ARP_FILTERING |
3930 ACX_ARP_FILTER_AUTO_ARP),
3931 addr);
3932 } else {
3933 wlvif->ip_addr = 0;
3934 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
3935 }
3936
3937 if (ret < 0)
3938 goto out;
3939 }
3940
Arik Nemtsove78a2872010-10-16 19:07:21 +02003941out:
3942 return;
3943}
3944
3945static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3946 struct ieee80211_vif *vif,
3947 struct ieee80211_bss_conf *bss_conf,
3948 u32 changed)
3949{
3950 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003951 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3952 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003953 int ret;
3954
3955 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3956 (int)changed);
3957
3958 mutex_lock(&wl->mutex);
3959
3960 if (unlikely(wl->state == WL1271_STATE_OFF))
3961 goto out;
3962
Eliad Peller10c8cd02011-10-10 10:13:06 +02003963 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3964 goto out;
3965
Ido Yariva6208652011-03-01 15:14:41 +02003966 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003967 if (ret < 0)
3968 goto out;
3969
3970 if (is_ap)
3971 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3972 else
3973 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3974
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003975 wl1271_ps_elp_sleep(wl);
3976
3977out:
3978 mutex_unlock(&wl->mutex);
3979}
3980
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003981static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3982 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003983 const struct ieee80211_tx_queue_params *params)
3984{
3985 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003986 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003987 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003988 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003989
3990 mutex_lock(&wl->mutex);
3991
3992 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3993
Kalle Valo4695dc92010-03-18 12:26:38 +02003994 if (params->uapsd)
3995 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3996 else
3997 ps_scheme = CONF_PS_SCHEME_LEGACY;
3998
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003999 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004000 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004001
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004002 ret = wl1271_ps_elp_wakeup(wl);
4003 if (ret < 0)
4004 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004005
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004006 /*
4007 * the txop is confed in units of 32us by the mac80211,
4008 * we need us
4009 */
Eliad Peller0603d892011-10-05 11:55:51 +02004010 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004011 params->cw_min, params->cw_max,
4012 params->aifs, params->txop << 5);
4013 if (ret < 0)
4014 goto out_sleep;
4015
Eliad Peller0603d892011-10-05 11:55:51 +02004016 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004017 CONF_CHANNEL_TYPE_EDCF,
4018 wl1271_tx_get_queue(queue),
4019 ps_scheme, CONF_ACK_POLICY_LEGACY,
4020 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004021
4022out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004023 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004024
4025out:
4026 mutex_unlock(&wl->mutex);
4027
4028 return ret;
4029}
4030
Eliad Peller37a41b42011-09-21 14:06:11 +03004031static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4032 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004033{
4034
4035 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004036 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004037 u64 mactime = ULLONG_MAX;
4038 int ret;
4039
4040 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4041
4042 mutex_lock(&wl->mutex);
4043
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004044 if (unlikely(wl->state == WL1271_STATE_OFF))
4045 goto out;
4046
Ido Yariva6208652011-03-01 15:14:41 +02004047 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004048 if (ret < 0)
4049 goto out;
4050
Eliad Peller9c531142012-01-31 11:57:18 +02004051 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004052 if (ret < 0)
4053 goto out_sleep;
4054
4055out_sleep:
4056 wl1271_ps_elp_sleep(wl);
4057
4058out:
4059 mutex_unlock(&wl->mutex);
4060 return mactime;
4061}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004062
John W. Linvilleece550d2010-07-28 16:41:06 -04004063static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4064 struct survey_info *survey)
4065{
4066 struct wl1271 *wl = hw->priv;
4067 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004068
John W. Linvilleece550d2010-07-28 16:41:06 -04004069 if (idx != 0)
4070 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004071
John W. Linvilleece550d2010-07-28 16:41:06 -04004072 survey->channel = conf->channel;
4073 survey->filled = SURVEY_INFO_NOISE_DBM;
4074 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004075
John W. Linvilleece550d2010-07-28 16:41:06 -04004076 return 0;
4077}
4078
Arik Nemtsov409622e2011-02-23 00:22:29 +02004079static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004080 struct wl12xx_vif *wlvif,
4081 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004082{
4083 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004084 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004085
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004086
4087 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004088 wl1271_warning("could not allocate HLID - too much stations");
4089 return -EBUSY;
4090 }
4091
4092 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4094 if (ret < 0) {
4095 wl1271_warning("could not allocate HLID - too many links");
4096 return -EBUSY;
4097 }
4098
4099 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004100 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004101 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004102 return 0;
4103}
4104
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004105void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004107 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004108 return;
4109
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004110 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004111 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004112 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004113 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004114 __clear_bit(hlid, &wl->ap_ps_map);
4115 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004116 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004117 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004118}
4119
4120static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4121 struct ieee80211_vif *vif,
4122 struct ieee80211_sta *sta)
4123{
4124 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004125 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004126 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004127 int ret = 0;
4128 u8 hlid;
4129
4130 mutex_lock(&wl->mutex);
4131
4132 if (unlikely(wl->state == WL1271_STATE_OFF))
4133 goto out;
4134
Eliad Peller536129c2011-10-05 11:55:45 +02004135 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004136 goto out;
4137
4138 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4139
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004140 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004141 if (ret < 0)
4142 goto out;
4143
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004144 wl_sta = (struct wl1271_station *)sta->drv_priv;
4145 hlid = wl_sta->hlid;
4146
Ido Yariva6208652011-03-01 15:14:41 +02004147 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004149 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004150
Eliad Peller1b92f152011-10-10 10:13:09 +02004151 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004152 if (ret < 0)
4153 goto out_sleep;
4154
Eliad Pellerb67476e2011-08-14 13:17:23 +03004155 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4156 if (ret < 0)
4157 goto out_sleep;
4158
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004159 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4160 if (ret < 0)
4161 goto out_sleep;
4162
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004163out_sleep:
4164 wl1271_ps_elp_sleep(wl);
4165
Arik Nemtsov409622e2011-02-23 00:22:29 +02004166out_free_sta:
4167 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004168 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004169
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004170out:
4171 mutex_unlock(&wl->mutex);
4172 return ret;
4173}
4174
4175static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4176 struct ieee80211_vif *vif,
4177 struct ieee80211_sta *sta)
4178{
4179 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004180 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004181 struct wl1271_station *wl_sta;
4182 int ret = 0, id;
4183
4184 mutex_lock(&wl->mutex);
4185
4186 if (unlikely(wl->state == WL1271_STATE_OFF))
4187 goto out;
4188
Eliad Peller536129c2011-10-05 11:55:45 +02004189 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004190 goto out;
4191
4192 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4193
4194 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004195 id = wl_sta->hlid;
4196 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004197 goto out;
4198
Ido Yariva6208652011-03-01 15:14:41 +02004199 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004200 if (ret < 0)
4201 goto out;
4202
Eliad Pellerc690ec82011-08-14 13:17:07 +03004203 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004204 if (ret < 0)
4205 goto out_sleep;
4206
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004207 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004208
4209out_sleep:
4210 wl1271_ps_elp_sleep(wl);
4211
4212out:
4213 mutex_unlock(&wl->mutex);
4214 return ret;
4215}
4216
Luciano Coelho4623ec72011-03-21 19:26:41 +02004217static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4218 struct ieee80211_vif *vif,
4219 enum ieee80211_ampdu_mlme_action action,
4220 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4221 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004222{
4223 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004224 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004225 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004226 u8 hlid, *ba_bitmap;
4227
4228 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4229 tid);
4230
4231 /* sanity check - the fields in FW are only 8bits wide */
4232 if (WARN_ON(tid > 0xFF))
4233 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004234
4235 mutex_lock(&wl->mutex);
4236
4237 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4238 ret = -EAGAIN;
4239 goto out;
4240 }
4241
Eliad Peller536129c2011-10-05 11:55:45 +02004242 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004243 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004244 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004245 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004246 struct wl1271_station *wl_sta;
4247
4248 wl_sta = (struct wl1271_station *)sta->drv_priv;
4249 hlid = wl_sta->hlid;
4250 ba_bitmap = &wl->links[hlid].ba_bitmap;
4251 } else {
4252 ret = -EINVAL;
4253 goto out;
4254 }
4255
Ido Yariva6208652011-03-01 15:14:41 +02004256 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004257 if (ret < 0)
4258 goto out;
4259
Shahar Levi70559a02011-05-22 16:10:22 +03004260 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4261 tid, action);
4262
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004263 switch (action) {
4264 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004265 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004266 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004267 break;
4268 }
4269
4270 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4271 ret = -EBUSY;
4272 wl1271_error("exceeded max RX BA sessions");
4273 break;
4274 }
4275
4276 if (*ba_bitmap & BIT(tid)) {
4277 ret = -EINVAL;
4278 wl1271_error("cannot enable RX BA session on active "
4279 "tid: %d", tid);
4280 break;
4281 }
4282
4283 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4284 hlid);
4285 if (!ret) {
4286 *ba_bitmap |= BIT(tid);
4287 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004288 }
4289 break;
4290
4291 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004292 if (!(*ba_bitmap & BIT(tid))) {
4293 ret = -EINVAL;
4294 wl1271_error("no active RX BA session on tid: %d",
4295 tid);
4296 break;
4297 }
4298
4299 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4300 hlid);
4301 if (!ret) {
4302 *ba_bitmap &= ~BIT(tid);
4303 wl->ba_rx_session_count--;
4304 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004305 break;
4306
4307 /*
4308 * The BA initiator session management in FW independently.
4309 * Falling break here on purpose for all TX APDU commands.
4310 */
4311 case IEEE80211_AMPDU_TX_START:
4312 case IEEE80211_AMPDU_TX_STOP:
4313 case IEEE80211_AMPDU_TX_OPERATIONAL:
4314 ret = -EINVAL;
4315 break;
4316
4317 default:
4318 wl1271_error("Incorrect ampdu action id=%x\n", action);
4319 ret = -EINVAL;
4320 }
4321
4322 wl1271_ps_elp_sleep(wl);
4323
4324out:
4325 mutex_unlock(&wl->mutex);
4326
4327 return ret;
4328}
4329
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004330static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4331 struct ieee80211_vif *vif,
4332 const struct cfg80211_bitrate_mask *mask)
4333{
Eliad Peller83587502011-10-10 10:12:53 +02004334 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004335 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004336 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004337
4338 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4339 mask->control[NL80211_BAND_2GHZ].legacy,
4340 mask->control[NL80211_BAND_5GHZ].legacy);
4341
4342 mutex_lock(&wl->mutex);
4343
4344 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004345 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004346 wl1271_tx_enabled_rates_get(wl,
4347 mask->control[i].legacy,
4348 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004349
4350 if (unlikely(wl->state == WL1271_STATE_OFF))
4351 goto out;
4352
4353 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4354 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4355
4356 ret = wl1271_ps_elp_wakeup(wl);
4357 if (ret < 0)
4358 goto out;
4359
4360 wl1271_set_band_rate(wl, wlvif);
4361 wlvif->basic_rate =
4362 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4363 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4364
4365 wl1271_ps_elp_sleep(wl);
4366 }
4367out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004368 mutex_unlock(&wl->mutex);
4369
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004370 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004371}
4372
Shahar Levi6d158ff2011-09-08 13:01:33 +03004373static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4374 struct ieee80211_channel_switch *ch_switch)
4375{
4376 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004377 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004378 int ret;
4379
4380 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4381
4382 mutex_lock(&wl->mutex);
4383
4384 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004385 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4386 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4387 ieee80211_chswitch_done(vif, false);
4388 }
4389 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004390 }
4391
4392 ret = wl1271_ps_elp_wakeup(wl);
4393 if (ret < 0)
4394 goto out;
4395
Eliad Peller52630c52011-10-10 10:13:08 +02004396 /* TODO: change mac80211 to pass vif as param */
4397 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004398 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004399
Eliad Peller52630c52011-10-10 10:13:08 +02004400 if (!ret)
4401 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4402 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004403
4404 wl1271_ps_elp_sleep(wl);
4405
4406out:
4407 mutex_unlock(&wl->mutex);
4408}
4409
Arik Nemtsov33437892011-04-26 23:35:39 +03004410static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4411{
4412 struct wl1271 *wl = hw->priv;
4413 bool ret = false;
4414
4415 mutex_lock(&wl->mutex);
4416
4417 if (unlikely(wl->state == WL1271_STATE_OFF))
4418 goto out;
4419
4420 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004421 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004422out:
4423 mutex_unlock(&wl->mutex);
4424
4425 return ret;
4426}
4427
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004428/* can't be const, mac80211 writes to this */
4429static struct ieee80211_rate wl1271_rates[] = {
4430 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004431 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4432 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004433 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004434 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4435 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004436 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4437 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004438 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4439 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004440 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4441 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4445 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004446 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4447 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004448 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004449 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4450 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004451 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004452 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4453 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004454 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004455 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4456 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004458 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4459 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004460 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004461 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4462 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004463 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004464 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4465 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004466 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004467 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4468 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004469};
4470
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004471/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004472static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004473 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004474 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004475 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4476 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4477 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004478 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004479 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4480 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4481 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004482 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004483 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4484 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4485 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004486 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004487};
4488
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004489/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004490static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004491 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004492 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004493 7, /* CONF_HW_RXTX_RATE_MCS7 */
4494 6, /* CONF_HW_RXTX_RATE_MCS6 */
4495 5, /* CONF_HW_RXTX_RATE_MCS5 */
4496 4, /* CONF_HW_RXTX_RATE_MCS4 */
4497 3, /* CONF_HW_RXTX_RATE_MCS3 */
4498 2, /* CONF_HW_RXTX_RATE_MCS2 */
4499 1, /* CONF_HW_RXTX_RATE_MCS1 */
4500 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004501
4502 11, /* CONF_HW_RXTX_RATE_54 */
4503 10, /* CONF_HW_RXTX_RATE_48 */
4504 9, /* CONF_HW_RXTX_RATE_36 */
4505 8, /* CONF_HW_RXTX_RATE_24 */
4506
4507 /* TI-specific rate */
4508 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4509
4510 7, /* CONF_HW_RXTX_RATE_18 */
4511 6, /* CONF_HW_RXTX_RATE_12 */
4512 3, /* CONF_HW_RXTX_RATE_11 */
4513 5, /* CONF_HW_RXTX_RATE_9 */
4514 4, /* CONF_HW_RXTX_RATE_6 */
4515 2, /* CONF_HW_RXTX_RATE_5_5 */
4516 1, /* CONF_HW_RXTX_RATE_2 */
4517 0 /* CONF_HW_RXTX_RATE_1 */
4518};
4519
Shahar Levie8b03a22010-10-13 16:09:39 +02004520/* 11n STA capabilities */
4521#define HW_RX_HIGHEST_RATE 72
4522
Shahar Levi00d20102010-11-08 11:20:10 +00004523#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004524 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4525 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004526 .ht_supported = true, \
4527 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4528 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4529 .mcs = { \
4530 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4531 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4532 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4533 }, \
4534}
4535
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004536/* can't be const, mac80211 writes to this */
4537static struct ieee80211_supported_band wl1271_band_2ghz = {
4538 .channels = wl1271_channels,
4539 .n_channels = ARRAY_SIZE(wl1271_channels),
4540 .bitrates = wl1271_rates,
4541 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004542 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004543};
4544
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004545/* 5 GHz data rates for WL1273 */
4546static struct ieee80211_rate wl1271_rates_5ghz[] = {
4547 { .bitrate = 60,
4548 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4549 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4550 { .bitrate = 90,
4551 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4552 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4553 { .bitrate = 120,
4554 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4555 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4556 { .bitrate = 180,
4557 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4558 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4559 { .bitrate = 240,
4560 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4562 { .bitrate = 360,
4563 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4565 { .bitrate = 480,
4566 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4568 { .bitrate = 540,
4569 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4570 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4571};
4572
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004573/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004574static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004575 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4576 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4577 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4578 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4579 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4580 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4581 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4582 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4583 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4584 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4585 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4586 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4587 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4588 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4589 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4590 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4591 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4592 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4593 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4594 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4595 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4596 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4597 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4598 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4599 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4600 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4601 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4602 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4603 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4604 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4605 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4606 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4607 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4608 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004609};
4610
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004611/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004612static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004613 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004614 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004615 7, /* CONF_HW_RXTX_RATE_MCS7 */
4616 6, /* CONF_HW_RXTX_RATE_MCS6 */
4617 5, /* CONF_HW_RXTX_RATE_MCS5 */
4618 4, /* CONF_HW_RXTX_RATE_MCS4 */
4619 3, /* CONF_HW_RXTX_RATE_MCS3 */
4620 2, /* CONF_HW_RXTX_RATE_MCS2 */
4621 1, /* CONF_HW_RXTX_RATE_MCS1 */
4622 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004623
4624 7, /* CONF_HW_RXTX_RATE_54 */
4625 6, /* CONF_HW_RXTX_RATE_48 */
4626 5, /* CONF_HW_RXTX_RATE_36 */
4627 4, /* CONF_HW_RXTX_RATE_24 */
4628
4629 /* TI-specific rate */
4630 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4631
4632 3, /* CONF_HW_RXTX_RATE_18 */
4633 2, /* CONF_HW_RXTX_RATE_12 */
4634 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4635 1, /* CONF_HW_RXTX_RATE_9 */
4636 0, /* CONF_HW_RXTX_RATE_6 */
4637 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4638 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4639 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4640};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004641
4642static struct ieee80211_supported_band wl1271_band_5ghz = {
4643 .channels = wl1271_channels_5ghz,
4644 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4645 .bitrates = wl1271_rates_5ghz,
4646 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004647 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004648};
4649
Tobias Klausera0ea9492010-05-20 10:38:11 +02004650static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004651 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4652 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4653};
4654
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004655static const struct ieee80211_ops wl1271_ops = {
4656 .start = wl1271_op_start,
4657 .stop = wl1271_op_stop,
4658 .add_interface = wl1271_op_add_interface,
4659 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004660 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004661#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004662 .suspend = wl1271_op_suspend,
4663 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004664#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004665 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004666 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004667 .configure_filter = wl1271_op_configure_filter,
4668 .tx = wl1271_op_tx,
4669 .set_key = wl1271_op_set_key,
4670 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004671 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004672 .sched_scan_start = wl1271_op_sched_scan_start,
4673 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004674 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004675 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004676 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004677 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004678 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004679 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004680 .sta_add = wl1271_op_sta_add,
4681 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004682 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004683 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004684 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004685 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004686 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004687};
4688
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004689
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004690u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004691{
4692 u8 idx;
4693
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004694 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004695
4696 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4697 wl1271_error("Illegal RX rate from HW: %d", rate);
4698 return 0;
4699 }
4700
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004701 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004702 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4703 wl1271_error("Unsupported RX rate from HW: %d", rate);
4704 return 0;
4705 }
4706
4707 return idx;
4708}
4709
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004710static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4711 struct device_attribute *attr,
4712 char *buf)
4713{
4714 struct wl1271 *wl = dev_get_drvdata(dev);
4715 ssize_t len;
4716
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004717 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004718
4719 mutex_lock(&wl->mutex);
4720 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4721 wl->sg_enabled);
4722 mutex_unlock(&wl->mutex);
4723
4724 return len;
4725
4726}
4727
4728static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4729 struct device_attribute *attr,
4730 const char *buf, size_t count)
4731{
4732 struct wl1271 *wl = dev_get_drvdata(dev);
4733 unsigned long res;
4734 int ret;
4735
Luciano Coelho6277ed62011-04-01 17:49:54 +03004736 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004737 if (ret < 0) {
4738 wl1271_warning("incorrect value written to bt_coex_mode");
4739 return count;
4740 }
4741
4742 mutex_lock(&wl->mutex);
4743
4744 res = !!res;
4745
4746 if (res == wl->sg_enabled)
4747 goto out;
4748
4749 wl->sg_enabled = res;
4750
4751 if (wl->state == WL1271_STATE_OFF)
4752 goto out;
4753
Ido Yariva6208652011-03-01 15:14:41 +02004754 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004755 if (ret < 0)
4756 goto out;
4757
4758 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4759 wl1271_ps_elp_sleep(wl);
4760
4761 out:
4762 mutex_unlock(&wl->mutex);
4763 return count;
4764}
4765
4766static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4767 wl1271_sysfs_show_bt_coex_state,
4768 wl1271_sysfs_store_bt_coex_state);
4769
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004770static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4771 struct device_attribute *attr,
4772 char *buf)
4773{
4774 struct wl1271 *wl = dev_get_drvdata(dev);
4775 ssize_t len;
4776
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004777 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004778
4779 mutex_lock(&wl->mutex);
4780 if (wl->hw_pg_ver >= 0)
4781 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4782 else
4783 len = snprintf(buf, len, "n/a\n");
4784 mutex_unlock(&wl->mutex);
4785
4786 return len;
4787}
4788
Gery Kahn6f07b722011-07-18 14:21:49 +03004789static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004790 wl1271_sysfs_show_hw_pg_ver, NULL);
4791
Ido Yariv95dac04f2011-06-06 14:57:06 +03004792static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4793 struct bin_attribute *bin_attr,
4794 char *buffer, loff_t pos, size_t count)
4795{
4796 struct device *dev = container_of(kobj, struct device, kobj);
4797 struct wl1271 *wl = dev_get_drvdata(dev);
4798 ssize_t len;
4799 int ret;
4800
4801 ret = mutex_lock_interruptible(&wl->mutex);
4802 if (ret < 0)
4803 return -ERESTARTSYS;
4804
4805 /* Let only one thread read the log at a time, blocking others */
4806 while (wl->fwlog_size == 0) {
4807 DEFINE_WAIT(wait);
4808
4809 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4810 &wait,
4811 TASK_INTERRUPTIBLE);
4812
4813 if (wl->fwlog_size != 0) {
4814 finish_wait(&wl->fwlog_waitq, &wait);
4815 break;
4816 }
4817
4818 mutex_unlock(&wl->mutex);
4819
4820 schedule();
4821 finish_wait(&wl->fwlog_waitq, &wait);
4822
4823 if (signal_pending(current))
4824 return -ERESTARTSYS;
4825
4826 ret = mutex_lock_interruptible(&wl->mutex);
4827 if (ret < 0)
4828 return -ERESTARTSYS;
4829 }
4830
4831 /* Check if the fwlog is still valid */
4832 if (wl->fwlog_size < 0) {
4833 mutex_unlock(&wl->mutex);
4834 return 0;
4835 }
4836
4837 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4838 len = min(count, (size_t)wl->fwlog_size);
4839 wl->fwlog_size -= len;
4840 memcpy(buffer, wl->fwlog, len);
4841
4842 /* Make room for new messages */
4843 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4844
4845 mutex_unlock(&wl->mutex);
4846
4847 return len;
4848}
4849
4850static struct bin_attribute fwlog_attr = {
4851 .attr = {.name = "fwlog", .mode = S_IRUSR},
4852 .read = wl1271_sysfs_read_fwlog,
4853};
4854
Luciano Coelho5e037e72011-12-23 09:32:17 +02004855static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4856{
4857 bool supported = false;
4858 u8 major, minor;
4859
4860 if (wl->chip.id == CHIP_ID_1283_PG20) {
4861 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4862 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4863
4864 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4865 if (major > 2 || (major == 2 && minor >= 1))
4866 supported = true;
4867 } else {
4868 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4869 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4870
4871 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4872 if (major == 3 && minor >= 1)
4873 supported = true;
4874 }
4875
4876 wl1271_debug(DEBUG_PROBE,
4877 "PG Ver major = %d minor = %d, MAC %s present",
4878 major, minor, supported ? "is" : "is not");
4879
4880 return supported;
4881}
4882
4883static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4884 u32 oui, u32 nic, int n)
4885{
4886 int i;
4887
4888 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4889 oui, nic, n);
4890
4891 if (nic + n - 1 > 0xffffff)
4892 wl1271_warning("NIC part of the MAC address wraps around!");
4893
4894 for (i = 0; i < n; i++) {
4895 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4896 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4897 wl->addresses[i].addr[2] = (u8) oui;
4898 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4899 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4900 wl->addresses[i].addr[5] = (u8) nic;
4901 nic++;
4902 }
4903
4904 wl->hw->wiphy->n_addresses = n;
4905 wl->hw->wiphy->addresses = wl->addresses;
4906}
4907
4908static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4909{
4910 u32 mac1, mac2;
4911
4912 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4913
4914 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4915 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4916
4917 /* these are the two parts of the BD_ADDR */
4918 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4919 ((mac1 & 0xff000000) >> 24);
4920 wl->fuse_nic_addr = mac1 & 0xffffff;
4921
4922 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4923}
4924
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004925static int wl12xx_get_hw_info(struct wl1271 *wl)
4926{
4927 int ret;
4928 u32 die_info;
4929
4930 ret = wl12xx_set_power_on(wl);
4931 if (ret < 0)
4932 goto out;
4933
4934 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4935
4936 if (wl->chip.id == CHIP_ID_1283_PG20)
4937 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4938 else
4939 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4940
4941 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4942
Luciano Coelho5e037e72011-12-23 09:32:17 +02004943 if (!wl12xx_mac_in_fuse(wl)) {
4944 wl->fuse_oui_addr = 0;
4945 wl->fuse_nic_addr = 0;
4946 } else {
4947 wl12xx_get_fuse_mac(wl);
4948 }
4949
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004950 wl1271_power_off(wl);
4951out:
4952 return ret;
4953}
4954
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004955static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004956{
4957 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004958 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004959
4960 if (wl->mac80211_registered)
4961 return 0;
4962
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004963 ret = wl12xx_get_hw_info(wl);
4964 if (ret < 0) {
4965 wl1271_error("couldn't get hw info");
4966 goto out;
4967 }
4968
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004969 ret = wl1271_fetch_nvs(wl);
4970 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004971 /* NOTE: The wl->nvs->nvs element must be first, in
4972 * order to simplify the casting, we assume it is at
4973 * the beginning of the wl->nvs structure.
4974 */
4975 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004976
Luciano Coelho5e037e72011-12-23 09:32:17 +02004977 oui_addr =
4978 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4979 nic_addr =
4980 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004981 }
4982
Luciano Coelho5e037e72011-12-23 09:32:17 +02004983 /* if the MAC address is zeroed in the NVS derive from fuse */
4984 if (oui_addr == 0 && nic_addr == 0) {
4985 oui_addr = wl->fuse_oui_addr;
4986 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4987 nic_addr = wl->fuse_nic_addr + 1;
4988 }
4989
4990 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004991
4992 ret = ieee80211_register_hw(wl->hw);
4993 if (ret < 0) {
4994 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004995 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004996 }
4997
4998 wl->mac80211_registered = true;
4999
Eliad Pellerd60080a2010-11-24 12:53:16 +02005000 wl1271_debugfs_init(wl);
5001
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005002 register_netdevice_notifier(&wl1271_dev_notifier);
5003
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004 wl1271_notice("loaded");
5005
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005006out:
5007 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005008}
5009
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005010static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005011{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005012 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02005013 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005014
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005015 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005016 ieee80211_unregister_hw(wl->hw);
5017 wl->mac80211_registered = false;
5018
5019}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005020
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005021static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005022{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005023 static const u32 cipher_suites[] = {
5024 WLAN_CIPHER_SUITE_WEP40,
5025 WLAN_CIPHER_SUITE_WEP104,
5026 WLAN_CIPHER_SUITE_TKIP,
5027 WLAN_CIPHER_SUITE_CCMP,
5028 WL1271_CIPHER_SUITE_GEM,
5029 };
5030
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005031 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02005032 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005033 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005034
5035 /* unit us */
5036 /* FIXME: find a proper value */
5037 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005038 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005039
5040 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005041 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005042 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005043 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005044 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005045 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005046 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005047 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005048 IEEE80211_HW_AP_LINK_PS |
5049 IEEE80211_HW_AMPDU_AGGREGATION |
Eliad Peller79aba1b2012-02-02 13:15:35 +02005050 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
5051 IEEE80211_HW_SCAN_WHILE_IDLE;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005052
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005053 wl->hw->wiphy->cipher_suites = cipher_suites;
5054 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5055
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005056 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005057 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5058 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005059 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005060 wl->hw->wiphy->max_sched_scan_ssids = 16;
5061 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005062 /*
5063 * Maximum length of elements in scanning probe request templates
5064 * should be the maximum length possible for a template, without
5065 * the IEEE80211 header of the template
5066 */
Ido Reisc08e3712012-02-02 13:54:27 +02005067 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005068 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005069
Ido Reisc08e3712012-02-02 13:54:27 +02005070 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005071 sizeof(struct ieee80211_header);
5072
Eliad Peller1ec23f72011-08-25 14:26:54 +03005073 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5074
Luciano Coelho4a31c112011-03-21 23:16:14 +02005075 /* make sure all our channels fit in the scanned_ch bitmask */
5076 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5077 ARRAY_SIZE(wl1271_channels_5ghz) >
5078 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005079 /*
5080 * We keep local copies of the band structs because we need to
5081 * modify them on a per-device basis.
5082 */
5083 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5084 sizeof(wl1271_band_2ghz));
5085 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5086 sizeof(wl1271_band_5ghz));
5087
5088 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5089 &wl->bands[IEEE80211_BAND_2GHZ];
5090 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5091 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005092
Kalle Valo12bd8942010-03-18 12:26:33 +02005093 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005094 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005095
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005096 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5097
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005098 /* the FW answers probe-requests in AP-mode */
5099 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5100 wl->hw->wiphy->probe_resp_offload =
5101 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5102 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5103 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5104
Felipe Balbia390e852011-10-06 10:07:44 +03005105 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005106
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005107 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005108 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005109
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005110 wl->hw->max_rx_aggregation_subframes = 8;
5111
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005112 return 0;
5113}
5114
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005115#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005116
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005117static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005118{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005119 struct ieee80211_hw *hw;
5120 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005121 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005122 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005123
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005124 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005125
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005126 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5127 if (!hw) {
5128 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005129 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005130 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005131 }
5132
5133 wl = hw->priv;
5134 memset(wl, 0, sizeof(*wl));
5135
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005136 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005137 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005138
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005139 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005140
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005141 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005142 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005143 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5144
Ido Yariva6208652011-03-01 15:14:41 +02005145 skb_queue_head_init(&wl->deferred_rx_queue);
5146 skb_queue_head_init(&wl->deferred_tx_queue);
5147
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005148 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005149 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005150 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5151 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5152 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005153
Eliad Peller92ef8962011-06-07 12:50:46 +03005154 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5155 if (!wl->freezable_wq) {
5156 ret = -ENOMEM;
5157 goto err_hw;
5158 }
5159
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005160 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005161 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005162 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005163 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005164 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005165 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005166 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005167 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005168 wl->ap_ps_map = 0;
5169 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005170 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005171 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005172 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005173 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005174 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005175 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005176 wl->fwlog_size = 0;
5177 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005178
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005179 /* The system link is always allocated */
5180 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5181
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005182 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005183 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005184 wl->tx_frames[i] = NULL;
5185
5186 spin_lock_init(&wl->wl_lock);
5187
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005188 wl->state = WL1271_STATE_OFF;
5189 mutex_init(&wl->mutex);
5190
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005191 /* Apply default driver configuration. */
5192 wl1271_conf_init(wl);
5193
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005194 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5195 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5196 if (!wl->aggr_buf) {
5197 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005198 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005199 }
5200
Ido Yariv990f5de2011-03-31 10:06:59 +02005201 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5202 if (!wl->dummy_packet) {
5203 ret = -ENOMEM;
5204 goto err_aggr;
5205 }
5206
Ido Yariv95dac04f2011-06-06 14:57:06 +03005207 /* Allocate one page for the FW log */
5208 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5209 if (!wl->fwlog) {
5210 ret = -ENOMEM;
5211 goto err_dummy_packet;
5212 }
5213
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005214 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005215
Ido Yariv990f5de2011-03-31 10:06:59 +02005216err_dummy_packet:
5217 dev_kfree_skb(wl->dummy_packet);
5218
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005219err_aggr:
5220 free_pages((unsigned long)wl->aggr_buf, order);
5221
Eliad Peller92ef8962011-06-07 12:50:46 +03005222err_wq:
5223 destroy_workqueue(wl->freezable_wq);
5224
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005225err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005226 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005227 ieee80211_free_hw(hw);
5228
5229err_hw_alloc:
5230
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005231 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005232}
5233
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005234static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005235{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005236 /* Unblock any fwlog readers */
5237 mutex_lock(&wl->mutex);
5238 wl->fwlog_size = -1;
5239 wake_up_interruptible_all(&wl->fwlog_waitq);
5240 mutex_unlock(&wl->mutex);
5241
Felipe Balbif79f8902011-10-06 13:05:25 +03005242 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005243
Felipe Balbif79f8902011-10-06 13:05:25 +03005244 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005245
Felipe Balbif79f8902011-10-06 13:05:25 +03005246 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005247 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005248 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005249 free_pages((unsigned long)wl->aggr_buf,
5250 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005251
5252 wl1271_debugfs_exit(wl);
5253
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005254 vfree(wl->fw);
5255 wl->fw = NULL;
5256 kfree(wl->nvs);
5257 wl->nvs = NULL;
5258
5259 kfree(wl->fw_status);
5260 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005261 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005262
5263 ieee80211_free_hw(wl->hw);
5264
5265 return 0;
5266}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005267
Felipe Balbia390e852011-10-06 10:07:44 +03005268static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5269{
5270 struct wl1271 *wl = cookie;
5271 unsigned long flags;
5272
5273 wl1271_debug(DEBUG_IRQ, "IRQ");
5274
5275 /* complete the ELP completion */
5276 spin_lock_irqsave(&wl->wl_lock, flags);
5277 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5278 if (wl->elp_compl) {
5279 complete(wl->elp_compl);
5280 wl->elp_compl = NULL;
5281 }
5282
5283 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5284 /* don't enqueue a work right now. mark it as pending */
5285 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5286 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5287 disable_irq_nosync(wl->irq);
5288 pm_wakeup_event(wl->dev, 0);
5289 spin_unlock_irqrestore(&wl->wl_lock, flags);
5290 return IRQ_HANDLED;
5291 }
5292 spin_unlock_irqrestore(&wl->wl_lock, flags);
5293
5294 return IRQ_WAKE_THREAD;
5295}
5296
Felipe Balbice2a2172011-10-05 14:12:55 +03005297static int __devinit wl12xx_probe(struct platform_device *pdev)
5298{
Felipe Balbia390e852011-10-06 10:07:44 +03005299 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5300 struct ieee80211_hw *hw;
5301 struct wl1271 *wl;
5302 unsigned long irqflags;
5303 int ret = -ENODEV;
5304
5305 hw = wl1271_alloc_hw();
5306 if (IS_ERR(hw)) {
5307 wl1271_error("can't allocate hw");
5308 ret = PTR_ERR(hw);
5309 goto out;
5310 }
5311
5312 wl = hw->priv;
5313 wl->irq = platform_get_irq(pdev, 0);
5314 wl->ref_clock = pdata->board_ref_clock;
5315 wl->tcxo_clock = pdata->board_tcxo_clock;
5316 wl->platform_quirks = pdata->platform_quirks;
5317 wl->set_power = pdata->set_power;
5318 wl->dev = &pdev->dev;
5319 wl->if_ops = pdata->ops;
5320
5321 platform_set_drvdata(pdev, wl);
5322
5323 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5324 irqflags = IRQF_TRIGGER_RISING;
5325 else
5326 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5327
5328 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5329 irqflags,
5330 pdev->name, wl);
5331 if (ret < 0) {
5332 wl1271_error("request_irq() failed: %d", ret);
5333 goto out_free_hw;
5334 }
5335
5336 ret = enable_irq_wake(wl->irq);
5337 if (!ret) {
5338 wl->irq_wake_enabled = true;
5339 device_init_wakeup(wl->dev, 1);
5340 if (pdata->pwr_in_suspend)
5341 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5342
5343 }
5344 disable_irq(wl->irq);
5345
5346 ret = wl1271_init_ieee80211(wl);
5347 if (ret)
5348 goto out_irq;
5349
5350 ret = wl1271_register_hw(wl);
5351 if (ret)
5352 goto out_irq;
5353
Felipe Balbif79f8902011-10-06 13:05:25 +03005354 /* Create sysfs file to control bt coex state */
5355 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5356 if (ret < 0) {
5357 wl1271_error("failed to create sysfs file bt_coex_state");
5358 goto out_irq;
5359 }
5360
5361 /* Create sysfs file to get HW PG version */
5362 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5363 if (ret < 0) {
5364 wl1271_error("failed to create sysfs file hw_pg_ver");
5365 goto out_bt_coex_state;
5366 }
5367
5368 /* Create sysfs file for the FW log */
5369 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5370 if (ret < 0) {
5371 wl1271_error("failed to create sysfs file fwlog");
5372 goto out_hw_pg_ver;
5373 }
5374
Felipe Balbice2a2172011-10-05 14:12:55 +03005375 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005376
Felipe Balbif79f8902011-10-06 13:05:25 +03005377out_hw_pg_ver:
5378 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5379
5380out_bt_coex_state:
5381 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5382
Felipe Balbia390e852011-10-06 10:07:44 +03005383out_irq:
5384 free_irq(wl->irq, wl);
5385
5386out_free_hw:
5387 wl1271_free_hw(wl);
5388
5389out:
5390 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005391}
5392
5393static int __devexit wl12xx_remove(struct platform_device *pdev)
5394{
Felipe Balbia390e852011-10-06 10:07:44 +03005395 struct wl1271 *wl = platform_get_drvdata(pdev);
5396
5397 if (wl->irq_wake_enabled) {
5398 device_init_wakeup(wl->dev, 0);
5399 disable_irq_wake(wl->irq);
5400 }
5401 wl1271_unregister_hw(wl);
5402 free_irq(wl->irq, wl);
5403 wl1271_free_hw(wl);
5404
Felipe Balbice2a2172011-10-05 14:12:55 +03005405 return 0;
5406}
5407
5408static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005409 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005410 { } /* Terminating Entry */
5411};
5412MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5413
5414static struct platform_driver wl12xx_driver = {
5415 .probe = wl12xx_probe,
5416 .remove = __devexit_p(wl12xx_remove),
5417 .id_table = wl12xx_id_table,
5418 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005419 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005420 .owner = THIS_MODULE,
5421 }
5422};
5423
5424static int __init wl12xx_init(void)
5425{
5426 return platform_driver_register(&wl12xx_driver);
5427}
5428module_init(wl12xx_init);
5429
5430static void __exit wl12xx_exit(void)
5431{
5432 platform_driver_unregister(&wl12xx_driver);
5433}
5434module_exit(wl12xx_exit);
5435
Guy Eilam491bbd62011-01-12 10:33:29 +01005436u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005437EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005438module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005439MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5440
Ido Yariv95dac04f2011-06-06 14:57:06 +03005441module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005442MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005443 "FW logger options: continuous, ondemand, dbgpins or disable");
5444
Eliad Peller2a5bff02011-08-25 18:10:59 +03005445module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5446MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5447
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005448MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005449MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005450MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");