blob: a84fe28873eabbab8f828ebaab6b7abc558d3db5 [file] [log] [blame]
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02001
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002/*
3 * This file is part of wl1271
4 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02005 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03006 *
7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030026#include <linux/firmware.h>
27#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030028#include <linux/spi/spi.h>
29#include <linux/crc32.h>
30#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030031#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020032#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020034#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030035#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030036#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030037
Shahar Levi00d20102010-11-08 11:20:10 +000038#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030039#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030040#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000041#include "reg.h"
42#include "io.h"
43#include "event.h"
44#include "tx.h"
45#include "rx.h"
46#include "ps.h"
47#include "init.h"
48#include "debugfs.h"
49#include "cmd.h"
50#include "boot.h"
51#include "testmode.h"
52#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030053
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020054#define WL1271_BOOT_RETRIES 3
55
Juuso Oikarinen8a080482009-10-13 12:47:44 +030056static struct conf_drv_settings default_conf = {
57 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030058 .params = {
59 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
60 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
61 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
62 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
63 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
64 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
65 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
66 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
67 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
69 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
70 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
72 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
74 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
76 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
78 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
80 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
81 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
82 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
83 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
84 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
85 /* active scan params */
86 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
88 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
89 /* passive scan params */
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
92 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
93 /* passive scan in dual antenna params */
94 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
96 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
97 /* general params */
98 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
99 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
100 [CONF_SG_BEACON_MISS_PERCENT] = 60,
101 [CONF_SG_DHCP_TIME] = 5000,
102 [CONF_SG_RXT] = 1200,
103 [CONF_SG_TXT] = 1000,
104 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
105 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
106 [CONF_SG_HV3_MAX_SERVED] = 6,
107 [CONF_SG_PS_POLL_TIMEOUT] = 10,
108 [CONF_SG_UPSD_TIMEOUT] = 10,
109 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
110 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
111 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
112 /* AP params */
113 [CONF_AP_BEACON_MISS_TX] = 3,
114 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
115 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
116 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
117 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
118 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Eliad Peller26612c42012-01-31 17:54:43 +0200119 /* CTS Diluting params */
120 [CONF_SG_CTS_DILUTED_BAD_RX_PACKETS_TH] = 0,
121 [CONF_SG_CTS_CHOP_IN_DUAL_ANT_SCO_MASTER] = 0,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300122 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200123 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300124 },
125 .rx = {
126 .rx_msdu_life_time = 512000,
127 .packet_detection_threshold = 0,
128 .ps_poll_timeout = 15,
129 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300130 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200131 .rx_cca_threshold = 0,
132 .irq_blk_threshold = 0xFFFF,
133 .irq_pkt_threshold = 0,
134 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300135 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
136 },
137 .tx = {
138 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300140 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300141 .short_retry_limit = 10,
142 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200143 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 },
145 .ac_conf_count = 4,
146 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200147 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300148 .ac = CONF_TX_AC_BE,
149 .cw_min = 15,
150 .cw_max = 63,
151 .aifsn = 3,
152 .tx_op_limit = 0,
153 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200154 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300155 .ac = CONF_TX_AC_BK,
156 .cw_min = 15,
157 .cw_max = 63,
158 .aifsn = 7,
159 .tx_op_limit = 0,
160 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200161 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300162 .ac = CONF_TX_AC_VI,
163 .cw_min = 15,
164 .cw_max = 63,
165 .aifsn = CONF_TX_AIFS_PIFS,
166 .tx_op_limit = 3008,
167 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200168 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300169 .ac = CONF_TX_AC_VO,
170 .cw_min = 15,
171 .cw_max = 63,
172 .aifsn = CONF_TX_AIFS_PIFS,
173 .tx_op_limit = 1504,
174 },
175 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300176 .max_tx_retries = 100,
177 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200178 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200180 [CONF_TX_AC_BE] = {
181 .queue_id = CONF_TX_AC_BE,
182 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300183 .tsid = CONF_TX_AC_BE,
184 .ps_scheme = CONF_PS_SCHEME_LEGACY,
185 .ack_policy = CONF_ACK_POLICY_LEGACY,
186 .apsd_conf = {0, 0},
187 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200188 [CONF_TX_AC_BK] = {
189 .queue_id = CONF_TX_AC_BK,
190 .channel_type = CONF_CHANNEL_TYPE_EDCF,
191 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300192 .ps_scheme = CONF_PS_SCHEME_LEGACY,
193 .ack_policy = CONF_ACK_POLICY_LEGACY,
194 .apsd_conf = {0, 0},
195 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200196 [CONF_TX_AC_VI] = {
197 .queue_id = CONF_TX_AC_VI,
198 .channel_type = CONF_CHANNEL_TYPE_EDCF,
199 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300200 .ps_scheme = CONF_PS_SCHEME_LEGACY,
201 .ack_policy = CONF_ACK_POLICY_LEGACY,
202 .apsd_conf = {0, 0},
203 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200204 [CONF_TX_AC_VO] = {
205 .queue_id = CONF_TX_AC_VO,
206 .channel_type = CONF_CHANNEL_TYPE_EDCF,
207 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 .ps_scheme = CONF_PS_SCHEME_LEGACY,
209 .ack_policy = CONF_ACK_POLICY_LEGACY,
210 .apsd_conf = {0, 0},
211 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300212 },
213 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200214 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300215 .tx_compl_threshold = 4,
216 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
217 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200218 .tmpl_short_retry_limit = 10,
219 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 },
221 .conn = {
222 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300223 .listen_interval = 1,
Eyal Shapiradae728f2012-02-02 12:03:39 +0200224 .suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM,
225 .suspend_listen_interval = 3,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300226 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300227 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300228 .bcn_filt_ie = {
229 [0] = {
230 .ie = WLAN_EID_CHANNEL_SWITCH,
231 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300232 },
233 [1] = {
234 .ie = WLAN_EID_HT_INFORMATION,
235 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
236 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300237 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200238 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300239 .bss_lose_timeout = 100,
240 .beacon_rx_timeout = 10000,
241 .broadcast_timeout = 20000,
242 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300243 .ps_poll_threshold = 10,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300244 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e2011-03-14 18:53:10 +0200245 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300246 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300247 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200248 .psm_entry_nullfunc_retries = 3,
Eyal Shapiraf1d63a52012-01-31 11:57:21 +0200249 .dynamic_ps_timeout = 100,
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +0200250 .forced_ps = false,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300251 .keep_alive_interval = 55000,
252 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300253 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200254 .itrim = {
255 .enable = false,
256 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200257 },
258 .pm_config = {
259 .host_clk_settling_time = 5000,
260 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300261 },
262 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300263 .trigger_pacing = 1,
264 .avg_weight_rssi_beacon = 20,
265 .avg_weight_rssi_data = 10,
266 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100267 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200268 },
269 .scan = {
270 .min_dwell_time_active = 7500,
271 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100272 .min_dwell_time_passive = 100000,
273 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200274 .num_probe_reqs = 2,
275 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300276 .sched_scan = {
277 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300278 .min_dwell_time_active = 30,
279 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300280 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300281 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300282 .num_probe_reqs = 2,
283 .rssi_threshold = -90,
284 .snr_threshold = 0,
285 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200286 .rf = {
287 .tx_per_channel_power_compensation_2 = {
288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 },
290 .tx_per_channel_power_compensation_5 = {
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 },
295 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100296 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300297 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100298 .tx_ba_win_size = 64,
299 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300300 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100301 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200302 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200303 .num_stations = 1,
304 .ssid_profiles = 1,
305 .rx_block_num = 70,
306 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300307 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200308 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200309 .min_req_rx_blocks = 22,
310 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200311 },
312 .mem_wl128x = {
313 .num_stations = 1,
314 .ssid_profiles = 1,
315 .rx_block_num = 40,
316 .tx_min_block_num = 40,
317 .dynamic_memory = 1,
318 .min_req_tx_blocks = 45,
319 .min_req_rx_blocks = 22,
320 .tx_min = 27,
321 },
Shahar Leviff868432011-04-11 15:41:46 +0300322 .fm_coex = {
323 .enable = true,
324 .swallow_period = 5,
325 .n_divider_fref_set_1 = 0xff, /* default */
326 .n_divider_fref_set_2 = 12,
327 .m_divider_fref_set_1 = 148,
328 .m_divider_fref_set_2 = 0xffff, /* default */
329 .coex_pll_stabilization_time = 0xffffffff, /* default */
330 .ldo_stabilization_time = 0xffff, /* default */
331 .fm_disturbed_band_margin = 0xff, /* default */
332 .swallow_clk_diff = 0xff, /* default */
333 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300334 .rx_streaming = {
335 .duration = 150,
336 .queues = 0x1,
337 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300338 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300339 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300340 .fwlog = {
341 .mode = WL12XX_FWLOG_ON_DEMAND,
342 .mem_blocks = 2,
343 .severity = 0,
344 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
345 .output = WL12XX_FWLOG_OUTPUT_HOST,
346 .threshold = 0,
347 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300348 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300349 .rate = {
350 .rate_retry_score = 32000,
351 .per_add = 8192,
352 .per_th1 = 2048,
353 .per_th2 = 4096,
354 .max_per = 8100,
355 .inverse_curiosity_factor = 5,
356 .tx_fail_low_th = 4,
357 .tx_fail_high_th = 10,
358 .per_alpha_shift = 4,
359 .per_add_shift = 13,
360 .per_beta1_shift = 10,
361 .per_beta2_shift = 8,
362 .rate_check_up = 2,
363 .rate_check_down = 12,
364 .rate_retry_policy = {
365 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00,
368 },
369 },
Eliad Peller94877752011-08-28 15:11:56 +0300370 .hangover = {
371 .recover_time = 0,
372 .hangover_period = 20,
373 .dynamic_mode = 1,
374 .early_termination_mode = 1,
375 .max_period = 20,
376 .min_period = 1,
377 .increase_delta = 1,
378 .decrease_delta = 2,
379 .quiet_time = 4,
380 .increase_time = 1,
381 .window_size = 16,
382 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300383};
384
Ido Yariv95dac04f2011-06-06 14:57:06 +0300385static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300386static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300387
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300388static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +0200389 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300390 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200391static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200392static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200393
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200394static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300395static LIST_HEAD(wl_list);
396
Eliad Pellerba8447f2011-10-10 10:13:00 +0200397static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
398 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399{
400 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200401
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (operstate != IF_OPER_UP)
403 return 0;
404
Eliad Peller8181aec2011-10-10 10:13:04 +0200405 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300406 return 0;
407
Eliad Peller154da672011-10-05 11:55:53 +0200408 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300409 if (ret < 0)
410 return ret;
411
Eliad Peller0603d892011-10-05 11:55:51 +0200412 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300413
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300414 wl1271_info("Association completed.");
415 return 0;
416}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300417static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
418 void *arg)
419{
420 struct net_device *dev = arg;
421 struct wireless_dev *wdev;
422 struct wiphy *wiphy;
423 struct ieee80211_hw *hw;
424 struct wl1271 *wl;
425 struct wl1271 *wl_temp;
Eliad Pellerba8447f2011-10-10 10:13:00 +0200426 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300427 int ret = 0;
428
429 /* Check that this notification is for us. */
430 if (what != NETDEV_CHANGE)
431 return NOTIFY_DONE;
432
433 wdev = dev->ieee80211_ptr;
434 if (wdev == NULL)
435 return NOTIFY_DONE;
436
437 wiphy = wdev->wiphy;
438 if (wiphy == NULL)
439 return NOTIFY_DONE;
440
441 hw = wiphy_priv(wiphy);
442 if (hw == NULL)
443 return NOTIFY_DONE;
444
445 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200446 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300447 list_for_each_entry(wl, &wl_list, list) {
448 if (wl == wl_temp)
449 break;
450 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200451 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300452 if (wl != wl_temp)
453 return NOTIFY_DONE;
454
455 mutex_lock(&wl->mutex);
456
457 if (wl->state == WL1271_STATE_OFF)
458 goto out;
459
Eliad Peller6ab70912011-12-18 20:25:45 +0200460 if (dev->operstate != IF_OPER_UP)
461 goto out;
462 /*
463 * The correct behavior should be just getting the appropriate wlvif
464 * from the given dev, but currently we don't have a mac80211
465 * interface for it.
466 */
Eliad Pellerba8447f2011-10-10 10:13:00 +0200467 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200468 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
469
Eliad Pellerba8447f2011-10-10 10:13:00 +0200470 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
471 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f2011-10-10 10:13:00 +0200473 ret = wl1271_ps_elp_wakeup(wl);
474 if (ret < 0)
475 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300476
Eliad Peller6ab70912011-12-18 20:25:45 +0200477 wl1271_check_operstate(wl, wlvif,
478 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300479
Eliad Pellerba8447f2011-10-10 10:13:00 +0200480 wl1271_ps_elp_sleep(wl);
481 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300482out:
483 mutex_unlock(&wl->mutex);
484
485 return NOTIFY_OK;
486}
487
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100488static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200489 struct regulatory_request *request)
490{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100491 struct ieee80211_supported_band *band;
492 struct ieee80211_channel *ch;
493 int i;
494
495 band = wiphy->bands[IEEE80211_BAND_5GHZ];
496 for (i = 0; i < band->n_channels; i++) {
497 ch = &band->channels[i];
498 if (ch->flags & IEEE80211_CHAN_DISABLED)
499 continue;
500
501 if (ch->flags & IEEE80211_CHAN_RADAR)
502 ch->flags |= IEEE80211_CHAN_NO_IBSS |
503 IEEE80211_CHAN_PASSIVE_SCAN;
504
505 }
506
507 return 0;
508}
509
Eliad Peller9eb599e2011-10-10 10:12:59 +0200510static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
511 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300512{
513 int ret = 0;
514
515 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200516 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517 if (ret < 0)
518 goto out;
519
520 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200521 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300522 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200523 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300524out:
525 return ret;
526}
527
528/*
529 * this function is being called when the rx_streaming interval
530 * has beed changed or rx_streaming should be disabled
531 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200532int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300533{
534 int ret = 0;
535 int period = wl->conf.rx_streaming.interval;
536
537 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200538 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300539 goto out;
540
541 /* reconfigure/disable according to new streaming_period */
542 if (period &&
Eliad Pellerba8447f2011-10-10 10:13:00 +0200543 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 (wl->conf.rx_streaming.always ||
545 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200546 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300547 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200548 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300549 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200550 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300551 }
552out:
553 return ret;
554}
555
556static void wl1271_rx_streaming_enable_work(struct work_struct *work)
557{
558 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200559 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
560 rx_streaming_enable_work);
561 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300562
563 mutex_lock(&wl->mutex);
564
Eliad Peller0744bdb2011-10-10 10:13:05 +0200565 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f2011-10-10 10:13:00 +0200566 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300567 (!wl->conf.rx_streaming.always &&
568 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
569 goto out;
570
571 if (!wl->conf.rx_streaming.interval)
572 goto out;
573
574 ret = wl1271_ps_elp_wakeup(wl);
575 if (ret < 0)
576 goto out;
577
Eliad Peller9eb599e2011-10-10 10:12:59 +0200578 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300579 if (ret < 0)
580 goto out_sleep;
581
582 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200583 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300584 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
585
586out_sleep:
587 wl1271_ps_elp_sleep(wl);
588out:
589 mutex_unlock(&wl->mutex);
590}
591
592static void wl1271_rx_streaming_disable_work(struct work_struct *work)
593{
594 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200595 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
596 rx_streaming_disable_work);
597 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300598
599 mutex_lock(&wl->mutex);
600
Eliad Peller0744bdb2011-10-10 10:13:05 +0200601 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 goto out;
603
604 ret = wl1271_ps_elp_wakeup(wl);
605 if (ret < 0)
606 goto out;
607
Eliad Peller9eb599e2011-10-10 10:12:59 +0200608 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300609 if (ret)
610 goto out_sleep;
611
612out_sleep:
613 wl1271_ps_elp_sleep(wl);
614out:
615 mutex_unlock(&wl->mutex);
616}
617
618static void wl1271_rx_streaming_timer(unsigned long data)
619{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200620 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
621 struct wl1271 *wl = wlvif->wl;
622 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300623}
624
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300625static void wl1271_conf_init(struct wl1271 *wl)
626{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300627
628 /*
629 * This function applies the default configuration to the driver. This
630 * function is invoked upon driver load (spi probe.)
631 *
632 * The configuration is stored in a run-time structure in order to
633 * facilitate for run-time adjustment of any of the parameters. Making
634 * changes to the configuration structure will apply the new values on
635 * the next interface up (wl1271_op_start.)
636 */
637
638 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300639 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300640
Ido Yariv95dac04f2011-06-06 14:57:06 +0300641 /* Adjust settings according to optional module parameters */
642 if (fwlog_param) {
643 if (!strcmp(fwlog_param, "continuous")) {
644 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
645 } else if (!strcmp(fwlog_param, "ondemand")) {
646 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
647 } else if (!strcmp(fwlog_param, "dbgpins")) {
648 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
649 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
650 } else if (!strcmp(fwlog_param, "disable")) {
651 wl->conf.fwlog.mem_blocks = 0;
652 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
653 } else {
654 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
655 }
656 }
657}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300658
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300659static int wl1271_plt_init(struct wl1271 *wl)
660{
Eliad Peller188e7f52011-12-06 12:15:06 +0200661 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_general_parms(wl);
665 else
666 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id == CHIP_ID_1283_PG20)
671 ret = wl128x_cmd_radio_parms(wl);
672 else
673 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200674 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200675 return ret;
676
Shahar Levi49d750ca2011-03-06 16:32:09 +0200677 if (wl->chip.id != CHIP_ID_1283_PG20) {
678 ret = wl1271_cmd_ext_radio_parms(wl);
679 if (ret < 0)
680 return ret;
681 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200682 if (ret < 0)
683 return ret;
684
Shahar Levi48a61472011-03-06 16:32:08 +0200685 /* Chip-specific initializations */
686 ret = wl1271_chip_specific_init(wl);
687 if (ret < 0)
688 return ret;
689
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300690 ret = wl1271_acx_init_mem_config(wl);
691 if (ret < 0)
692 return ret;
693
Eliad Peller7f0979882011-08-14 13:17:06 +0300694 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600695 if (ret < 0)
696 goto out_free_memmap;
697
Luciano Coelho12419cc2010-02-18 13:25:44 +0200698 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200699 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300700 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200701 goto out_free_memmap;
702
703 /* Configure for CAM power saving (ie. always active) */
704 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
705 if (ret < 0)
706 goto out_free_memmap;
707
708 /* configure PM */
709 ret = wl1271_acx_pm_config(wl);
710 if (ret < 0)
711 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300712
713 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200714
715 out_free_memmap:
716 kfree(wl->target_mem_map);
717 wl->target_mem_map = NULL;
718
719 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300720}
721
Eliad Peller6e8cd332011-10-10 10:13:13 +0200722static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
723 struct wl12xx_vif *wlvif,
724 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200725{
Arik Nemtsovda032092011-08-25 12:43:15 +0300726 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727
Arik Nemtsovb622d992011-02-23 00:22:31 +0200728 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300729 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
731 /*
732 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300733 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200734 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300735 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200736 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200737
Arik Nemtsovda032092011-08-25 12:43:15 +0300738 /*
739 * Start high-level PS if the STA is asleep with enough blocks in FW.
740 * Make an exception if this is the only connected station. In this
741 * case FW-memory congestion is not a problem.
742 */
743 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200744 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745}
746
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300747static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200748 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300749 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200750{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200751 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200752 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300753 u8 hlid, cnt;
754
755 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200756
757 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
758 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
759 wl1271_debug(DEBUG_PSM,
760 "link ps prev 0x%x cur 0x%x changed 0x%x",
761 wl->ap_fw_ps_map, cur_fw_ps_map,
762 wl->ap_fw_ps_map ^ cur_fw_ps_map);
763
764 wl->ap_fw_ps_map = cur_fw_ps_map;
765 }
766
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200767 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
768 lnk = &wl->links[hlid];
769 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200770
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200771 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
772 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200773
Eliad Peller6e8cd332011-10-10 10:13:13 +0200774 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
775 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200776 }
777}
778
Eliad Peller4d56ad92011-08-14 13:17:05 +0300779static void wl12xx_fw_status(struct wl1271 *wl,
780 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300781{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200782 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200783 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200784 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300785 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300786 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300787
Eliad Peller4d56ad92011-08-14 13:17:05 +0300788 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200789
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300790 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
791 "drv_rx_counter = %d, tx_results_counter = %d)",
792 status->intr,
793 status->fw_rx_counter,
794 status->drv_rx_counter,
795 status->tx_results_counter);
796
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300797 for (i = 0; i < NUM_TX_QUEUES; i++) {
798 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300799 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300800 (status->tx_released_pkts[i] -
801 wl->tx_pkts_freed[i]) & 0xff;
802
803 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
804 }
805
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300806 /* prevent wrap-around in total blocks counter */
807 if (likely(wl->tx_blocks_freed <=
808 le32_to_cpu(status->total_released_blks)))
809 freed_blocks = le32_to_cpu(status->total_released_blks) -
810 wl->tx_blocks_freed;
811 else
812 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
813 le32_to_cpu(status->total_released_blks);
814
Eliad Peller4d56ad92011-08-14 13:17:05 +0300815 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200816
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300817 wl->tx_allocated_blocks -= freed_blocks;
818
Eliad Peller4d56ad92011-08-14 13:17:05 +0300819 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200820
Eliad Peller4d56ad92011-08-14 13:17:05 +0300821 /*
822 * The FW might change the total number of TX memblocks before
823 * we get a notification about blocks being released. Thus, the
824 * available blocks calculation might yield a temporary result
825 * which is lower than the actual available blocks. Keeping in
826 * mind that only blocks that were allocated can be moved from
827 * TX to RX, tx_blocks_available should never decrease here.
828 */
829 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
830 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300831
Ido Yariva5225502010-10-12 14:49:10 +0200832 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200833 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200834 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300835
Eliad Peller4d56ad92011-08-14 13:17:05 +0300836 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200837 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200838 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200839 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300840
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300841 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200842 getnstimeofday(&ts);
843 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
844 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300845}
846
Ido Yariva6208652011-03-01 15:14:41 +0200847static void wl1271_flush_deferred_work(struct wl1271 *wl)
848{
849 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200850
Ido Yariva6208652011-03-01 15:14:41 +0200851 /* Pass all received frames to the network stack */
852 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
853 ieee80211_rx_ni(wl->hw, skb);
854
855 /* Return sent skbs to the network stack */
856 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300857 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200858}
859
860static void wl1271_netstack_work(struct work_struct *work)
861{
862 struct wl1271 *wl =
863 container_of(work, struct wl1271, netstack_work);
864
865 do {
866 wl1271_flush_deferred_work(wl);
867 } while (skb_queue_len(&wl->deferred_rx_queue));
868}
869
870#define WL1271_IRQ_MAX_LOOPS 256
871
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300872static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300874 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300875 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200876 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200877 struct wl1271 *wl = (struct wl1271 *)cookie;
878 bool done = false;
879 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200880 unsigned long flags;
881
882 /* TX might be handled here, avoid redundant work */
883 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
884 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300885
Ido Yariv341b7cd2011-03-31 10:07:01 +0200886 /*
887 * In case edge triggered interrupt must be used, we cannot iterate
888 * more than once without introducing race conditions with the hardirq.
889 */
890 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
891 loopcount = 1;
892
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300893 mutex_lock(&wl->mutex);
894
895 wl1271_debug(DEBUG_IRQ, "IRQ work");
896
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200897 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300898 goto out;
899
Ido Yariva6208652011-03-01 15:14:41 +0200900 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300901 if (ret < 0)
902 goto out;
903
Ido Yariva6208652011-03-01 15:14:41 +0200904 while (!done && loopcount--) {
905 /*
906 * In order to avoid a race with the hardirq, clear the flag
907 * before acknowledging the chip. Since the mutex is held,
908 * wl1271_ps_elp_wakeup cannot be called concurrently.
909 */
910 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
911 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200912
Eliad Peller4d56ad92011-08-14 13:17:05 +0300913 wl12xx_fw_status(wl, wl->fw_status);
914 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200915 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200916 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200917 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200918 continue;
919 }
920
Eliad Pellerccc83b02010-10-27 14:09:57 +0200921 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
922 wl1271_error("watchdog interrupt received! "
923 "starting recovery.");
Ido Yarivbaacb9a2011-06-06 14:57:05 +0300924 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200925
926 /* restarting the chip. ignore any other interrupt. */
927 goto out;
928 }
929
Ido Yariva6208652011-03-01 15:14:41 +0200930 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200931 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
932
Eliad Peller4d56ad92011-08-14 13:17:05 +0300933 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200934
Ido Yariva5225502010-10-12 14:49:10 +0200935 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200936 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200937 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300938 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 /*
941 * In order to avoid starvation of the TX path,
942 * call the work function directly.
943 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200944 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200945 } else {
946 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200947 }
948
Ido Yariv8aad2462011-03-01 15:14:38 +0200949 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300950 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200951 (wl->tx_results_count & 0xff))
952 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200953
954 /* Make sure the deferred queues don't get too long */
955 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
956 skb_queue_len(&wl->deferred_rx_queue);
957 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
958 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200959 }
960
961 if (intr & WL1271_ACX_INTR_EVENT_A) {
962 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
963 wl1271_event_handle(wl, 0);
964 }
965
966 if (intr & WL1271_ACX_INTR_EVENT_B) {
967 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
968 wl1271_event_handle(wl, 1);
969 }
970
971 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
972 wl1271_debug(DEBUG_IRQ,
973 "WL1271_ACX_INTR_INIT_COMPLETE");
974
975 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
976 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300977 }
978
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300979 wl1271_ps_elp_sleep(wl);
980
981out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200982 spin_lock_irqsave(&wl->wl_lock, flags);
983 /* In case TX was not handled here, queue TX work */
984 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
985 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300986 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200987 ieee80211_queue_work(wl->hw, &wl->tx_work);
988 spin_unlock_irqrestore(&wl->wl_lock, flags);
989
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300990 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200991
992 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300993}
994
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300995static int wl1271_fetch_firmware(struct wl1271 *wl)
996{
997 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300999 int ret;
1000
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001001 if (wl->chip.id == CHIP_ID_1283_PG20)
1002 fw_name = WL128X_FW_NAME;
1003 else
1004 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001005
1006 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1007
Felipe Balbia390e852011-10-06 10:07:44 +03001008 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001009
1010 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001011 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001012 return ret;
1013 }
1014
1015 if (fw->size % 4) {
1016 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1017 fw->size);
1018 ret = -EILSEQ;
1019 goto out;
1020 }
1021
Arik Nemtsov166d5042010-10-16 21:44:57 +02001022 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001023 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001024 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001025
1026 if (!wl->fw) {
1027 wl1271_error("could not allocate memory for the firmware");
1028 ret = -ENOMEM;
1029 goto out;
1030 }
1031
1032 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001033 ret = 0;
1034
1035out:
1036 release_firmware(fw);
1037
1038 return ret;
1039}
1040
1041static int wl1271_fetch_nvs(struct wl1271 *wl)
1042{
1043 const struct firmware *fw;
1044 int ret;
1045
Felipe Balbia390e852011-10-06 10:07:44 +03001046 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001047
1048 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001049 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1050 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001051 return ret;
1052 }
1053
Shahar Levibc765bf2011-03-06 16:32:10 +02001054 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001055
1056 if (!wl->nvs) {
1057 wl1271_error("could not allocate memory for the nvs file");
1058 ret = -ENOMEM;
1059 goto out;
1060 }
1061
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001062 wl->nvs_len = fw->size;
1063
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001064out:
1065 release_firmware(fw);
1066
1067 return ret;
1068}
1069
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001070void wl12xx_queue_recovery_work(struct wl1271 *wl)
1071{
1072 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1073 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1074}
1075
Ido Yariv95dac04f2011-06-06 14:57:06 +03001076size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1077{
1078 size_t len = 0;
1079
1080 /* The FW log is a length-value list, find where the log end */
1081 while (len < maxlen) {
1082 if (memblock[len] == 0)
1083 break;
1084 if (len + memblock[len] + 1 > maxlen)
1085 break;
1086 len += memblock[len] + 1;
1087 }
1088
1089 /* Make sure we have enough room */
1090 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1091
1092 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1093 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1094 wl->fwlog_size += len;
1095
1096 return len;
1097}
1098
1099static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1100{
1101 u32 addr;
1102 u32 first_addr;
1103 u8 *block;
1104
1105 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1106 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1107 (wl->conf.fwlog.mem_blocks == 0))
1108 return;
1109
1110 wl1271_info("Reading FW panic log");
1111
1112 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1113 if (!block)
1114 return;
1115
1116 /*
1117 * Make sure the chip is awake and the logger isn't active.
1118 * This might fail if the firmware hanged.
1119 */
1120 if (!wl1271_ps_elp_wakeup(wl))
1121 wl12xx_cmd_stop_fwlog(wl);
1122
1123 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001124 wl12xx_fw_status(wl, wl->fw_status);
1125 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001126 if (!first_addr)
1127 goto out;
1128
1129 /* Traverse the memory blocks linked list */
1130 addr = first_addr;
1131 do {
1132 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1133 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1134 false);
1135
1136 /*
1137 * Memory blocks are linked to one another. The first 4 bytes
1138 * of each memory block hold the hardware address of the next
1139 * one. The last memory block points to the first one.
1140 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001141 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001142 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1143 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1144 break;
1145 } while (addr && (addr != first_addr));
1146
1147 wake_up_interruptible(&wl->fwlog_waitq);
1148
1149out:
1150 kfree(block);
1151}
1152
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001153static void wl1271_recovery_work(struct work_struct *work)
1154{
1155 struct wl1271 *wl =
1156 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001157 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001158 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001159
1160 mutex_lock(&wl->mutex);
1161
1162 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001163 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001164
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001165 /* Avoid a recursive recovery */
1166 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1167
Ido Yariv95dac04f2011-06-06 14:57:06 +03001168 wl12xx_read_fwlog_panic(wl);
1169
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001170 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1171 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001172
Eliad Peller2a5bff02011-08-25 18:10:59 +03001173 BUG_ON(bug_on_recovery);
1174
Oz Krakowskib992c682011-06-26 10:36:02 +03001175 /*
1176 * Advance security sequence number to overcome potential progress
1177 * in the firmware during recovery. This doens't hurt if the network is
1178 * not encrypted.
1179 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001180 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f2011-10-10 10:13:00 +02001181 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001182 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001183 wlvif->tx_security_seq +=
1184 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1185 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001186
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001187 /* Prevent spurious TX during FW restart */
1188 ieee80211_stop_queues(wl->hw);
1189
Luciano Coelho33c2c062011-05-10 14:46:02 +03001190 if (wl->sched_scanning) {
1191 ieee80211_sched_scan_stopped(wl->hw);
1192 wl->sched_scanning = false;
1193 }
1194
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001195 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001196 while (!list_empty(&wl->wlvif_list)) {
1197 wlvif = list_first_entry(&wl->wlvif_list,
1198 struct wl12xx_vif, list);
1199 vif = wl12xx_wlvif_to_vif(wlvif);
1200 __wl1271_op_remove_interface(wl, vif, false);
1201 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001202 mutex_unlock(&wl->mutex);
1203 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9a2011-06-06 14:57:05 +03001204
1205 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1206
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001207 ieee80211_restart_hw(wl->hw);
1208
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001209 /*
1210 * Its safe to enable TX now - the queues are stopped after a request
1211 * to restart the HW.
1212 */
1213 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001214 return;
1215out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001216 mutex_unlock(&wl->mutex);
1217}
1218
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001219static void wl1271_fw_wakeup(struct wl1271 *wl)
1220{
1221 u32 elp_reg;
1222
1223 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001224 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001225}
1226
1227static int wl1271_setup(struct wl1271 *wl)
1228{
1229 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1230 if (!wl->fw_status)
1231 return -ENOMEM;
1232
1233 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1234 if (!wl->tx_res_if) {
1235 kfree(wl->fw_status);
1236 return -ENOMEM;
1237 }
1238
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001239 return 0;
1240}
1241
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001242static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001244 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001245
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001246 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001247 ret = wl1271_power_on(wl);
1248 if (ret < 0)
1249 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001250 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001251 wl1271_io_reset(wl);
1252 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001253
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001254 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255
1256 /* ELP module wake up */
1257 wl1271_fw_wakeup(wl);
1258
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001259out:
1260 return ret;
1261}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001262
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001263static int wl1271_chip_wakeup(struct wl1271 *wl)
1264{
1265 int ret = 0;
1266
1267 ret = wl12xx_set_power_on(wl);
1268 if (ret < 0)
1269 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001270
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001271 /*
1272 * For wl127x based devices we could use the default block
1273 * size (512 bytes), but due to a bug in the sdio driver, we
1274 * need to set it explicitly after the chip is powered on. To
1275 * simplify the code and since the performance impact is
1276 * negligible, we use the same block size for all different
1277 * chip types.
1278 */
1279 if (!wl1271_set_block_size(wl))
1280 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001281
1282 switch (wl->chip.id) {
1283 case CHIP_ID_1271_PG10:
1284 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1285 wl->chip.id);
1286
1287 ret = wl1271_setup(wl);
1288 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001289 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001290 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001291 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001292
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001293 case CHIP_ID_1271_PG20:
1294 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1295 wl->chip.id);
1296
1297 ret = wl1271_setup(wl);
1298 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001299 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001300 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001301 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001302
Shahar Levi0830cee2011-03-06 16:32:20 +02001303 case CHIP_ID_1283_PG20:
1304 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1305 wl->chip.id);
1306
1307 ret = wl1271_setup(wl);
1308 if (ret < 0)
1309 goto out;
1310 break;
1311 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001313 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001314 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001315 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001316 }
1317
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001318 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001319 ret = wl1271_fetch_firmware(wl);
1320 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001321 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 }
1323
1324 /* No NVS from netlink, try to get it from the filesystem */
1325 if (wl->nvs == NULL) {
1326 ret = wl1271_fetch_nvs(wl);
1327 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001328 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001329 }
1330
1331out:
1332 return ret;
1333}
1334
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001335int wl1271_plt_start(struct wl1271 *wl)
1336{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001337 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001338 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001339 int ret;
1340
1341 mutex_lock(&wl->mutex);
1342
1343 wl1271_notice("power up");
1344
1345 if (wl->state != WL1271_STATE_OFF) {
1346 wl1271_error("cannot go into PLT state because not "
1347 "in off state: %d", wl->state);
1348 ret = -EBUSY;
1349 goto out;
1350 }
1351
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001352 while (retries) {
1353 retries--;
1354 ret = wl1271_chip_wakeup(wl);
1355 if (ret < 0)
1356 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001357
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001358 ret = wl1271_boot(wl);
1359 if (ret < 0)
1360 goto power_off;
1361
1362 ret = wl1271_plt_init(wl);
1363 if (ret < 0)
1364 goto irq_disable;
1365
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001366 wl->state = WL1271_STATE_PLT;
1367 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001368 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001369
Gery Kahn6f07b722011-07-18 14:21:49 +03001370 /* update hw/fw version info in wiphy struct */
1371 wiphy->hw_version = wl->chip.id;
1372 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1373 sizeof(wiphy->fw_version));
1374
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001375 goto out;
1376
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001377irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001378 mutex_unlock(&wl->mutex);
1379 /* Unlocking the mutex in the middle of handling is
1380 inherently unsafe. In this case we deem it safe to do,
1381 because we need to let any possibly pending IRQ out of
1382 the system (and while we are WL1271_STATE_OFF the IRQ
1383 work function will not do anything.) Also, any other
1384 possible concurrent operations will fail due to the
1385 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001386 wl1271_disable_interrupts(wl);
1387 wl1271_flush_deferred_work(wl);
1388 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001389 mutex_lock(&wl->mutex);
1390power_off:
1391 wl1271_power_off(wl);
1392 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001393
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001394 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1395 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396out:
1397 mutex_unlock(&wl->mutex);
1398
1399 return ret;
1400}
1401
Ido Yarivf3df1332012-01-11 09:42:39 +02001402int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001403{
1404 int ret = 0;
1405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001406 wl1271_notice("power down");
1407
Ido Yariv46b0cc92012-01-11 09:42:41 +02001408 /*
1409 * Interrupts must be disabled before setting the state to OFF.
1410 * Otherwise, the interrupt handler might be called and exit without
1411 * reading the interrupt status.
1412 */
1413 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001414 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001415 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001416 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001417
1418 /*
1419 * This will not necessarily enable interrupts as interrupts
1420 * may have been disabled when op_stop was called. It will,
1421 * however, balance the above call to disable_interrupts().
1422 */
1423 wl1271_enable_interrupts(wl);
1424
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001425 wl1271_error("cannot power down because not in PLT "
1426 "state: %d", wl->state);
1427 ret = -EBUSY;
1428 goto out;
1429 }
1430
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001431 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001432
Ido Yariva6208652011-03-01 15:14:41 +02001433 wl1271_flush_deferred_work(wl);
1434 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001435 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001436 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001437
1438 mutex_lock(&wl->mutex);
1439 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001440 wl->flags = 0;
1441 wl->state = WL1271_STATE_OFF;
1442 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001443 mutex_unlock(&wl->mutex);
1444
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001445out:
1446 return ret;
1447}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001448
Johannes Berg7bb45682011-02-24 14:42:06 +01001449static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001450{
1451 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001452 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1453 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001454 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001455 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001456 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001457 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001458
Eliad Peller0f168012011-10-11 13:52:25 +02001459 if (vif)
1460 wlvif = wl12xx_vif_to_data(vif);
1461
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001462 mapping = skb_get_queue_mapping(skb);
1463 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001464
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001465 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001466
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001467 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001468
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001469 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001470 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001471 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001472 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001473 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001474 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001475 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001476
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001477 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1478 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1479
Arik Nemtsov04b4d692011-08-14 13:17:39 +03001480 wl->tx_queue_count[q]++;
1481
1482 /*
1483 * The workqueue is slow to process the tx_queue and we need stop
1484 * the queue here, otherwise the queue will get too long.
1485 */
1486 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1487 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1488 ieee80211_stop_queue(wl->hw, mapping);
1489 set_bit(q, &wl->stopped_queues_map);
1490 }
1491
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001492 /*
1493 * The chip specific setup must run before the first TX packet -
1494 * before that, the tx_work will not be initialized!
1495 */
1496
Ido Yarivb07d4032011-03-01 15:14:43 +02001497 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1498 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001499 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001500
Arik Nemtsov04216da2011-08-14 13:17:38 +03001501out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001502 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001503}
1504
Shahar Leviae47c452011-03-06 16:32:14 +02001505int wl1271_tx_dummy_packet(struct wl1271 *wl)
1506{
Ido Yariv990f5de2011-03-31 10:06:59 +02001507 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001508 int q;
1509
1510 /* no need to queue a new dummy packet if one is already pending */
1511 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1512 return 0;
1513
1514 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001515
Ido Yariv990f5de2011-03-31 10:06:59 +02001516 spin_lock_irqsave(&wl->wl_lock, flags);
1517 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001518 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001519 spin_unlock_irqrestore(&wl->wl_lock, flags);
1520
1521 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1522 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001523 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001524
1525 /*
1526 * If the FW TX is busy, TX work will be scheduled by the threaded
1527 * interrupt handler function
1528 */
1529 return 0;
1530}
1531
1532/*
1533 * The size of the dummy packet should be at least 1400 bytes. However, in
1534 * order to minimize the number of bus transactions, aligning it to 512 bytes
1535 * boundaries could be beneficial, performance wise
1536 */
1537#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1538
Luciano Coelhocf27d862011-04-01 21:08:23 +03001539static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001540{
1541 struct sk_buff *skb;
1542 struct ieee80211_hdr_3addr *hdr;
1543 unsigned int dummy_packet_size;
1544
1545 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1546 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1547
1548 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001549 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001550 wl1271_warning("Failed to allocate a dummy packet skb");
1551 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001552 }
1553
1554 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1555
1556 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1557 memset(hdr, 0, sizeof(*hdr));
1558 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001559 IEEE80211_STYPE_NULLFUNC |
1560 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001561
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001563
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001564 /* Dummy packets require the TID to be management */
1565 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001566
1567 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001568 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001569 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001570
Ido Yariv990f5de2011-03-31 10:06:59 +02001571 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001572}
1573
Ido Yariv990f5de2011-03-31 10:06:59 +02001574
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001575static struct notifier_block wl1271_dev_notifier = {
1576 .notifier_call = wl1271_dev_notify,
1577};
1578
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001579#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001580static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1581 struct wl12xx_vif *wlvif)
1582{
1583 int ret = 0;
1584
1585 mutex_lock(&wl->mutex);
1586
1587 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1588 goto out_unlock;
1589
1590 ret = wl1271_ps_elp_wakeup(wl);
1591 if (ret < 0)
1592 goto out_unlock;
1593
1594 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1595 wl->conf.conn.suspend_wake_up_event,
1596 wl->conf.conn.suspend_listen_interval);
1597
1598 if (ret < 0)
1599 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1600
1601
1602 wl1271_ps_elp_sleep(wl);
1603
1604out_unlock:
1605 mutex_unlock(&wl->mutex);
1606 return ret;
1607
1608}
Eliad Peller94390642011-05-13 11:57:13 +03001609
Eliad Peller0603d892011-10-05 11:55:51 +02001610static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1611 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001612{
Eliad Pellere85d1622011-06-27 13:06:43 +03001613 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001614
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001615 mutex_lock(&wl->mutex);
1616
Eliad Peller53d40d02011-10-10 10:13:02 +02001617 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001618 goto out_unlock;
1619
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001620 ret = wl1271_ps_elp_wakeup(wl);
1621 if (ret < 0)
1622 goto out_unlock;
1623
Eliad Peller0603d892011-10-05 11:55:51 +02001624 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001625
1626 wl1271_ps_elp_sleep(wl);
1627out_unlock:
1628 mutex_unlock(&wl->mutex);
1629 return ret;
1630
1631}
1632
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001633static int wl1271_configure_suspend(struct wl1271 *wl,
1634 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001636 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1637 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c2011-10-05 11:55:45 +02001638 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001639 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640 return 0;
1641}
1642
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001643static void wl1271_configure_resume(struct wl1271 *wl,
1644 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001645{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001646 int ret = 0;
Eliad Peller536129c2011-10-05 11:55:45 +02001647 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001648 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001649
Eyal Shapiradae728f2012-02-02 12:03:39 +02001650 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001651 return;
1652
1653 mutex_lock(&wl->mutex);
1654 ret = wl1271_ps_elp_wakeup(wl);
1655 if (ret < 0)
1656 goto out;
1657
Eyal Shapiradae728f2012-02-02 12:03:39 +02001658 if (is_sta) {
1659 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1660 wl->conf.conn.wake_up_event,
1661 wl->conf.conn.listen_interval);
1662
1663 if (ret < 0)
1664 wl1271_error("resume: wake up conditions failed: %d",
1665 ret);
1666
1667 } else if (is_ap) {
1668 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1669 }
Eliad Peller94390642011-05-13 11:57:13 +03001670
1671 wl1271_ps_elp_sleep(wl);
1672out:
1673 mutex_unlock(&wl->mutex);
1674}
1675
Eliad Peller402e48612011-05-13 11:57:09 +03001676static int wl1271_op_suspend(struct ieee80211_hw *hw,
1677 struct cfg80211_wowlan *wow)
1678{
1679 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001680 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001681 int ret;
1682
Eliad Peller402e48612011-05-13 11:57:09 +03001683 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001684 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001685
Eliad Peller4a859df2011-06-06 12:21:52 +03001686 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001687 wl12xx_for_each_wlvif(wl, wlvif) {
1688 ret = wl1271_configure_suspend(wl, wlvif);
1689 if (ret < 0) {
1690 wl1271_warning("couldn't prepare device to suspend");
1691 return ret;
1692 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001693 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001694 /* flush any remaining work */
1695 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001696
1697 /*
1698 * disable and re-enable interrupts in order to flush
1699 * the threaded_irq
1700 */
1701 wl1271_disable_interrupts(wl);
1702
1703 /*
1704 * set suspended flag to avoid triggering a new threaded_irq
1705 * work. no need for spinlock as interrupts are disabled.
1706 */
1707 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1708
1709 wl1271_enable_interrupts(wl);
1710 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001711 flush_delayed_work(&wl->elp_work);
1712
Eliad Peller402e48612011-05-13 11:57:09 +03001713 return 0;
1714}
1715
1716static int wl1271_op_resume(struct ieee80211_hw *hw)
1717{
1718 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001719 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001720 unsigned long flags;
1721 bool run_irq_work = false;
1722
Eliad Peller402e48612011-05-13 11:57:09 +03001723 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1724 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001726
1727 /*
1728 * re-enable irq_work enqueuing, and call irq_work directly if
1729 * there is a pending work.
1730 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001731 spin_lock_irqsave(&wl->wl_lock, flags);
1732 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1733 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1734 run_irq_work = true;
1735 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001736
Eliad Peller4a859df2011-06-06 12:21:52 +03001737 if (run_irq_work) {
1738 wl1271_debug(DEBUG_MAC80211,
1739 "run postponed irq_work directly");
1740 wl1271_irq(0, wl);
1741 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001742 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001743 wl12xx_for_each_wlvif(wl, wlvif) {
1744 wl1271_configure_resume(wl, wlvif);
1745 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001746 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001747
Eliad Peller402e48612011-05-13 11:57:09 +03001748 return 0;
1749}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001750#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001751
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001752static int wl1271_op_start(struct ieee80211_hw *hw)
1753{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001754 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1755
1756 /*
1757 * We have to delay the booting of the hardware because
1758 * we need to know the local MAC address before downloading and
1759 * initializing the firmware. The MAC address cannot be changed
1760 * after boot, and without the proper MAC address, the firmware
1761 * will not function properly.
1762 *
1763 * The MAC address is first known when the corresponding interface
1764 * is added. That is where we will initialize the hardware.
1765 */
1766
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001767 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001768}
1769
1770static void wl1271_op_stop(struct ieee80211_hw *hw)
1771{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001772 struct wl1271 *wl = hw->priv;
1773 int i;
1774
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001775 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001776
Ido Yariv46b0cc92012-01-11 09:42:41 +02001777 /*
1778 * Interrupts must be disabled before setting the state to OFF.
1779 * Otherwise, the interrupt handler might be called and exit without
1780 * reading the interrupt status.
1781 */
1782 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001783 mutex_lock(&wl->mutex);
1784 if (wl->state == WL1271_STATE_OFF) {
1785 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001786
1787 /*
1788 * This will not necessarily enable interrupts as interrupts
1789 * may have been disabled when op_stop was called. It will,
1790 * however, balance the above call to disable_interrupts().
1791 */
1792 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001793 return;
1794 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001795
Eliad Pellerbaf62772011-10-10 10:12:52 +02001796 /*
1797 * this must be before the cancel_work calls below, so that the work
1798 * functions don't perform further work.
1799 */
1800 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001801 mutex_unlock(&wl->mutex);
1802
1803 mutex_lock(&wl_list_mutex);
1804 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001805 mutex_unlock(&wl_list_mutex);
1806
Eliad Pellerbaf62772011-10-10 10:12:52 +02001807 wl1271_flush_deferred_work(wl);
1808 cancel_delayed_work_sync(&wl->scan_complete_work);
1809 cancel_work_sync(&wl->netstack_work);
1810 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001811 cancel_delayed_work_sync(&wl->elp_work);
1812
1813 /* let's notify MAC80211 about the remaining pending TX frames */
1814 wl12xx_tx_reset(wl, true);
1815 mutex_lock(&wl->mutex);
1816
1817 wl1271_power_off(wl);
1818
1819 wl->band = IEEE80211_BAND_2GHZ;
1820
1821 wl->rx_counter = 0;
1822 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1823 wl->tx_blocks_available = 0;
1824 wl->tx_allocated_blocks = 0;
1825 wl->tx_results_count = 0;
1826 wl->tx_packets_count = 0;
1827 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001828 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1829 wl->ap_fw_ps_map = 0;
1830 wl->ap_ps_map = 0;
1831 wl->sched_scanning = false;
1832 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1833 memset(wl->links_map, 0, sizeof(wl->links_map));
1834 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1835 wl->active_sta_count = 0;
1836
1837 /* The system link is always allocated */
1838 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1839
1840 /*
1841 * this is performed after the cancel_work calls and the associated
1842 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1843 * get executed before all these vars have been reset.
1844 */
1845 wl->flags = 0;
1846
1847 wl->tx_blocks_freed = 0;
1848
1849 for (i = 0; i < NUM_TX_QUEUES; i++) {
1850 wl->tx_pkts_freed[i] = 0;
1851 wl->tx_allocated_pkts[i] = 0;
1852 }
1853
1854 wl1271_debugfs_reset(wl);
1855
1856 kfree(wl->fw_status);
1857 wl->fw_status = NULL;
1858 kfree(wl->tx_res_if);
1859 wl->tx_res_if = NULL;
1860 kfree(wl->target_mem_map);
1861 wl->target_mem_map = NULL;
1862
1863 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001864}
1865
Eliad Pellere5a359f2011-10-10 10:13:15 +02001866static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1867{
1868 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1869 WL12XX_MAX_RATE_POLICIES);
1870 if (policy >= WL12XX_MAX_RATE_POLICIES)
1871 return -EBUSY;
1872
1873 __set_bit(policy, wl->rate_policies_map);
1874 *idx = policy;
1875 return 0;
1876}
1877
1878static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1879{
1880 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1881 return;
1882
1883 __clear_bit(*idx, wl->rate_policies_map);
1884 *idx = WL12XX_MAX_RATE_POLICIES;
1885}
1886
Eliad Peller536129c2011-10-05 11:55:45 +02001887static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001888{
Eliad Peller536129c2011-10-05 11:55:45 +02001889 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001890 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001891 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001892 return WL1271_ROLE_P2P_GO;
1893 else
1894 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001895
1896 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001897 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001898 return WL1271_ROLE_P2P_CL;
1899 else
1900 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001901
Eliad Peller227e81e2011-08-14 13:17:26 +03001902 case BSS_TYPE_IBSS:
1903 return WL1271_ROLE_IBSS;
1904
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001905 default:
Eliad Peller536129c2011-10-05 11:55:45 +02001906 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001907 }
1908 return WL12XX_INVALID_ROLE_TYPE;
1909}
1910
Eliad Peller83587502011-10-10 10:12:53 +02001911static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001912{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001913 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001914 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001915
Eliad Peller48e93e42011-10-10 10:12:58 +02001916 /* clear everything but the persistent data */
1917 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001918
1919 switch (ieee80211_vif_type_p2p(vif)) {
1920 case NL80211_IFTYPE_P2P_CLIENT:
1921 wlvif->p2p = 1;
1922 /* fall-through */
1923 case NL80211_IFTYPE_STATION:
1924 wlvif->bss_type = BSS_TYPE_STA_BSS;
1925 break;
1926 case NL80211_IFTYPE_ADHOC:
1927 wlvif->bss_type = BSS_TYPE_IBSS;
1928 break;
1929 case NL80211_IFTYPE_P2P_GO:
1930 wlvif->p2p = 1;
1931 /* fall-through */
1932 case NL80211_IFTYPE_AP:
1933 wlvif->bss_type = BSS_TYPE_AP_BSS;
1934 break;
1935 default:
1936 wlvif->bss_type = MAX_BSS_TYPE;
1937 return -EOPNOTSUPP;
1938 }
1939
Eliad Peller0603d892011-10-05 11:55:51 +02001940 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001941 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001942 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001943
Eliad Pellere936bbe2011-10-05 11:55:56 +02001944 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1945 wlvif->bss_type == BSS_TYPE_IBSS) {
1946 /* init sta/ibss data */
1947 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001948 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1949 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1950 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001951 } else {
1952 /* init ap data */
1953 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1954 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001955 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1956 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1957 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1958 wl12xx_allocate_rate_policy(wl,
1959 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001960 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001961
Eliad Peller83587502011-10-10 10:12:53 +02001962 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1963 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001964 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001965 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001966 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001967 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1968
Eliad Peller1b92f152011-10-10 10:13:09 +02001969 /*
1970 * mac80211 configures some values globally, while we treat them
1971 * per-interface. thus, on init, we have to copy them from wl
1972 */
1973 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001974 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001975 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001976
Eliad Peller9eb599e2011-10-10 10:12:59 +02001977 INIT_WORK(&wlvif->rx_streaming_enable_work,
1978 wl1271_rx_streaming_enable_work);
1979 INIT_WORK(&wlvif->rx_streaming_disable_work,
1980 wl1271_rx_streaming_disable_work);
Eliad Peller87627212011-10-10 10:12:54 +02001981 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001982
Eliad Peller9eb599e2011-10-10 10:12:59 +02001983 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1984 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001985 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001986}
1987
Eliad Peller1d095472011-10-10 10:12:49 +02001988static bool wl12xx_init_fw(struct wl1271 *wl)
1989{
1990 int retries = WL1271_BOOT_RETRIES;
1991 bool booted = false;
1992 struct wiphy *wiphy = wl->hw->wiphy;
1993 int ret;
1994
1995 while (retries) {
1996 retries--;
1997 ret = wl1271_chip_wakeup(wl);
1998 if (ret < 0)
1999 goto power_off;
2000
2001 ret = wl1271_boot(wl);
2002 if (ret < 0)
2003 goto power_off;
2004
2005 ret = wl1271_hw_init(wl);
2006 if (ret < 0)
2007 goto irq_disable;
2008
2009 booted = true;
2010 break;
2011
2012irq_disable:
2013 mutex_unlock(&wl->mutex);
2014 /* Unlocking the mutex in the middle of handling is
2015 inherently unsafe. In this case we deem it safe to do,
2016 because we need to let any possibly pending IRQ out of
2017 the system (and while we are WL1271_STATE_OFF the IRQ
2018 work function will not do anything.) Also, any other
2019 possible concurrent operations will fail due to the
2020 current state, hence the wl1271 struct should be safe. */
2021 wl1271_disable_interrupts(wl);
2022 wl1271_flush_deferred_work(wl);
2023 cancel_work_sync(&wl->netstack_work);
2024 mutex_lock(&wl->mutex);
2025power_off:
2026 wl1271_power_off(wl);
2027 }
2028
2029 if (!booted) {
2030 wl1271_error("firmware boot failed despite %d retries",
2031 WL1271_BOOT_RETRIES);
2032 goto out;
2033 }
2034
2035 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2036
2037 /* update hw/fw version info in wiphy struct */
2038 wiphy->hw_version = wl->chip.id;
2039 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2040 sizeof(wiphy->fw_version));
2041
2042 /*
2043 * Now we know if 11a is supported (info from the NVS), so disable
2044 * 11a channels if not supported
2045 */
2046 if (!wl->enable_11a)
2047 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2048
2049 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2050 wl->enable_11a ? "" : "not ");
2051
2052 wl->state = WL1271_STATE_ON;
2053out:
2054 return booted;
2055}
2056
Eliad Peller92e712d2011-12-18 20:25:43 +02002057static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2058{
2059 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2060}
2061
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002062static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2063 struct ieee80211_vif *vif)
2064{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002065 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002066 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002067 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002068 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002069 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002070
Johannes Bergea086352012-01-19 09:29:58 +01002071 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2072 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002073
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002074 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002075 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002076
2077 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002078 ret = wl1271_ps_elp_wakeup(wl);
2079 if (ret < 0)
2080 goto out_unlock;
2081
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002082 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002083 wl1271_debug(DEBUG_MAC80211,
2084 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002085 ret = -EBUSY;
2086 goto out;
2087 }
2088
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002089 /*
2090 * in some very corner case HW recovery scenarios its possible to
2091 * get here before __wl1271_op_remove_interface is complete, so
2092 * opt out if that is the case.
2093 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002094 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2095 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002096 ret = -EBUSY;
2097 goto out;
2098 }
2099
Eliad Peller83587502011-10-10 10:12:53 +02002100 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002101 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002103
Eliad Peller252efa42011-10-05 11:56:00 +02002104 wlvif->wl = wl;
Eliad Peller536129c2011-10-05 11:55:45 +02002105 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002106 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2107 ret = -EINVAL;
2108 goto out;
2109 }
Eliad Peller1d095472011-10-10 10:12:49 +02002110
Eliad Peller784f6942011-10-05 11:55:39 +02002111 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002112 * TODO: after the nvs issue will be solved, move this block
2113 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002114 */
Eliad Peller1d095472011-10-10 10:12:49 +02002115 if (wl->state == WL1271_STATE_OFF) {
2116 /*
2117 * we still need this in order to configure the fw
2118 * while uploading the nvs
2119 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002120 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002121
Eliad Peller1d095472011-10-10 10:12:49 +02002122 booted = wl12xx_init_fw(wl);
2123 if (!booted) {
2124 ret = -EINVAL;
2125 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002126 }
Eliad Peller1d095472011-10-10 10:12:49 +02002127 }
Eliad Peller04e80792011-08-14 13:17:09 +03002128
Eliad Peller1d095472011-10-10 10:12:49 +02002129 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2130 wlvif->bss_type == BSS_TYPE_IBSS) {
2131 /*
2132 * The device role is a special role used for
2133 * rx and tx frames prior to association (as
2134 * the STA role can get packets only from
2135 * its associated bssid)
2136 */
Eliad Peller784f6942011-10-05 11:55:39 +02002137 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002138 WL1271_ROLE_DEVICE,
2139 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002140 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002141 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002142 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002143
Eliad Peller1d095472011-10-10 10:12:49 +02002144 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2145 role_type, &wlvif->role_id);
2146 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002147 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002148
2149 ret = wl1271_init_vif_specific(wl, vif);
2150 if (ret < 0)
2151 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002152
2153 wl->vif = vif;
Eliad Peller87627212011-10-10 10:12:54 +02002154 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002155 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002156
2157 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2158 wl->ap_count++;
2159 else
2160 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002161out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002162 wl1271_ps_elp_sleep(wl);
2163out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002164 mutex_unlock(&wl->mutex);
2165
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002166 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002167 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002168 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002169 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002170
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002171 return ret;
2172}
2173
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002174static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c2011-10-05 11:55:45 +02002175 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002176 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002177{
Eliad Peller536129c2011-10-05 11:55:45 +02002178 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002179 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002180
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002181 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002182
Eliad Peller10c8cd02011-10-10 10:13:06 +02002183 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2184 return;
2185
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002186 wl->vif = NULL;
2187
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002188 /* because of hardware recovery, we may get here twice */
2189 if (wl->state != WL1271_STATE_ON)
2190 return;
2191
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002192 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002193
Eliad Pellerbaf62772011-10-10 10:12:52 +02002194 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2195 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002196 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002197 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002198 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002199 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002200 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002201 }
2202
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002203 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2204 /* disable active roles */
2205 ret = wl1271_ps_elp_wakeup(wl);
2206 if (ret < 0)
2207 goto deinit;
2208
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002209 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2210 wlvif->bss_type == BSS_TYPE_IBSS) {
2211 if (wl12xx_dev_role_started(wlvif))
2212 wl12xx_stop_dev(wl, wlvif);
2213
Eliad Peller7edebf52011-10-05 11:55:52 +02002214 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002215 if (ret < 0)
2216 goto deinit;
2217 }
2218
Eliad Peller0603d892011-10-05 11:55:51 +02002219 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002220 if (ret < 0)
2221 goto deinit;
2222
2223 wl1271_ps_elp_sleep(wl);
2224 }
2225deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002226 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002227 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002228
2229 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2230 wlvif->bss_type == BSS_TYPE_IBSS) {
2231 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2232 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2233 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2234 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2235 } else {
2236 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2237 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2238 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2239 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2240 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2241 wl12xx_free_rate_policy(wl,
2242 &wlvif->ap.ucast_rate_idx[i]);
2243 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002244
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002245 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002246 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002247 if (wl->last_wlvif == wlvif)
2248 wl->last_wlvif = NULL;
Eliad Peller87627212011-10-10 10:12:54 +02002249 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002250 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002251 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002252 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d12009-10-12 15:08:43 +03002253
Eliad Pellera4e41302011-10-11 11:49:15 +02002254 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2255 wl->ap_count--;
2256 else
2257 wl->sta_count--;
2258
Eliad Pellerbaf62772011-10-10 10:12:52 +02002259 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002260
Eliad Peller9eb599e2011-10-10 10:12:59 +02002261 del_timer_sync(&wlvif->rx_streaming_timer);
2262 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2263 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002264
Eliad Pellerbaf62772011-10-10 10:12:52 +02002265 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002266}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002267
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002268static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2269 struct ieee80211_vif *vif)
2270{
2271 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002272 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002273 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002274
2275 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002276
2277 if (wl->state == WL1271_STATE_OFF ||
2278 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2279 goto out;
2280
Juuso Oikarinen67353292010-11-18 15:19:02 +02002281 /*
2282 * wl->vif can be null here if someone shuts down the interface
2283 * just when hardware recovery has been started.
2284 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002285 wl12xx_for_each_wlvif(wl, iter) {
2286 if (iter != wlvif)
2287 continue;
2288
Eliad Peller536129c2011-10-05 11:55:45 +02002289 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002290 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002291 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002292 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002293out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002294 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002295 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002296}
2297
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002298static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2299 struct ieee80211_vif *vif,
2300 enum nl80211_iftype new_type, bool p2p)
2301{
2302 wl1271_op_remove_interface(hw, vif);
2303
2304 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2305 vif->p2p = p2p;
2306 return wl1271_op_add_interface(hw, vif);
2307}
2308
Eliad Peller87fbcb02011-10-05 11:55:41 +02002309static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2310 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002311{
2312 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002313 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002314
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002315 /*
2316 * One of the side effects of the JOIN command is that is clears
2317 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2318 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002319 * Currently the only valid scenario for JOIN during association
2320 * is on roaming, in which case we will also be given new keys.
2321 * Keep the below message for now, unless it starts bothering
2322 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002323 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002324 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002325 wl1271_info("JOIN while associated.");
2326
Eliad Peller5ec8a442012-02-02 12:22:09 +02002327 /* clear encryption type */
2328 wlvif->encryption_type = KEY_NONE;
2329
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002330 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002331 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002332
Eliad Peller227e81e2011-08-14 13:17:26 +03002333 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002334 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002335 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002336 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002337 if (ret < 0)
2338 goto out;
2339
Eliad Pellerba8447f2011-10-10 10:13:00 +02002340 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002341 goto out;
2342
2343 /*
2344 * The join command disable the keep-alive mode, shut down its process,
2345 * and also clear the template config, so we need to reset it all after
2346 * the join. The acx_aid starts the keep-alive process, and the order
2347 * of the commands below is relevant.
2348 */
Eliad Peller0603d892011-10-05 11:55:51 +02002349 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 if (ret < 0)
2351 goto out;
2352
Eliad Peller0603d892011-10-05 11:55:51 +02002353 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002354 if (ret < 0)
2355 goto out;
2356
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002357 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002358 if (ret < 0)
2359 goto out;
2360
Eliad Peller0603d892011-10-05 11:55:51 +02002361 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2362 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002363 ACX_KEEP_ALIVE_TPL_VALID);
2364 if (ret < 0)
2365 goto out;
2366
2367out:
2368 return ret;
2369}
2370
Eliad Peller0603d892011-10-05 11:55:51 +02002371static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002372{
2373 int ret;
2374
Eliad Peller52630c52011-10-10 10:13:08 +02002375 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002376 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2377
Shahar Levi6d158ff2011-09-08 13:01:33 +03002378 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002379 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002380 }
2381
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002382 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002383 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002384 if (ret < 0)
2385 goto out;
2386
Oz Krakowskib992c682011-06-26 10:36:02 +03002387 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002388 wlvif->tx_security_last_seq_lsb = 0;
2389 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002390
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002391out:
2392 return ret;
2393}
2394
Eliad Peller87fbcb02011-10-05 11:55:41 +02002395static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396{
Eliad Peller1b92f152011-10-10 10:13:09 +02002397 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002398 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002399}
2400
Eliad Peller87fbcb02011-10-05 11:55:41 +02002401static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2402 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002403{
2404 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002405 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2406
2407 if (idle == cur_idle)
2408 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002409
2410 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002411 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002412 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002413 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002414 if (ret < 0)
2415 goto out;
2416 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002417 wlvif->rate_set =
2418 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2419 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002420 if (ret < 0)
2421 goto out;
2422 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002423 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002424 ACX_KEEP_ALIVE_TPL_INVALID);
2425 if (ret < 0)
2426 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002427 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002428 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002429 /* The current firmware only supports sched_scan in idle */
2430 if (wl->sched_scanning) {
2431 wl1271_scan_sched_scan_stop(wl);
2432 ieee80211_sched_scan_stopped(wl->hw);
2433 }
2434
Eliad Peller679a6732011-10-11 11:55:44 +02002435 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002436 if (ret < 0)
2437 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002438 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002439 }
2440
2441out:
2442 return ret;
2443}
2444
Eliad Peller9f259c42011-10-10 10:13:12 +02002445static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2446 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447{
Eliad Peller9f259c42011-10-10 10:13:12 +02002448 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2449 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002450
2451 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2452
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002453 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002454 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002455 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002456 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002457 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002458 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002459 wlvif->band = conf->channel->band;
2460 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002461
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002462 if (!is_ap) {
2463 /*
2464 * FIXME: the mac80211 should really provide a fixed
2465 * rate to use here. for now, just use the smallest
2466 * possible rate for the band as a fixed rate for
2467 * association frames and other control messages.
2468 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002469 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002470 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002472 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002473 wl1271_tx_min_rate_get(wl,
2474 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002475 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002476 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002477 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002478 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002479
Eliad Pellerba8447f2011-10-10 10:13:00 +02002480 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2481 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002482 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002483 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002484 ret = wl12xx_croc(wl,
2485 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002486 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002487 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002488 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002489 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002490 if (ret < 0)
2491 wl1271_warning("cmd join on channel "
2492 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002493 } else {
2494 /*
2495 * change the ROC channel. do it only if we are
2496 * not idle. otherwise, CROC will be called
2497 * anyway.
2498 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002499 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002500 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002501 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002503 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002504
Eliad Peller679a6732011-10-11 11:55:44 +02002505 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002506 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002507 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002508 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002509 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002510 }
2511 }
2512
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002513 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002514
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002515 if ((conf->flags & IEEE80211_CONF_PS) &&
2516 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002517 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002518
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002519 int ps_mode;
2520 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002521
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002522 if (wl->conf.conn.forced_ps) {
2523 ps_mode = STATION_POWER_SAVE_MODE;
2524 ps_mode_str = "forced";
2525 } else {
2526 ps_mode = STATION_AUTO_PS_MODE;
2527 ps_mode_str = "auto";
2528 }
2529
2530 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2531
2532 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2533
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002534 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002535 wl1271_warning("enter %s ps failed %d",
2536 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002538 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002539 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002541 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2542
Eliad Peller0603d892011-10-05 11:55:51 +02002543 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002544 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002545 if (ret < 0)
2546 wl1271_warning("exit auto ps failed %d", ret);
2547 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002548 }
2549
Eliad Peller6bd65022011-10-10 10:13:11 +02002550 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002551 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002552 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002553 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002554
Eliad Peller6bd65022011-10-10 10:13:11 +02002555 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556 }
2557
Eliad Peller9f259c42011-10-10 10:13:12 +02002558 return 0;
2559}
2560
2561static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2562{
2563 struct wl1271 *wl = hw->priv;
2564 struct wl12xx_vif *wlvif;
2565 struct ieee80211_conf *conf = &hw->conf;
2566 int channel, ret = 0;
2567
2568 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2569
2570 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2571 " changed 0x%x",
2572 channel,
2573 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2574 conf->power_level,
2575 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2576 changed);
2577
2578 /*
2579 * mac80211 will go to idle nearly immediately after transmitting some
2580 * frames, such as the deauth. To make sure those frames reach the air,
2581 * wait here until the TX queue is fully flushed.
2582 */
2583 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2584 (conf->flags & IEEE80211_CONF_IDLE))
2585 wl1271_tx_flush(wl);
2586
2587 mutex_lock(&wl->mutex);
2588
2589 /* we support configuring the channel and band even while off */
2590 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2591 wl->band = conf->channel->band;
2592 wl->channel = channel;
2593 }
2594
2595 if (changed & IEEE80211_CONF_CHANGE_POWER)
2596 wl->power_level = conf->power_level;
2597
2598 if (unlikely(wl->state == WL1271_STATE_OFF))
2599 goto out;
2600
2601 ret = wl1271_ps_elp_wakeup(wl);
2602 if (ret < 0)
2603 goto out;
2604
2605 /* configure each interface */
2606 wl12xx_for_each_wlvif(wl, wlvif) {
2607 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2608 if (ret < 0)
2609 goto out_sleep;
2610 }
2611
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002612out_sleep:
2613 wl1271_ps_elp_sleep(wl);
2614
2615out:
2616 mutex_unlock(&wl->mutex);
2617
2618 return ret;
2619}
2620
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002621struct wl1271_filter_params {
2622 bool enabled;
2623 int mc_list_length;
2624 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2625};
2626
Jiri Pirko22bedad2010-04-01 21:22:57 +00002627static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2628 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002629{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002630 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002631 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002632 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002633
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002634 if (unlikely(wl->state == WL1271_STATE_OFF))
2635 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002636
Juuso Oikarinen74441132009-10-13 12:47:53 +03002637 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002638 if (!fp) {
2639 wl1271_error("Out of memory setting filters.");
2640 return 0;
2641 }
2642
2643 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002645 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2646 fp->enabled = false;
2647 } else {
2648 fp->enabled = true;
2649 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002650 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002651 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002652 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002653 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002654 }
2655
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002656 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002657}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002658
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002659#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2660 FIF_ALLMULTI | \
2661 FIF_FCSFAIL | \
2662 FIF_BCN_PRBRESP_PROMISC | \
2663 FIF_CONTROL | \
2664 FIF_OTHER_BSS)
2665
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002666static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2667 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002668 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002669{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002670 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002671 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002672 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002673
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002674 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675
Arik Nemtsov7d057862010-10-16 19:25:35 +02002676 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2677 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002678
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002679 mutex_lock(&wl->mutex);
2680
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002681 *total &= WL1271_SUPPORTED_FILTERS;
2682 changed &= WL1271_SUPPORTED_FILTERS;
2683
2684 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002685 goto out;
2686
Ido Yariva6208652011-03-01 15:14:41 +02002687 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002688 if (ret < 0)
2689 goto out;
2690
Eliad Peller6e8cd332011-10-10 10:13:13 +02002691 wl12xx_for_each_wlvif(wl, wlvif) {
2692 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2693 if (*total & FIF_ALLMULTI)
2694 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2695 false,
2696 NULL, 0);
2697 else if (fp)
2698 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2699 fp->enabled,
2700 fp->mc_list,
2701 fp->mc_list_length);
2702 if (ret < 0)
2703 goto out_sleep;
2704 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002705 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002706
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002707 /*
2708 * the fw doesn't provide an api to configure the filters. instead,
2709 * the filters configuration is based on the active roles / ROC
2710 * state.
2711 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002712
2713out_sleep:
2714 wl1271_ps_elp_sleep(wl);
2715
2716out:
2717 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002718 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002719}
2720
Eliad Peller170d0e62011-10-05 11:56:06 +02002721static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2722 u8 id, u8 key_type, u8 key_size,
2723 const u8 *key, u8 hlid, u32 tx_seq_32,
2724 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002725{
2726 struct wl1271_ap_key *ap_key;
2727 int i;
2728
2729 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2730
2731 if (key_size > MAX_KEY_SIZE)
2732 return -EINVAL;
2733
2734 /*
2735 * Find next free entry in ap_keys. Also check we are not replacing
2736 * an existing key.
2737 */
2738 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002739 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002740 break;
2741
Eliad Peller170d0e62011-10-05 11:56:06 +02002742 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002743 wl1271_warning("trying to record key replacement");
2744 return -EINVAL;
2745 }
2746 }
2747
2748 if (i == MAX_NUM_KEYS)
2749 return -EBUSY;
2750
2751 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2752 if (!ap_key)
2753 return -ENOMEM;
2754
2755 ap_key->id = id;
2756 ap_key->key_type = key_type;
2757 ap_key->key_size = key_size;
2758 memcpy(ap_key->key, key, key_size);
2759 ap_key->hlid = hlid;
2760 ap_key->tx_seq_32 = tx_seq_32;
2761 ap_key->tx_seq_16 = tx_seq_16;
2762
Eliad Peller170d0e62011-10-05 11:56:06 +02002763 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002764 return 0;
2765}
2766
Eliad Peller170d0e62011-10-05 11:56:06 +02002767static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002768{
2769 int i;
2770
2771 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 kfree(wlvif->ap.recorded_keys[i]);
2773 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002774 }
2775}
2776
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002777static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778{
2779 int i, ret = 0;
2780 struct wl1271_ap_key *key;
2781 bool wep_key_added = false;
2782
2783 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002784 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002785 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002786 break;
2787
Eliad Peller170d0e62011-10-05 11:56:06 +02002788 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002789 hlid = key->hlid;
2790 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002791 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002792
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002793 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794 key->id, key->key_type,
2795 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002796 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002797 key->tx_seq_16);
2798 if (ret < 0)
2799 goto out;
2800
2801 if (key->key_type == KEY_WEP)
2802 wep_key_added = true;
2803 }
2804
2805 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002806 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002807 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808 if (ret < 0)
2809 goto out;
2810 }
2811
2812out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002813 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002814 return ret;
2815}
2816
Eliad Peller536129c2011-10-05 11:55:45 +02002817static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2818 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002819 u8 key_size, const u8 *key, u32 tx_seq_32,
2820 u16 tx_seq_16, struct ieee80211_sta *sta)
2821{
2822 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002823 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002824
2825 if (is_ap) {
2826 struct wl1271_station *wl_sta;
2827 u8 hlid;
2828
2829 if (sta) {
2830 wl_sta = (struct wl1271_station *)sta->drv_priv;
2831 hlid = wl_sta->hlid;
2832 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002833 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 }
2835
Eliad Peller53d40d02011-10-10 10:13:02 +02002836 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002837 /*
2838 * We do not support removing keys after AP shutdown.
2839 * Pretend we do to make mac80211 happy.
2840 */
2841 if (action != KEY_ADD_OR_REPLACE)
2842 return 0;
2843
Eliad Peller170d0e62011-10-05 11:56:06 +02002844 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002845 key_type, key_size,
2846 key, hlid, tx_seq_32,
2847 tx_seq_16);
2848 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002849 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002850 id, key_type, key_size,
2851 key, hlid, tx_seq_32,
2852 tx_seq_16);
2853 }
2854
2855 if (ret < 0)
2856 return ret;
2857 } else {
2858 const u8 *addr;
2859 static const u8 bcast_addr[ETH_ALEN] = {
2860 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2861 };
2862
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002863 /*
2864 * A STA set to GEM cipher requires 2 tx spare blocks.
2865 * Return to default value when GEM cipher key is removed
2866 */
2867 if (key_type == KEY_GEM) {
2868 if (action == KEY_ADD_OR_REPLACE)
2869 wl->tx_spare_blocks = 2;
2870 else if (action == KEY_REMOVE)
2871 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2872 }
2873
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002874 addr = sta ? sta->addr : bcast_addr;
2875
2876 if (is_zero_ether_addr(addr)) {
2877 /* We dont support TX only encryption */
2878 return -EOPNOTSUPP;
2879 }
2880
2881 /* The wl1271 does not allow to remove unicast keys - they
2882 will be cleared automatically on next CMD_JOIN. Ignore the
2883 request silently, as we dont want the mac80211 to emit
2884 an error message. */
2885 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2886 return 0;
2887
Eliad Peller010d3d32011-08-14 13:17:31 +03002888 /* don't remove key if hlid was already deleted */
2889 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002890 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002891 return 0;
2892
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002893 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002894 id, key_type, key_size,
2895 key, addr, tx_seq_32,
2896 tx_seq_16);
2897 if (ret < 0)
2898 return ret;
2899
2900 /* the default WEP key needs to be configured at least once */
2901 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002902 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002903 wlvif->default_key,
2904 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002905 if (ret < 0)
2906 return ret;
2907 }
2908 }
2909
2910 return 0;
2911}
2912
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002913static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2914 struct ieee80211_vif *vif,
2915 struct ieee80211_sta *sta,
2916 struct ieee80211_key_conf *key_conf)
2917{
2918 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002919 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002921 u32 tx_seq_32 = 0;
2922 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002923 u8 key_type;
2924
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2926
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002927 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002929 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 key_conf->keylen, key_conf->flags);
2931 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2932
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002933 mutex_lock(&wl->mutex);
2934
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002935 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2936 ret = -EAGAIN;
2937 goto out_unlock;
2938 }
2939
Ido Yariva6208652011-03-01 15:14:41 +02002940 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 if (ret < 0)
2942 goto out_unlock;
2943
Johannes Berg97359d12010-08-10 09:46:38 +02002944 switch (key_conf->cipher) {
2945 case WLAN_CIPHER_SUITE_WEP40:
2946 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002947 key_type = KEY_WEP;
2948
2949 key_conf->hw_key_idx = key_conf->keyidx;
2950 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002951 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002952 key_type = KEY_TKIP;
2953
2954 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002955 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2956 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002957 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002958 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002959 key_type = KEY_AES;
2960
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002961 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002962 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2963 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002964 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002965 case WL1271_CIPHER_SUITE_GEM:
2966 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002967 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2968 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002969 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002970 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002971 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972
2973 ret = -EOPNOTSUPP;
2974 goto out_sleep;
2975 }
2976
2977 switch (cmd) {
2978 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002979 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002980 key_conf->keyidx, key_type,
2981 key_conf->keylen, key_conf->key,
2982 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002983 if (ret < 0) {
2984 wl1271_error("Could not add or replace key");
2985 goto out_sleep;
2986 }
Eliad Peller5ec8a442012-02-02 12:22:09 +02002987
2988 /*
2989 * reconfiguring arp response if the unicast (or common)
2990 * encryption key type was changed
2991 */
2992 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
2993 (sta || key_type == KEY_WEP) &&
2994 wlvif->encryption_type != key_type) {
2995 wlvif->encryption_type = key_type;
2996 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
2997 if (ret < 0) {
2998 wl1271_warning("build arp rsp failed: %d", ret);
2999 goto out_sleep;
3000 }
3001 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003002 break;
3003
3004 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02003005 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003006 key_conf->keyidx, key_type,
3007 key_conf->keylen, key_conf->key,
3008 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 if (ret < 0) {
3010 wl1271_error("Could not remove key");
3011 goto out_sleep;
3012 }
3013 break;
3014
3015 default:
3016 wl1271_error("Unsupported key cmd 0x%x", cmd);
3017 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 break;
3019 }
3020
3021out_sleep:
3022 wl1271_ps_elp_sleep(wl);
3023
3024out_unlock:
3025 mutex_unlock(&wl->mutex);
3026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 return ret;
3028}
3029
3030static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003031 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 struct cfg80211_scan_request *req)
3033{
3034 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003035 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037 int ret;
3038 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003039 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040
3041 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3042
3043 if (req->n_ssids) {
3044 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003045 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 }
3047
3048 mutex_lock(&wl->mutex);
3049
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003050 if (wl->state == WL1271_STATE_OFF) {
3051 /*
3052 * We cannot return -EBUSY here because cfg80211 will expect
3053 * a call to ieee80211_scan_completed if we do - in this case
3054 * there won't be any call.
3055 */
3056 ret = -EAGAIN;
3057 goto out;
3058 }
3059
Ido Yariva6208652011-03-01 15:14:41 +02003060 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 if (ret < 0)
3062 goto out;
3063
Eliad Peller92e712d2011-12-18 20:25:43 +02003064 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3065 test_bit(wlvif->role_id, wl->roc_map)) {
3066 /* don't allow scanning right now */
3067 ret = -EBUSY;
3068 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003069 }
3070
Eliad Peller92e712d2011-12-18 20:25:43 +02003071 /* cancel ROC before scanning */
3072 if (wl12xx_dev_role_started(wlvif))
Eliad Pellerc059beb2012-01-31 11:57:17 +02003073 wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller92e712d2011-12-18 20:25:43 +02003074
Eliad Peller784f6942011-10-05 11:55:39 +02003075 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003076out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003078out:
3079 mutex_unlock(&wl->mutex);
3080
3081 return ret;
3082}
3083
Eliad Peller73ecce32011-06-27 13:06:45 +03003084static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3085 struct ieee80211_vif *vif)
3086{
3087 struct wl1271 *wl = hw->priv;
3088 int ret;
3089
3090 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3091
3092 mutex_lock(&wl->mutex);
3093
3094 if (wl->state == WL1271_STATE_OFF)
3095 goto out;
3096
3097 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3098 goto out;
3099
3100 ret = wl1271_ps_elp_wakeup(wl);
3101 if (ret < 0)
3102 goto out;
3103
3104 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3105 ret = wl1271_scan_stop(wl);
3106 if (ret < 0)
3107 goto out_sleep;
3108 }
3109 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3110 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003111 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003112 wl->scan.req = NULL;
3113 ieee80211_scan_completed(wl->hw, true);
3114
3115out_sleep:
3116 wl1271_ps_elp_sleep(wl);
3117out:
3118 mutex_unlock(&wl->mutex);
3119
3120 cancel_delayed_work_sync(&wl->scan_complete_work);
3121}
3122
Luciano Coelho33c2c062011-05-10 14:46:02 +03003123static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3124 struct ieee80211_vif *vif,
3125 struct cfg80211_sched_scan_request *req,
3126 struct ieee80211_sched_scan_ies *ies)
3127{
3128 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003129 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003130 int ret;
3131
3132 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3133
3134 mutex_lock(&wl->mutex);
3135
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003136 if (wl->state == WL1271_STATE_OFF) {
3137 ret = -EAGAIN;
3138 goto out;
3139 }
3140
Luciano Coelho33c2c062011-05-10 14:46:02 +03003141 ret = wl1271_ps_elp_wakeup(wl);
3142 if (ret < 0)
3143 goto out;
3144
Eliad Peller536129c2011-10-05 11:55:45 +02003145 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003146 if (ret < 0)
3147 goto out_sleep;
3148
Eliad Peller536129c2011-10-05 11:55:45 +02003149 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003150 if (ret < 0)
3151 goto out_sleep;
3152
3153 wl->sched_scanning = true;
3154
3155out_sleep:
3156 wl1271_ps_elp_sleep(wl);
3157out:
3158 mutex_unlock(&wl->mutex);
3159 return ret;
3160}
3161
3162static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3163 struct ieee80211_vif *vif)
3164{
3165 struct wl1271 *wl = hw->priv;
3166 int ret;
3167
3168 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3169
3170 mutex_lock(&wl->mutex);
3171
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003172 if (wl->state == WL1271_STATE_OFF)
3173 goto out;
3174
Luciano Coelho33c2c062011-05-10 14:46:02 +03003175 ret = wl1271_ps_elp_wakeup(wl);
3176 if (ret < 0)
3177 goto out;
3178
3179 wl1271_scan_sched_scan_stop(wl);
3180
3181 wl1271_ps_elp_sleep(wl);
3182out:
3183 mutex_unlock(&wl->mutex);
3184}
3185
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003186static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3187{
3188 struct wl1271 *wl = hw->priv;
3189 int ret = 0;
3190
3191 mutex_lock(&wl->mutex);
3192
3193 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3194 ret = -EAGAIN;
3195 goto out;
3196 }
3197
Ido Yariva6208652011-03-01 15:14:41 +02003198 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003199 if (ret < 0)
3200 goto out;
3201
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003202 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 if (ret < 0)
3204 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3205
3206 wl1271_ps_elp_sleep(wl);
3207
3208out:
3209 mutex_unlock(&wl->mutex);
3210
3211 return ret;
3212}
3213
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003214static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3215{
3216 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003217 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003218 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219
3220 mutex_lock(&wl->mutex);
3221
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003222 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3223 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003224 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003225 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003226
Ido Yariva6208652011-03-01 15:14:41 +02003227 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 if (ret < 0)
3229 goto out;
3230
Eliad Peller6e8cd332011-10-10 10:13:13 +02003231 wl12xx_for_each_wlvif(wl, wlvif) {
3232 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3233 if (ret < 0)
3234 wl1271_warning("set rts threshold failed: %d", ret);
3235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236 wl1271_ps_elp_sleep(wl);
3237
3238out:
3239 mutex_unlock(&wl->mutex);
3240
3241 return ret;
3242}
3243
Eliad Peller1fe9f162011-10-05 11:55:48 +02003244static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003245 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003246{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003247 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003248 u8 ssid_len;
3249 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3250 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003251
Eliad Peller889cb362011-05-01 09:56:45 +03003252 if (!ptr) {
3253 wl1271_error("No SSID in IEs!");
3254 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003255 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003256
Eliad Peller889cb362011-05-01 09:56:45 +03003257 ssid_len = ptr[1];
3258 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3259 wl1271_error("SSID is too long!");
3260 return -EINVAL;
3261 }
3262
Eliad Peller1fe9f162011-10-05 11:55:48 +02003263 wlvif->ssid_len = ssid_len;
3264 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003265 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003266}
3267
Eliad Pellerd48055d2011-09-15 12:07:04 +03003268static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3269{
3270 int len;
3271 const u8 *next, *end = skb->data + skb->len;
3272 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3273 skb->len - ieoffset);
3274 if (!ie)
3275 return;
3276 len = ie[1] + 2;
3277 next = ie + len;
3278 memmove(ie, next, end - next);
3279 skb_trim(skb, skb->len - len);
3280}
3281
Eliad Peller26b4bf22011-09-15 12:07:05 +03003282static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3283 unsigned int oui, u8 oui_type,
3284 int ieoffset)
3285{
3286 int len;
3287 const u8 *next, *end = skb->data + skb->len;
3288 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3289 skb->data + ieoffset,
3290 skb->len - ieoffset);
3291 if (!ie)
3292 return;
3293 len = ie[1] + 2;
3294 next = ie + len;
3295 memmove(ie, next, end - next);
3296 skb_trim(skb, skb->len - len);
3297}
3298
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003299static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3300 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003301{
Eliad Pellercdaac622012-01-31 11:57:16 +02003302 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003303 struct sk_buff *skb;
3304 int ret;
3305
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003306 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003307 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003308 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003309
Eliad Pellercdaac622012-01-31 11:57:16 +02003310 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003311 CMD_TEMPL_AP_PROBE_RESPONSE,
3312 skb->data,
3313 skb->len, 0,
3314 rates);
3315
3316 dev_kfree_skb(skb);
3317 return ret;
3318}
3319
3320static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3321 struct ieee80211_vif *vif,
3322 u8 *probe_rsp_data,
3323 size_t probe_rsp_len,
3324 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003325{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003326 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3327 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003328 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3329 int ssid_ie_offset, ie_offset, templ_len;
3330 const u8 *ptr;
3331
3332 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003333 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003334 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003335 CMD_TEMPL_AP_PROBE_RESPONSE,
3336 probe_rsp_data,
3337 probe_rsp_len, 0,
3338 rates);
3339
3340 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3341 wl1271_error("probe_rsp template too big");
3342 return -EINVAL;
3343 }
3344
3345 /* start searching from IE offset */
3346 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3347
3348 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3349 probe_rsp_len - ie_offset);
3350 if (!ptr) {
3351 wl1271_error("No SSID in beacon!");
3352 return -EINVAL;
3353 }
3354
3355 ssid_ie_offset = ptr - probe_rsp_data;
3356 ptr += (ptr[1] + 2);
3357
3358 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3359
3360 /* insert SSID from bss_conf */
3361 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3362 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3363 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3364 bss_conf->ssid, bss_conf->ssid_len);
3365 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3366
3367 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3368 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3369 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3370
Eliad Pellercdaac622012-01-31 11:57:16 +02003371 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003372 CMD_TEMPL_AP_PROBE_RESPONSE,
3373 probe_rsp_templ,
3374 templ_len, 0,
3375 rates);
3376}
3377
Arik Nemtsove78a2872010-10-16 19:07:21 +02003378static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003379 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 struct ieee80211_bss_conf *bss_conf,
3381 u32 changed)
3382{
Eliad Peller0603d892011-10-05 11:55:51 +02003383 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 int ret = 0;
3385
3386 if (changed & BSS_CHANGED_ERP_SLOT) {
3387 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003388 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 else
Eliad Peller0603d892011-10-05 11:55:51 +02003390 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 if (ret < 0) {
3392 wl1271_warning("Set slot time failed %d", ret);
3393 goto out;
3394 }
3395 }
3396
3397 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3398 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003399 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400 else
Eliad Peller0603d892011-10-05 11:55:51 +02003401 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 }
3403
3404 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3405 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003406 ret = wl1271_acx_cts_protect(wl, wlvif,
3407 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 else
Eliad Peller0603d892011-10-05 11:55:51 +02003409 ret = wl1271_acx_cts_protect(wl, wlvif,
3410 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 if (ret < 0) {
3412 wl1271_warning("Set ctsprotect failed %d", ret);
3413 goto out;
3414 }
3415 }
3416
3417out:
3418 return ret;
3419}
3420
3421static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3422 struct ieee80211_vif *vif,
3423 struct ieee80211_bss_conf *bss_conf,
3424 u32 changed)
3425{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003426 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003427 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003428 int ret = 0;
3429
3430 if ((changed & BSS_CHANGED_BEACON_INT)) {
3431 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3432 bss_conf->beacon_int);
3433
Eliad Peller6a899792011-10-05 11:55:58 +02003434 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 }
3436
Arik Nemtsov560f0022011-11-08 18:46:54 +02003437 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3438 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003439 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3440 wl1271_debug(DEBUG_AP, "probe response updated");
3441 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3442 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003443 }
3444
Arik Nemtsove78a2872010-10-16 19:07:21 +02003445 if ((changed & BSS_CHANGED_BEACON)) {
3446 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003447 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 int ieoffset = offsetof(struct ieee80211_mgmt,
3449 u.beacon.variable);
3450 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3451 u16 tmpl_id;
3452
Arik Nemtsov560f0022011-11-08 18:46:54 +02003453 if (!beacon) {
3454 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003455 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003456 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457
3458 wl1271_debug(DEBUG_MASTER, "beacon updated");
3459
Eliad Peller1fe9f162011-10-05 11:55:48 +02003460 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003461 if (ret < 0) {
3462 dev_kfree_skb(beacon);
3463 goto out;
3464 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003465 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3467 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003468 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 beacon->data,
3470 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003471 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003472 if (ret < 0) {
3473 dev_kfree_skb(beacon);
3474 goto out;
3475 }
3476
Arik Nemtsov560f0022011-11-08 18:46:54 +02003477 /*
3478 * In case we already have a probe-resp beacon set explicitly
3479 * by usermode, don't use the beacon data.
3480 */
3481 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3482 goto end_bcn;
3483
Eliad Pellerd48055d2011-09-15 12:07:04 +03003484 /* remove TIM ie from probe response */
3485 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3486
Eliad Peller26b4bf22011-09-15 12:07:05 +03003487 /*
3488 * remove p2p ie from probe response.
3489 * the fw reponds to probe requests that don't include
3490 * the p2p ie. probe requests with p2p ie will be passed,
3491 * and will be responded by the supplicant (the spec
3492 * forbids including the p2p ie when responding to probe
3493 * requests that didn't include it).
3494 */
3495 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3496 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3497
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 hdr = (struct ieee80211_hdr *) beacon->data;
3499 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3500 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003501 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003502 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003503 beacon->data,
3504 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003505 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003506 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003507 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003508 CMD_TEMPL_PROBE_RESPONSE,
3509 beacon->data,
3510 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003511 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003512end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 dev_kfree_skb(beacon);
3514 if (ret < 0)
3515 goto out;
3516 }
3517
3518out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003519 if (ret != 0)
3520 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 return ret;
3522}
3523
3524/* AP mode changes */
3525static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003526 struct ieee80211_vif *vif,
3527 struct ieee80211_bss_conf *bss_conf,
3528 u32 changed)
3529{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003530 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
Arik Nemtsove78a2872010-10-16 19:07:21 +02003533 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3534 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003535
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003537 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003538 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003539 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540
Eliad Peller87fbcb02011-10-05 11:55:41 +02003541 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003543 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003544 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003545 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003546
Eliad Peller784f6942011-10-05 11:55:39 +02003547 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003548 if (ret < 0)
3549 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003550 }
3551
Arik Nemtsove78a2872010-10-16 19:07:21 +02003552 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3553 if (ret < 0)
3554 goto out;
3555
3556 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3557 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003558 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003559 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003560 if (ret < 0)
3561 goto out;
3562
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003563 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003564 if (ret < 0)
3565 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003566
Eliad Peller53d40d02011-10-10 10:13:02 +02003567 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003568 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003569 }
3570 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003571 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003572 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003573 if (ret < 0)
3574 goto out;
3575
Eliad Peller53d40d02011-10-10 10:13:02 +02003576 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003577 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3578 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 wl1271_debug(DEBUG_AP, "stopped AP");
3580 }
3581 }
3582 }
3583
Eliad Peller0603d892011-10-05 11:55:51 +02003584 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003585 if (ret < 0)
3586 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003587
3588 /* Handle HT information change */
3589 if ((changed & BSS_CHANGED_HT) &&
3590 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003591 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003592 bss_conf->ht_operation_mode);
3593 if (ret < 0) {
3594 wl1271_warning("Set ht information failed %d", ret);
3595 goto out;
3596 }
3597 }
3598
Arik Nemtsove78a2872010-10-16 19:07:21 +02003599out:
3600 return;
3601}
3602
3603/* STA/IBSS mode changes */
3604static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3605 struct ieee80211_vif *vif,
3606 struct ieee80211_bss_conf *bss_conf,
3607 u32 changed)
3608{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003609 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003611 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003613 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003614 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003615 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003616 bool sta_exists = false;
3617 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618
3619 if (is_ibss) {
3620 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3621 changed);
3622 if (ret < 0)
3623 goto out;
3624 }
3625
Eliad Peller227e81e2011-08-14 13:17:26 +03003626 if (changed & BSS_CHANGED_IBSS) {
3627 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003628 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003629 ibss_joined = true;
3630 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003631 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3632 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003633 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003634 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003635 }
3636 }
3637 }
3638
3639 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003640 do_join = true;
3641
3642 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003643 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003644 do_join = true;
3645
Eliad Peller227e81e2011-08-14 13:17:26 +03003646 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003647 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3648 bss_conf->enable_beacon ? "enabled" : "disabled");
3649
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003650 do_join = true;
3651 }
3652
Eliad Pellerc31e4942011-10-23 08:21:55 +02003653 if (changed & BSS_CHANGED_IDLE) {
3654 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3655 if (ret < 0)
3656 wl1271_warning("idle mode change failed %d", ret);
3657 }
3658
Arik Nemtsove78a2872010-10-16 19:07:21 +02003659 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003660 bool enable = false;
3661 if (bss_conf->cqm_rssi_thold)
3662 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003663 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003664 bss_conf->cqm_rssi_thold,
3665 bss_conf->cqm_rssi_hyst);
3666 if (ret < 0)
3667 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003668 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003669 }
3670
Eliad Peller7db4ee62012-01-24 18:18:42 +02003671 if (changed & BSS_CHANGED_BSSID &&
3672 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003673 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003674 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003675 if (ret < 0)
3676 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003677
Eliad Peller784f6942011-10-05 11:55:39 +02003678 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003679 if (ret < 0)
3680 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003681
Eliad Pellerfa287b82010-12-26 09:27:50 +01003682 /* Need to update the BSSID (for filtering etc) */
3683 do_join = true;
3684 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003685
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003686 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3687 rcu_read_lock();
3688 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3689 if (!sta)
3690 goto sta_not_found;
3691
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003692 /* save the supp_rates of the ap */
3693 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3694 if (sta->ht_cap.ht_supported)
3695 sta_rate_set |=
3696 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003697 sta_ht_cap = sta->ht_cap;
3698 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003700sta_not_found:
3701 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003702 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003703
Arik Nemtsove78a2872010-10-16 19:07:21 +02003704 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003706 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003707 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003708 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003709 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003711 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003712 * use basic rates from AP, and determine lowest rate
3713 * to use with control frames.
3714 */
3715 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003716 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003717 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003718 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003719 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003720 wl1271_tx_min_rate_get(wl,
3721 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003722 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003723 wlvif->rate_set =
3724 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003725 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003726 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003727 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003728 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003729 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003730
3731 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003732 * with wl1271, we don't need to update the
3733 * beacon_int and dtim_period, because the firmware
3734 * updates it by itself when the first beacon is
3735 * received after a join.
3736 */
Eliad Peller6840e372011-10-05 11:55:50 +02003737 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003738 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003739 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003740
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003741 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003742 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003743 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003744 dev_kfree_skb(wlvif->probereq);
3745 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003746 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003747 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003748 ieoffset = offsetof(struct ieee80211_mgmt,
3749 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003750 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003751
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003752 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003753 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003754 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003755 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003756 } else {
3757 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003758 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003759 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3760 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003761 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003762 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3763 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003764 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003765
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003766 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003767 dev_kfree_skb(wlvif->probereq);
3768 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003769
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003770 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003771 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003772 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003773 wl1271_tx_min_rate_get(wl,
3774 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003775 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003776 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003777 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003778
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003779 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003780 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003781
3782 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003783 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003784 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003785 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003786
3787 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003788 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003789 u32 conf_flags = wl->hw->conf.flags;
3790 /*
3791 * we might have to disable roc, if there was
3792 * no IF_OPER_UP notification.
3793 */
3794 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003795 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003796 if (ret < 0)
3797 goto out;
3798 }
3799 /*
3800 * (we also need to disable roc in case of
3801 * roaming on the same channel. until we will
3802 * have a better flow...)
3803 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003804 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3805 ret = wl12xx_croc(wl,
3806 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003807 if (ret < 0)
3808 goto out;
3809 }
3810
Eliad Peller0603d892011-10-05 11:55:51 +02003811 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003812 if (!(conf_flags & IEEE80211_CONF_IDLE))
3813 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003814 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003815 }
3816 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003817
Eliad Pellerd192d262011-05-24 14:33:08 +03003818 if (changed & BSS_CHANGED_IBSS) {
3819 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3820 bss_conf->ibss_joined);
3821
3822 if (bss_conf->ibss_joined) {
3823 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003824 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003825 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003826 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003827 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003828 wl1271_tx_min_rate_get(wl,
3829 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003830
Shahar Levi06b660e2011-09-05 13:54:36 +03003831 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003832 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3833 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003834 if (ret < 0)
3835 goto out;
3836 }
3837 }
3838
Eliad Peller0603d892011-10-05 11:55:51 +02003839 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003840 if (ret < 0)
3841 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003842
Eliad Peller5ec8a442012-02-02 12:22:09 +02003843 if ((changed & BSS_CHANGED_ARP_FILTER) ||
3844 (!is_ibss && (changed & BSS_CHANGED_QOS))) {
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003845 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller5ec8a442012-02-02 12:22:09 +02003846 wlvif->sta.qos = bss_conf->qos;
Eliad Peller536129c2011-10-05 11:55:45 +02003847 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003848
Eliad Pellerc5312772010-12-09 11:31:27 +02003849 if (bss_conf->arp_addr_cnt == 1 &&
3850 bss_conf->arp_filter_enabled) {
Eliad Peller5ec8a442012-02-02 12:22:09 +02003851 wlvif->ip_addr = addr;
Eliad Pellerc5312772010-12-09 11:31:27 +02003852 /*
3853 * The template should have been configured only upon
3854 * association. however, it seems that the correct ip
3855 * isn't being set (when sending), so we have to
3856 * reconfigure the template upon every ip change.
3857 */
Eliad Peller5ec8a442012-02-02 12:22:09 +02003858 ret = wl1271_cmd_build_arp_rsp(wl, wlvif);
Eliad Pellerc5312772010-12-09 11:31:27 +02003859 if (ret < 0) {
3860 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003861 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003862 }
3863
Eliad Peller0603d892011-10-05 11:55:51 +02003864 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003865 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003866 addr);
Eliad Peller5ec8a442012-02-02 12:22:09 +02003867 } else {
3868 wlvif->ip_addr = 0;
Eliad Peller0603d892011-10-05 11:55:51 +02003869 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Eliad Peller5ec8a442012-02-02 12:22:09 +02003870 }
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003871
3872 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003873 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003874 }
3875
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003876 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003877 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003878 if (ret < 0) {
3879 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003880 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003881 }
Eliad Peller251c1772011-08-14 13:17:17 +03003882
3883 /* ROC until connected (after EAPOL exchange) */
3884 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003885 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003886 if (ret < 0)
3887 goto out;
3888
Eliad Pellerba8447f2011-10-10 10:13:00 +02003889 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003890 ieee80211_get_operstate(vif));
3891 }
3892 /*
3893 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003894 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003895 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003896 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003897 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003898 if (ret < 0)
3899 goto out;
3900 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003901 }
3902
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003903 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003904 if (sta_exists) {
3905 if ((changed & BSS_CHANGED_HT) &&
3906 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003907 ret = wl1271_acx_set_ht_capabilities(wl,
3908 &sta_ht_cap,
3909 true,
Eliad Peller154da672011-10-05 11:55:53 +02003910 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003911 if (ret < 0) {
3912 wl1271_warning("Set ht cap true failed %d",
3913 ret);
3914 goto out;
3915 }
3916 }
3917 /* handle new association without HT and disassociation */
3918 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003919 ret = wl1271_acx_set_ht_capabilities(wl,
3920 &sta_ht_cap,
3921 false,
Eliad Peller154da672011-10-05 11:55:53 +02003922 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003923 if (ret < 0) {
3924 wl1271_warning("Set ht cap false failed %d",
3925 ret);
3926 goto out;
3927 }
3928 }
3929 }
3930
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003931 /* Handle HT information change. Done after join. */
3932 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003933 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003934 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003935 bss_conf->ht_operation_mode);
3936 if (ret < 0) {
3937 wl1271_warning("Set ht information failed %d", ret);
3938 goto out;
3939 }
3940 }
3941
Arik Nemtsove78a2872010-10-16 19:07:21 +02003942out:
3943 return;
3944}
3945
3946static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3947 struct ieee80211_vif *vif,
3948 struct ieee80211_bss_conf *bss_conf,
3949 u32 changed)
3950{
3951 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003952 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3953 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003954 int ret;
3955
3956 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3957 (int)changed);
3958
3959 mutex_lock(&wl->mutex);
3960
3961 if (unlikely(wl->state == WL1271_STATE_OFF))
3962 goto out;
3963
Eliad Peller10c8cd02011-10-10 10:13:06 +02003964 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3965 goto out;
3966
Ido Yariva6208652011-03-01 15:14:41 +02003967 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003968 if (ret < 0)
3969 goto out;
3970
3971 if (is_ap)
3972 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3973 else
3974 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3975
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003976 wl1271_ps_elp_sleep(wl);
3977
3978out:
3979 mutex_unlock(&wl->mutex);
3980}
3981
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003982static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3983 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003984 const struct ieee80211_tx_queue_params *params)
3985{
3986 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003987 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003988 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003989 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003990
3991 mutex_lock(&wl->mutex);
3992
3993 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3994
Kalle Valo4695dc92010-03-18 12:26:38 +02003995 if (params->uapsd)
3996 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3997 else
3998 ps_scheme = CONF_PS_SCHEME_LEGACY;
3999
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004000 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004001 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004002
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004003 ret = wl1271_ps_elp_wakeup(wl);
4004 if (ret < 0)
4005 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004006
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004007 /*
4008 * the txop is confed in units of 32us by the mac80211,
4009 * we need us
4010 */
Eliad Peller0603d892011-10-05 11:55:51 +02004011 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004012 params->cw_min, params->cw_max,
4013 params->aifs, params->txop << 5);
4014 if (ret < 0)
4015 goto out_sleep;
4016
Eliad Peller0603d892011-10-05 11:55:51 +02004017 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004018 CONF_CHANNEL_TYPE_EDCF,
4019 wl1271_tx_get_queue(queue),
4020 ps_scheme, CONF_ACK_POLICY_LEGACY,
4021 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004022
4023out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004024 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004025
4026out:
4027 mutex_unlock(&wl->mutex);
4028
4029 return ret;
4030}
4031
Eliad Peller37a41b42011-09-21 14:06:11 +03004032static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4033 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004034{
4035
4036 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004037 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004038 u64 mactime = ULLONG_MAX;
4039 int ret;
4040
4041 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4042
4043 mutex_lock(&wl->mutex);
4044
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004045 if (unlikely(wl->state == WL1271_STATE_OFF))
4046 goto out;
4047
Ido Yariva6208652011-03-01 15:14:41 +02004048 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004049 if (ret < 0)
4050 goto out;
4051
Eliad Peller9c531142012-01-31 11:57:18 +02004052 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004053 if (ret < 0)
4054 goto out_sleep;
4055
4056out_sleep:
4057 wl1271_ps_elp_sleep(wl);
4058
4059out:
4060 mutex_unlock(&wl->mutex);
4061 return mactime;
4062}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004063
John W. Linvilleece550d2010-07-28 16:41:06 -04004064static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4065 struct survey_info *survey)
4066{
4067 struct wl1271 *wl = hw->priv;
4068 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004069
John W. Linvilleece550d2010-07-28 16:41:06 -04004070 if (idx != 0)
4071 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004072
John W. Linvilleece550d2010-07-28 16:41:06 -04004073 survey->channel = conf->channel;
4074 survey->filled = SURVEY_INFO_NOISE_DBM;
4075 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004076
John W. Linvilleece550d2010-07-28 16:41:06 -04004077 return 0;
4078}
4079
Arik Nemtsov409622e2011-02-23 00:22:29 +02004080static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004081 struct wl12xx_vif *wlvif,
4082 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083{
4084 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004086
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004087
4088 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004089 wl1271_warning("could not allocate HLID - too much stations");
4090 return -EBUSY;
4091 }
4092
4093 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004094 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4095 if (ret < 0) {
4096 wl1271_warning("could not allocate HLID - too many links");
4097 return -EBUSY;
4098 }
4099
4100 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004101 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004102 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004103 return 0;
4104}
4105
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004106void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004107{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004108 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004109 return;
4110
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004111 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004112 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004113 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004114 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004115 __clear_bit(hlid, &wl->ap_ps_map);
4116 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004117 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004118 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119}
4120
4121static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4122 struct ieee80211_vif *vif,
4123 struct ieee80211_sta *sta)
4124{
4125 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004126 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004127 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128 int ret = 0;
4129 u8 hlid;
4130
4131 mutex_lock(&wl->mutex);
4132
4133 if (unlikely(wl->state == WL1271_STATE_OFF))
4134 goto out;
4135
Eliad Peller536129c2011-10-05 11:55:45 +02004136 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004137 goto out;
4138
4139 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4140
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004141 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004142 if (ret < 0)
4143 goto out;
4144
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004145 wl_sta = (struct wl1271_station *)sta->drv_priv;
4146 hlid = wl_sta->hlid;
4147
Ido Yariva6208652011-03-01 15:14:41 +02004148 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004150 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004151
Eliad Peller1b92f152011-10-10 10:13:09 +02004152 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004153 if (ret < 0)
4154 goto out_sleep;
4155
Eliad Pellerb67476e2011-08-14 13:17:23 +03004156 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4157 if (ret < 0)
4158 goto out_sleep;
4159
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004160 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4161 if (ret < 0)
4162 goto out_sleep;
4163
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004164out_sleep:
4165 wl1271_ps_elp_sleep(wl);
4166
Arik Nemtsov409622e2011-02-23 00:22:29 +02004167out_free_sta:
4168 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004169 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004170
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004171out:
4172 mutex_unlock(&wl->mutex);
4173 return ret;
4174}
4175
4176static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4177 struct ieee80211_vif *vif,
4178 struct ieee80211_sta *sta)
4179{
4180 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004181 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004182 struct wl1271_station *wl_sta;
4183 int ret = 0, id;
4184
4185 mutex_lock(&wl->mutex);
4186
4187 if (unlikely(wl->state == WL1271_STATE_OFF))
4188 goto out;
4189
Eliad Peller536129c2011-10-05 11:55:45 +02004190 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004191 goto out;
4192
4193 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4194
4195 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004196 id = wl_sta->hlid;
4197 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004198 goto out;
4199
Ido Yariva6208652011-03-01 15:14:41 +02004200 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004201 if (ret < 0)
4202 goto out;
4203
Eliad Pellerc690ec82011-08-14 13:17:07 +03004204 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004205 if (ret < 0)
4206 goto out_sleep;
4207
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004208 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004209
4210out_sleep:
4211 wl1271_ps_elp_sleep(wl);
4212
4213out:
4214 mutex_unlock(&wl->mutex);
4215 return ret;
4216}
4217
Luciano Coelho4623ec72011-03-21 19:26:41 +02004218static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4219 struct ieee80211_vif *vif,
4220 enum ieee80211_ampdu_mlme_action action,
4221 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4222 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004223{
4224 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004225 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004226 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004227 u8 hlid, *ba_bitmap;
4228
4229 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4230 tid);
4231
4232 /* sanity check - the fields in FW are only 8bits wide */
4233 if (WARN_ON(tid > 0xFF))
4234 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235
4236 mutex_lock(&wl->mutex);
4237
4238 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4239 ret = -EAGAIN;
4240 goto out;
4241 }
4242
Eliad Peller536129c2011-10-05 11:55:45 +02004243 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004244 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004245 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004246 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004247 struct wl1271_station *wl_sta;
4248
4249 wl_sta = (struct wl1271_station *)sta->drv_priv;
4250 hlid = wl_sta->hlid;
4251 ba_bitmap = &wl->links[hlid].ba_bitmap;
4252 } else {
4253 ret = -EINVAL;
4254 goto out;
4255 }
4256
Ido Yariva6208652011-03-01 15:14:41 +02004257 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004258 if (ret < 0)
4259 goto out;
4260
Shahar Levi70559a02011-05-22 16:10:22 +03004261 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4262 tid, action);
4263
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004264 switch (action) {
4265 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004266 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004267 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004268 break;
4269 }
4270
4271 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4272 ret = -EBUSY;
4273 wl1271_error("exceeded max RX BA sessions");
4274 break;
4275 }
4276
4277 if (*ba_bitmap & BIT(tid)) {
4278 ret = -EINVAL;
4279 wl1271_error("cannot enable RX BA session on active "
4280 "tid: %d", tid);
4281 break;
4282 }
4283
4284 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4285 hlid);
4286 if (!ret) {
4287 *ba_bitmap |= BIT(tid);
4288 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004289 }
4290 break;
4291
4292 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004293 if (!(*ba_bitmap & BIT(tid))) {
4294 ret = -EINVAL;
4295 wl1271_error("no active RX BA session on tid: %d",
4296 tid);
4297 break;
4298 }
4299
4300 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4301 hlid);
4302 if (!ret) {
4303 *ba_bitmap &= ~BIT(tid);
4304 wl->ba_rx_session_count--;
4305 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004306 break;
4307
4308 /*
4309 * The BA initiator session management in FW independently.
4310 * Falling break here on purpose for all TX APDU commands.
4311 */
4312 case IEEE80211_AMPDU_TX_START:
4313 case IEEE80211_AMPDU_TX_STOP:
4314 case IEEE80211_AMPDU_TX_OPERATIONAL:
4315 ret = -EINVAL;
4316 break;
4317
4318 default:
4319 wl1271_error("Incorrect ampdu action id=%x\n", action);
4320 ret = -EINVAL;
4321 }
4322
4323 wl1271_ps_elp_sleep(wl);
4324
4325out:
4326 mutex_unlock(&wl->mutex);
4327
4328 return ret;
4329}
4330
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004331static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4332 struct ieee80211_vif *vif,
4333 const struct cfg80211_bitrate_mask *mask)
4334{
Eliad Peller83587502011-10-10 10:12:53 +02004335 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004337 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004338
4339 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4340 mask->control[NL80211_BAND_2GHZ].legacy,
4341 mask->control[NL80211_BAND_5GHZ].legacy);
4342
4343 mutex_lock(&wl->mutex);
4344
4345 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004346 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004347 wl1271_tx_enabled_rates_get(wl,
4348 mask->control[i].legacy,
4349 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004350
4351 if (unlikely(wl->state == WL1271_STATE_OFF))
4352 goto out;
4353
4354 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4355 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4356
4357 ret = wl1271_ps_elp_wakeup(wl);
4358 if (ret < 0)
4359 goto out;
4360
4361 wl1271_set_band_rate(wl, wlvif);
4362 wlvif->basic_rate =
4363 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4364 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4365
4366 wl1271_ps_elp_sleep(wl);
4367 }
4368out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004369 mutex_unlock(&wl->mutex);
4370
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004371 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004372}
4373
Shahar Levi6d158ff2011-09-08 13:01:33 +03004374static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4375 struct ieee80211_channel_switch *ch_switch)
4376{
4377 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004378 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004379 int ret;
4380
4381 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4382
4383 mutex_lock(&wl->mutex);
4384
4385 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004386 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4387 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4388 ieee80211_chswitch_done(vif, false);
4389 }
4390 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004391 }
4392
4393 ret = wl1271_ps_elp_wakeup(wl);
4394 if (ret < 0)
4395 goto out;
4396
Eliad Peller52630c52011-10-10 10:13:08 +02004397 /* TODO: change mac80211 to pass vif as param */
4398 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004399 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004400
Eliad Peller52630c52011-10-10 10:13:08 +02004401 if (!ret)
4402 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4403 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004404
4405 wl1271_ps_elp_sleep(wl);
4406
4407out:
4408 mutex_unlock(&wl->mutex);
4409}
4410
Arik Nemtsov33437892011-04-26 23:35:39 +03004411static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4412{
4413 struct wl1271 *wl = hw->priv;
4414 bool ret = false;
4415
4416 mutex_lock(&wl->mutex);
4417
4418 if (unlikely(wl->state == WL1271_STATE_OFF))
4419 goto out;
4420
4421 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004422 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004423out:
4424 mutex_unlock(&wl->mutex);
4425
4426 return ret;
4427}
4428
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429/* can't be const, mac80211 writes to this */
4430static struct ieee80211_rate wl1271_rates[] = {
4431 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004435 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4436 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4438 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4442 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004443 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4444 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004445 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4446 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004450 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4451 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004453 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4454 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004455 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004456 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4457 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004458 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004459 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004461 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004462 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004465 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004468 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470};
4471
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004472/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004474 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004475 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004476 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4477 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4478 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004479 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004480 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4481 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4482 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004483 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004484 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4485 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4486 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004487 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004488};
4489
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004490/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004491static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004492 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004493 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004494 7, /* CONF_HW_RXTX_RATE_MCS7 */
4495 6, /* CONF_HW_RXTX_RATE_MCS6 */
4496 5, /* CONF_HW_RXTX_RATE_MCS5 */
4497 4, /* CONF_HW_RXTX_RATE_MCS4 */
4498 3, /* CONF_HW_RXTX_RATE_MCS3 */
4499 2, /* CONF_HW_RXTX_RATE_MCS2 */
4500 1, /* CONF_HW_RXTX_RATE_MCS1 */
4501 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004502
4503 11, /* CONF_HW_RXTX_RATE_54 */
4504 10, /* CONF_HW_RXTX_RATE_48 */
4505 9, /* CONF_HW_RXTX_RATE_36 */
4506 8, /* CONF_HW_RXTX_RATE_24 */
4507
4508 /* TI-specific rate */
4509 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4510
4511 7, /* CONF_HW_RXTX_RATE_18 */
4512 6, /* CONF_HW_RXTX_RATE_12 */
4513 3, /* CONF_HW_RXTX_RATE_11 */
4514 5, /* CONF_HW_RXTX_RATE_9 */
4515 4, /* CONF_HW_RXTX_RATE_6 */
4516 2, /* CONF_HW_RXTX_RATE_5_5 */
4517 1, /* CONF_HW_RXTX_RATE_2 */
4518 0 /* CONF_HW_RXTX_RATE_1 */
4519};
4520
Shahar Levie8b03a22010-10-13 16:09:39 +02004521/* 11n STA capabilities */
4522#define HW_RX_HIGHEST_RATE 72
4523
Shahar Levi00d20102010-11-08 11:20:10 +00004524#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004525 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4526 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004527 .ht_supported = true, \
4528 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4529 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4530 .mcs = { \
4531 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4532 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4533 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4534 }, \
4535}
4536
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004537/* can't be const, mac80211 writes to this */
4538static struct ieee80211_supported_band wl1271_band_2ghz = {
4539 .channels = wl1271_channels,
4540 .n_channels = ARRAY_SIZE(wl1271_channels),
4541 .bitrates = wl1271_rates,
4542 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004543 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004544};
4545
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004546/* 5 GHz data rates for WL1273 */
4547static struct ieee80211_rate wl1271_rates_5ghz[] = {
4548 { .bitrate = 60,
4549 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4550 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4551 { .bitrate = 90,
4552 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4553 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4554 { .bitrate = 120,
4555 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4556 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4557 { .bitrate = 180,
4558 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4559 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4560 { .bitrate = 240,
4561 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4562 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4563 { .bitrate = 360,
4564 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4565 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4566 { .bitrate = 480,
4567 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4568 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4569 { .bitrate = 540,
4570 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4571 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4572};
4573
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004574/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004575static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004576 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4577 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4578 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4579 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4580 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4581 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4582 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4583 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4584 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4585 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4586 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4587 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4588 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4589 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4590 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4591 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4592 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4593 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4594 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4595 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4596 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4597 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4598 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4599 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4600 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4601 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4602 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4603 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4604 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4605 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4606 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4607 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4608 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4609 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004610};
4611
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004612/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004613static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004614 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004615 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004616 7, /* CONF_HW_RXTX_RATE_MCS7 */
4617 6, /* CONF_HW_RXTX_RATE_MCS6 */
4618 5, /* CONF_HW_RXTX_RATE_MCS5 */
4619 4, /* CONF_HW_RXTX_RATE_MCS4 */
4620 3, /* CONF_HW_RXTX_RATE_MCS3 */
4621 2, /* CONF_HW_RXTX_RATE_MCS2 */
4622 1, /* CONF_HW_RXTX_RATE_MCS1 */
4623 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004624
4625 7, /* CONF_HW_RXTX_RATE_54 */
4626 6, /* CONF_HW_RXTX_RATE_48 */
4627 5, /* CONF_HW_RXTX_RATE_36 */
4628 4, /* CONF_HW_RXTX_RATE_24 */
4629
4630 /* TI-specific rate */
4631 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4632
4633 3, /* CONF_HW_RXTX_RATE_18 */
4634 2, /* CONF_HW_RXTX_RATE_12 */
4635 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4636 1, /* CONF_HW_RXTX_RATE_9 */
4637 0, /* CONF_HW_RXTX_RATE_6 */
4638 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4639 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4640 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4641};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004642
4643static struct ieee80211_supported_band wl1271_band_5ghz = {
4644 .channels = wl1271_channels_5ghz,
4645 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4646 .bitrates = wl1271_rates_5ghz,
4647 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004648 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004649};
4650
Tobias Klausera0ea9492010-05-20 10:38:11 +02004651static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004652 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4653 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4654};
4655
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004656static const struct ieee80211_ops wl1271_ops = {
4657 .start = wl1271_op_start,
4658 .stop = wl1271_op_stop,
4659 .add_interface = wl1271_op_add_interface,
4660 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004661 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004662#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004663 .suspend = wl1271_op_suspend,
4664 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004665#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004667 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004668 .configure_filter = wl1271_op_configure_filter,
4669 .tx = wl1271_op_tx,
4670 .set_key = wl1271_op_set_key,
4671 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004672 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004673 .sched_scan_start = wl1271_op_sched_scan_start,
4674 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004675 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004676 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004677 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004678 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004679 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004680 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004681 .sta_add = wl1271_op_sta_add,
4682 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004683 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004684 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004685 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004686 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004687 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004688};
4689
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004690
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004691u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004692{
4693 u8 idx;
4694
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004695 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004696
4697 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4698 wl1271_error("Illegal RX rate from HW: %d", rate);
4699 return 0;
4700 }
4701
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004702 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004703 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4704 wl1271_error("Unsupported RX rate from HW: %d", rate);
4705 return 0;
4706 }
4707
4708 return idx;
4709}
4710
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004711static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4712 struct device_attribute *attr,
4713 char *buf)
4714{
4715 struct wl1271 *wl = dev_get_drvdata(dev);
4716 ssize_t len;
4717
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004718 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004719
4720 mutex_lock(&wl->mutex);
4721 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4722 wl->sg_enabled);
4723 mutex_unlock(&wl->mutex);
4724
4725 return len;
4726
4727}
4728
4729static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4730 struct device_attribute *attr,
4731 const char *buf, size_t count)
4732{
4733 struct wl1271 *wl = dev_get_drvdata(dev);
4734 unsigned long res;
4735 int ret;
4736
Luciano Coelho6277ed62011-04-01 17:49:54 +03004737 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004738 if (ret < 0) {
4739 wl1271_warning("incorrect value written to bt_coex_mode");
4740 return count;
4741 }
4742
4743 mutex_lock(&wl->mutex);
4744
4745 res = !!res;
4746
4747 if (res == wl->sg_enabled)
4748 goto out;
4749
4750 wl->sg_enabled = res;
4751
4752 if (wl->state == WL1271_STATE_OFF)
4753 goto out;
4754
Ido Yariva6208652011-03-01 15:14:41 +02004755 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004756 if (ret < 0)
4757 goto out;
4758
4759 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4760 wl1271_ps_elp_sleep(wl);
4761
4762 out:
4763 mutex_unlock(&wl->mutex);
4764 return count;
4765}
4766
4767static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4768 wl1271_sysfs_show_bt_coex_state,
4769 wl1271_sysfs_store_bt_coex_state);
4770
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004771static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4772 struct device_attribute *attr,
4773 char *buf)
4774{
4775 struct wl1271 *wl = dev_get_drvdata(dev);
4776 ssize_t len;
4777
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004778 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004779
4780 mutex_lock(&wl->mutex);
4781 if (wl->hw_pg_ver >= 0)
4782 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4783 else
4784 len = snprintf(buf, len, "n/a\n");
4785 mutex_unlock(&wl->mutex);
4786
4787 return len;
4788}
4789
Gery Kahn6f07b722011-07-18 14:21:49 +03004790static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004791 wl1271_sysfs_show_hw_pg_ver, NULL);
4792
Ido Yariv95dac04f2011-06-06 14:57:06 +03004793static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4794 struct bin_attribute *bin_attr,
4795 char *buffer, loff_t pos, size_t count)
4796{
4797 struct device *dev = container_of(kobj, struct device, kobj);
4798 struct wl1271 *wl = dev_get_drvdata(dev);
4799 ssize_t len;
4800 int ret;
4801
4802 ret = mutex_lock_interruptible(&wl->mutex);
4803 if (ret < 0)
4804 return -ERESTARTSYS;
4805
4806 /* Let only one thread read the log at a time, blocking others */
4807 while (wl->fwlog_size == 0) {
4808 DEFINE_WAIT(wait);
4809
4810 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4811 &wait,
4812 TASK_INTERRUPTIBLE);
4813
4814 if (wl->fwlog_size != 0) {
4815 finish_wait(&wl->fwlog_waitq, &wait);
4816 break;
4817 }
4818
4819 mutex_unlock(&wl->mutex);
4820
4821 schedule();
4822 finish_wait(&wl->fwlog_waitq, &wait);
4823
4824 if (signal_pending(current))
4825 return -ERESTARTSYS;
4826
4827 ret = mutex_lock_interruptible(&wl->mutex);
4828 if (ret < 0)
4829 return -ERESTARTSYS;
4830 }
4831
4832 /* Check if the fwlog is still valid */
4833 if (wl->fwlog_size < 0) {
4834 mutex_unlock(&wl->mutex);
4835 return 0;
4836 }
4837
4838 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4839 len = min(count, (size_t)wl->fwlog_size);
4840 wl->fwlog_size -= len;
4841 memcpy(buffer, wl->fwlog, len);
4842
4843 /* Make room for new messages */
4844 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4845
4846 mutex_unlock(&wl->mutex);
4847
4848 return len;
4849}
4850
4851static struct bin_attribute fwlog_attr = {
4852 .attr = {.name = "fwlog", .mode = S_IRUSR},
4853 .read = wl1271_sysfs_read_fwlog,
4854};
4855
Luciano Coelho5e037e72011-12-23 09:32:17 +02004856static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4857{
4858 bool supported = false;
4859 u8 major, minor;
4860
4861 if (wl->chip.id == CHIP_ID_1283_PG20) {
4862 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4863 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4864
4865 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4866 if (major > 2 || (major == 2 && minor >= 1))
4867 supported = true;
4868 } else {
4869 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4870 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4871
4872 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4873 if (major == 3 && minor >= 1)
4874 supported = true;
4875 }
4876
4877 wl1271_debug(DEBUG_PROBE,
4878 "PG Ver major = %d minor = %d, MAC %s present",
4879 major, minor, supported ? "is" : "is not");
4880
4881 return supported;
4882}
4883
4884static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4885 u32 oui, u32 nic, int n)
4886{
4887 int i;
4888
4889 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4890 oui, nic, n);
4891
4892 if (nic + n - 1 > 0xffffff)
4893 wl1271_warning("NIC part of the MAC address wraps around!");
4894
4895 for (i = 0; i < n; i++) {
4896 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4897 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4898 wl->addresses[i].addr[2] = (u8) oui;
4899 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4900 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4901 wl->addresses[i].addr[5] = (u8) nic;
4902 nic++;
4903 }
4904
4905 wl->hw->wiphy->n_addresses = n;
4906 wl->hw->wiphy->addresses = wl->addresses;
4907}
4908
4909static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4910{
4911 u32 mac1, mac2;
4912
4913 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4914
4915 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4916 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4917
4918 /* these are the two parts of the BD_ADDR */
4919 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4920 ((mac1 & 0xff000000) >> 24);
4921 wl->fuse_nic_addr = mac1 & 0xffffff;
4922
4923 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4924}
4925
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004926static int wl12xx_get_hw_info(struct wl1271 *wl)
4927{
4928 int ret;
4929 u32 die_info;
4930
4931 ret = wl12xx_set_power_on(wl);
4932 if (ret < 0)
4933 goto out;
4934
4935 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4936
4937 if (wl->chip.id == CHIP_ID_1283_PG20)
4938 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4939 else
4940 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4941
4942 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4943
Luciano Coelho5e037e72011-12-23 09:32:17 +02004944 if (!wl12xx_mac_in_fuse(wl)) {
4945 wl->fuse_oui_addr = 0;
4946 wl->fuse_nic_addr = 0;
4947 } else {
4948 wl12xx_get_fuse_mac(wl);
4949 }
4950
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004951 wl1271_power_off(wl);
4952out:
4953 return ret;
4954}
4955
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004956static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004957{
4958 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004959 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004960
4961 if (wl->mac80211_registered)
4962 return 0;
4963
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004964 ret = wl12xx_get_hw_info(wl);
4965 if (ret < 0) {
4966 wl1271_error("couldn't get hw info");
4967 goto out;
4968 }
4969
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004970 ret = wl1271_fetch_nvs(wl);
4971 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004972 /* NOTE: The wl->nvs->nvs element must be first, in
4973 * order to simplify the casting, we assume it is at
4974 * the beginning of the wl->nvs structure.
4975 */
4976 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004977
Luciano Coelho5e037e72011-12-23 09:32:17 +02004978 oui_addr =
4979 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4980 nic_addr =
4981 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004982 }
4983
Luciano Coelho5e037e72011-12-23 09:32:17 +02004984 /* if the MAC address is zeroed in the NVS derive from fuse */
4985 if (oui_addr == 0 && nic_addr == 0) {
4986 oui_addr = wl->fuse_oui_addr;
4987 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4988 nic_addr = wl->fuse_nic_addr + 1;
4989 }
4990
4991 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004992
4993 ret = ieee80211_register_hw(wl->hw);
4994 if (ret < 0) {
4995 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004996 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004997 }
4998
4999 wl->mac80211_registered = true;
5000
Eliad Pellerd60080a2010-11-24 12:53:16 +02005001 wl1271_debugfs_init(wl);
5002
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005003 register_netdevice_notifier(&wl1271_dev_notifier);
5004
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005005 wl1271_notice("loaded");
5006
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005007out:
5008 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005009}
5010
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005011static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005012{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005013 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02005014 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005015
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005016 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005017 ieee80211_unregister_hw(wl->hw);
5018 wl->mac80211_registered = false;
5019
5020}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005021
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005022static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005024 static const u32 cipher_suites[] = {
5025 WLAN_CIPHER_SUITE_WEP40,
5026 WLAN_CIPHER_SUITE_WEP104,
5027 WLAN_CIPHER_SUITE_TKIP,
5028 WLAN_CIPHER_SUITE_CCMP,
5029 WL1271_CIPHER_SUITE_GEM,
5030 };
5031
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005032 /* The tx descriptor buffer and the TKIP space. */
Eliad Peller5ec8a442012-02-02 12:22:09 +02005033 wl->hw->extra_tx_headroom = WL1271_EXTRA_SPACE_TKIP +
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005034 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005035
5036 /* unit us */
5037 /* FIXME: find a proper value */
5038 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005039 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005040
5041 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005042 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005043 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005044 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005045 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005046 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005047 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005048 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005049 IEEE80211_HW_AP_LINK_PS |
5050 IEEE80211_HW_AMPDU_AGGREGATION |
5051 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
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 */
Eliad Peller154037d2011-08-14 13:17:12 +03005067 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005068 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005069
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005070 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5071 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>");