blob: b828149a1655db6f73ee47d9606ddb79f336073c [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
2327 if (set_assoc)
Eliad Pellerba8447f2011-10-10 10:13:00 +02002328 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002329
Eliad Peller227e81e2011-08-14 13:17:26 +03002330 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002331 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002332 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002333 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002334 if (ret < 0)
2335 goto out;
2336
Eliad Pellerba8447f2011-10-10 10:13:00 +02002337 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002338 goto out;
2339
2340 /*
2341 * The join command disable the keep-alive mode, shut down its process,
2342 * and also clear the template config, so we need to reset it all after
2343 * the join. The acx_aid starts the keep-alive process, and the order
2344 * of the commands below is relevant.
2345 */
Eliad Peller0603d892011-10-05 11:55:51 +02002346 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002347 if (ret < 0)
2348 goto out;
2349
Eliad Peller0603d892011-10-05 11:55:51 +02002350 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002351 if (ret < 0)
2352 goto out;
2353
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002354 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355 if (ret < 0)
2356 goto out;
2357
Eliad Peller0603d892011-10-05 11:55:51 +02002358 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2359 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002360 ACX_KEEP_ALIVE_TPL_VALID);
2361 if (ret < 0)
2362 goto out;
2363
2364out:
2365 return ret;
2366}
2367
Eliad Peller0603d892011-10-05 11:55:51 +02002368static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002369{
2370 int ret;
2371
Eliad Peller52630c52011-10-10 10:13:08 +02002372 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002373 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2374
Shahar Levi6d158ff2011-09-08 13:01:33 +03002375 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002376 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002377 }
2378
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002379 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002380 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002381 if (ret < 0)
2382 goto out;
2383
Oz Krakowskib992c682011-06-26 10:36:02 +03002384 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002385 wlvif->tx_security_last_seq_lsb = 0;
2386 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002387
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002388out:
2389 return ret;
2390}
2391
Eliad Peller87fbcb02011-10-05 11:55:41 +02002392static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002393{
Eliad Peller1b92f152011-10-10 10:13:09 +02002394 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002395 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002396}
2397
Eliad Peller87fbcb02011-10-05 11:55:41 +02002398static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2399 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002400{
2401 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002402 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2403
2404 if (idle == cur_idle)
2405 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002406
2407 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002408 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002409 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002410 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002411 if (ret < 0)
2412 goto out;
2413 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002414 wlvif->rate_set =
2415 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2416 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002417 if (ret < 0)
2418 goto out;
2419 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002420 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002421 ACX_KEEP_ALIVE_TPL_INVALID);
2422 if (ret < 0)
2423 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002424 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002425 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002426 /* The current firmware only supports sched_scan in idle */
2427 if (wl->sched_scanning) {
2428 wl1271_scan_sched_scan_stop(wl);
2429 ieee80211_sched_scan_stopped(wl->hw);
2430 }
2431
Eliad Peller679a6732011-10-11 11:55:44 +02002432 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002433 if (ret < 0)
2434 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002435 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002436 }
2437
2438out:
2439 return ret;
2440}
2441
Eliad Peller9f259c42011-10-10 10:13:12 +02002442static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2443 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002444{
Eliad Peller9f259c42011-10-10 10:13:12 +02002445 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2446 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002447
2448 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2449
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002450 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002451 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002452 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002453 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002454 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002455 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002456 wlvif->band = conf->channel->band;
2457 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002458
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002459 if (!is_ap) {
2460 /*
2461 * FIXME: the mac80211 should really provide a fixed
2462 * rate to use here. for now, just use the smallest
2463 * possible rate for the band as a fixed rate for
2464 * association frames and other control messages.
2465 */
Eliad Pellerba8447f2011-10-10 10:13:00 +02002466 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002467 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002468
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002469 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002470 wl1271_tx_min_rate_get(wl,
2471 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002472 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002473 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002474 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002475 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002476
Eliad Pellerba8447f2011-10-10 10:13:00 +02002477 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2478 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002479 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002480 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002481 ret = wl12xx_croc(wl,
2482 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002483 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002484 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002485 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002486 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002487 if (ret < 0)
2488 wl1271_warning("cmd join on channel "
2489 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002490 } else {
2491 /*
2492 * change the ROC channel. do it only if we are
2493 * not idle. otherwise, CROC will be called
2494 * anyway.
2495 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002496 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002497 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002498 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002499 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002500 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002501
Eliad Peller679a6732011-10-11 11:55:44 +02002502 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002503 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002504 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002505 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002506 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002507 }
2508 }
2509
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002510 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002511
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002512 if ((conf->flags & IEEE80211_CONF_PS) &&
2513 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002514 !test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002515
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002516 int ps_mode;
2517 char *ps_mode_str;
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002518
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002519 if (wl->conf.conn.forced_ps) {
2520 ps_mode = STATION_POWER_SAVE_MODE;
2521 ps_mode_str = "forced";
2522 } else {
2523 ps_mode = STATION_AUTO_PS_MODE;
2524 ps_mode_str = "auto";
2525 }
2526
2527 wl1271_debug(DEBUG_PSM, "%s ps enabled", ps_mode_str);
2528
2529 ret = wl1271_ps_set_mode(wl, wlvif, ps_mode);
2530
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002531 if (ret < 0)
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002532 wl1271_warning("enter %s ps failed %d",
2533 ps_mode_str, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002534
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002535 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eyal Shapira5c0dc2f2012-02-02 19:06:45 +02002536 test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002537
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002538 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2539
Eliad Peller0603d892011-10-05 11:55:51 +02002540 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002541 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002542 if (ret < 0)
2543 wl1271_warning("exit auto ps failed %d", ret);
2544 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002545 }
2546
Eliad Peller6bd65022011-10-10 10:13:11 +02002547 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002548 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002549 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002550 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002551
Eliad Peller6bd65022011-10-10 10:13:11 +02002552 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 }
2554
Eliad Peller9f259c42011-10-10 10:13:12 +02002555 return 0;
2556}
2557
2558static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2559{
2560 struct wl1271 *wl = hw->priv;
2561 struct wl12xx_vif *wlvif;
2562 struct ieee80211_conf *conf = &hw->conf;
2563 int channel, ret = 0;
2564
2565 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2566
2567 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2568 " changed 0x%x",
2569 channel,
2570 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2571 conf->power_level,
2572 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2573 changed);
2574
2575 /*
2576 * mac80211 will go to idle nearly immediately after transmitting some
2577 * frames, such as the deauth. To make sure those frames reach the air,
2578 * wait here until the TX queue is fully flushed.
2579 */
2580 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2581 (conf->flags & IEEE80211_CONF_IDLE))
2582 wl1271_tx_flush(wl);
2583
2584 mutex_lock(&wl->mutex);
2585
2586 /* we support configuring the channel and band even while off */
2587 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2588 wl->band = conf->channel->band;
2589 wl->channel = channel;
2590 }
2591
2592 if (changed & IEEE80211_CONF_CHANGE_POWER)
2593 wl->power_level = conf->power_level;
2594
2595 if (unlikely(wl->state == WL1271_STATE_OFF))
2596 goto out;
2597
2598 ret = wl1271_ps_elp_wakeup(wl);
2599 if (ret < 0)
2600 goto out;
2601
2602 /* configure each interface */
2603 wl12xx_for_each_wlvif(wl, wlvif) {
2604 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2605 if (ret < 0)
2606 goto out_sleep;
2607 }
2608
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002609out_sleep:
2610 wl1271_ps_elp_sleep(wl);
2611
2612out:
2613 mutex_unlock(&wl->mutex);
2614
2615 return ret;
2616}
2617
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002618struct wl1271_filter_params {
2619 bool enabled;
2620 int mc_list_length;
2621 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2622};
2623
Jiri Pirko22bedad2010-04-01 21:22:57 +00002624static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2625 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002626{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002627 struct wl1271_filter_params *fp;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002628 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002629 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002630
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002631 if (unlikely(wl->state == WL1271_STATE_OFF))
2632 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002633
Juuso Oikarinen74441132009-10-13 12:47:53 +03002634 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002635 if (!fp) {
2636 wl1271_error("Out of memory setting filters.");
2637 return 0;
2638 }
2639
2640 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002641 fp->mc_list_length = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002642 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2643 fp->enabled = false;
2644 } else {
2645 fp->enabled = true;
2646 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002647 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad2010-04-01 21:22:57 +00002648 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002649 fp->mc_list_length++;
Jiri Pirko22bedad2010-04-01 21:22:57 +00002650 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002651 }
2652
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002653 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002654}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002655
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002656#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2657 FIF_ALLMULTI | \
2658 FIF_FCSFAIL | \
2659 FIF_BCN_PRBRESP_PROMISC | \
2660 FIF_CONTROL | \
2661 FIF_OTHER_BSS)
2662
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002663static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2664 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002665 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002666{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002667 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002668 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002669 struct wl12xx_vif *wlvif;
Eliad Peller536129c2011-10-05 11:55:45 +02002670
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002671 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002672
Arik Nemtsov7d057862010-10-16 19:25:35 +02002673 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2674 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002675
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002676 mutex_lock(&wl->mutex);
2677
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002678 *total &= WL1271_SUPPORTED_FILTERS;
2679 changed &= WL1271_SUPPORTED_FILTERS;
2680
2681 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002682 goto out;
2683
Ido Yariva6208652011-03-01 15:14:41 +02002684 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002685 if (ret < 0)
2686 goto out;
2687
Eliad Peller6e8cd332011-10-10 10:13:13 +02002688 wl12xx_for_each_wlvif(wl, wlvif) {
2689 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2690 if (*total & FIF_ALLMULTI)
2691 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2692 false,
2693 NULL, 0);
2694 else if (fp)
2695 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2696 fp->enabled,
2697 fp->mc_list,
2698 fp->mc_list_length);
2699 if (ret < 0)
2700 goto out_sleep;
2701 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002702 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002703
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002704 /*
2705 * the fw doesn't provide an api to configure the filters. instead,
2706 * the filters configuration is based on the active roles / ROC
2707 * state.
2708 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002709
2710out_sleep:
2711 wl1271_ps_elp_sleep(wl);
2712
2713out:
2714 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002715 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002716}
2717
Eliad Peller170d0e62011-10-05 11:56:06 +02002718static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2719 u8 id, u8 key_type, u8 key_size,
2720 const u8 *key, u8 hlid, u32 tx_seq_32,
2721 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002722{
2723 struct wl1271_ap_key *ap_key;
2724 int i;
2725
2726 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2727
2728 if (key_size > MAX_KEY_SIZE)
2729 return -EINVAL;
2730
2731 /*
2732 * Find next free entry in ap_keys. Also check we are not replacing
2733 * an existing key.
2734 */
2735 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002736 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002737 break;
2738
Eliad Peller170d0e62011-10-05 11:56:06 +02002739 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002740 wl1271_warning("trying to record key replacement");
2741 return -EINVAL;
2742 }
2743 }
2744
2745 if (i == MAX_NUM_KEYS)
2746 return -EBUSY;
2747
2748 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2749 if (!ap_key)
2750 return -ENOMEM;
2751
2752 ap_key->id = id;
2753 ap_key->key_type = key_type;
2754 ap_key->key_size = key_size;
2755 memcpy(ap_key->key, key, key_size);
2756 ap_key->hlid = hlid;
2757 ap_key->tx_seq_32 = tx_seq_32;
2758 ap_key->tx_seq_16 = tx_seq_16;
2759
Eliad Peller170d0e62011-10-05 11:56:06 +02002760 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002761 return 0;
2762}
2763
Eliad Peller170d0e62011-10-05 11:56:06 +02002764static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002765{
2766 int i;
2767
2768 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002769 kfree(wlvif->ap.recorded_keys[i]);
2770 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002771 }
2772}
2773
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002774static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002775{
2776 int i, ret = 0;
2777 struct wl1271_ap_key *key;
2778 bool wep_key_added = false;
2779
2780 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002781 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002782 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783 break;
2784
Eliad Peller170d0e62011-10-05 11:56:06 +02002785 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002786 hlid = key->hlid;
2787 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002788 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002789
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002790 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002791 key->id, key->key_type,
2792 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002793 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002794 key->tx_seq_16);
2795 if (ret < 0)
2796 goto out;
2797
2798 if (key->key_type == KEY_WEP)
2799 wep_key_added = true;
2800 }
2801
2802 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002803 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002804 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002805 if (ret < 0)
2806 goto out;
2807 }
2808
2809out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002810 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002811 return ret;
2812}
2813
Eliad Peller536129c2011-10-05 11:55:45 +02002814static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2815 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002816 u8 key_size, const u8 *key, u32 tx_seq_32,
2817 u16 tx_seq_16, struct ieee80211_sta *sta)
2818{
2819 int ret;
Eliad Peller536129c2011-10-05 11:55:45 +02002820 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821
2822 if (is_ap) {
2823 struct wl1271_station *wl_sta;
2824 u8 hlid;
2825
2826 if (sta) {
2827 wl_sta = (struct wl1271_station *)sta->drv_priv;
2828 hlid = wl_sta->hlid;
2829 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002830 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002831 }
2832
Eliad Peller53d40d02011-10-10 10:13:02 +02002833 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 /*
2835 * We do not support removing keys after AP shutdown.
2836 * Pretend we do to make mac80211 happy.
2837 */
2838 if (action != KEY_ADD_OR_REPLACE)
2839 return 0;
2840
Eliad Peller170d0e62011-10-05 11:56:06 +02002841 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002842 key_type, key_size,
2843 key, hlid, tx_seq_32,
2844 tx_seq_16);
2845 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002846 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002847 id, key_type, key_size,
2848 key, hlid, tx_seq_32,
2849 tx_seq_16);
2850 }
2851
2852 if (ret < 0)
2853 return ret;
2854 } else {
2855 const u8 *addr;
2856 static const u8 bcast_addr[ETH_ALEN] = {
2857 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2858 };
2859
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002860 /*
2861 * A STA set to GEM cipher requires 2 tx spare blocks.
2862 * Return to default value when GEM cipher key is removed
2863 */
2864 if (key_type == KEY_GEM) {
2865 if (action == KEY_ADD_OR_REPLACE)
2866 wl->tx_spare_blocks = 2;
2867 else if (action == KEY_REMOVE)
2868 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2869 }
2870
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002871 addr = sta ? sta->addr : bcast_addr;
2872
2873 if (is_zero_ether_addr(addr)) {
2874 /* We dont support TX only encryption */
2875 return -EOPNOTSUPP;
2876 }
2877
2878 /* The wl1271 does not allow to remove unicast keys - they
2879 will be cleared automatically on next CMD_JOIN. Ignore the
2880 request silently, as we dont want the mac80211 to emit
2881 an error message. */
2882 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2883 return 0;
2884
Eliad Peller010d3d32011-08-14 13:17:31 +03002885 /* don't remove key if hlid was already deleted */
2886 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002887 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002888 return 0;
2889
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002890 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002891 id, key_type, key_size,
2892 key, addr, tx_seq_32,
2893 tx_seq_16);
2894 if (ret < 0)
2895 return ret;
2896
2897 /* the default WEP key needs to be configured at least once */
2898 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002899 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002900 wlvif->default_key,
2901 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002902 if (ret < 0)
2903 return ret;
2904 }
2905 }
2906
2907 return 0;
2908}
2909
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002910static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2911 struct ieee80211_vif *vif,
2912 struct ieee80211_sta *sta,
2913 struct ieee80211_key_conf *key_conf)
2914{
2915 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02002916 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002918 u32 tx_seq_32 = 0;
2919 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002920 u8 key_type;
2921
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002922 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2923
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002924 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002926 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002927 key_conf->keylen, key_conf->flags);
2928 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2929
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002930 mutex_lock(&wl->mutex);
2931
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002932 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2933 ret = -EAGAIN;
2934 goto out_unlock;
2935 }
2936
Ido Yariva6208652011-03-01 15:14:41 +02002937 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002938 if (ret < 0)
2939 goto out_unlock;
2940
Johannes Berg97359d12010-08-10 09:46:38 +02002941 switch (key_conf->cipher) {
2942 case WLAN_CIPHER_SUITE_WEP40:
2943 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002944 key_type = KEY_WEP;
2945
2946 key_conf->hw_key_idx = key_conf->keyidx;
2947 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002948 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002949 key_type = KEY_TKIP;
2950
2951 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002952 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2953 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002955 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 key_type = KEY_AES;
2957
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002958 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002959 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2960 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002961 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002962 case WL1271_CIPHER_SUITE_GEM:
2963 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002964 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2965 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002966 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002968 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002969
2970 ret = -EOPNOTSUPP;
2971 goto out_sleep;
2972 }
2973
2974 switch (cmd) {
2975 case SET_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002976 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002977 key_conf->keyidx, key_type,
2978 key_conf->keylen, key_conf->key,
2979 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002980 if (ret < 0) {
2981 wl1271_error("Could not add or replace key");
2982 goto out_sleep;
2983 }
2984 break;
2985
2986 case DISABLE_KEY:
Eliad Peller536129c2011-10-05 11:55:45 +02002987 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002988 key_conf->keyidx, key_type,
2989 key_conf->keylen, key_conf->key,
2990 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002991 if (ret < 0) {
2992 wl1271_error("Could not remove key");
2993 goto out_sleep;
2994 }
2995 break;
2996
2997 default:
2998 wl1271_error("Unsupported key cmd 0x%x", cmd);
2999 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003000 break;
3001 }
3002
3003out_sleep:
3004 wl1271_ps_elp_sleep(wl);
3005
3006out_unlock:
3007 mutex_unlock(&wl->mutex);
3008
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 return ret;
3010}
3011
3012static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003013 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003014 struct cfg80211_scan_request *req)
3015{
3016 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003017 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3018
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003019 int ret;
3020 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003021 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003022
3023 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3024
3025 if (req->n_ssids) {
3026 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003027 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003028 }
3029
3030 mutex_lock(&wl->mutex);
3031
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003032 if (wl->state == WL1271_STATE_OFF) {
3033 /*
3034 * We cannot return -EBUSY here because cfg80211 will expect
3035 * a call to ieee80211_scan_completed if we do - in this case
3036 * there won't be any call.
3037 */
3038 ret = -EAGAIN;
3039 goto out;
3040 }
3041
Ido Yariva6208652011-03-01 15:14:41 +02003042 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003043 if (ret < 0)
3044 goto out;
3045
Eliad Peller92e712d2011-12-18 20:25:43 +02003046 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3047 test_bit(wlvif->role_id, wl->roc_map)) {
3048 /* don't allow scanning right now */
3049 ret = -EBUSY;
3050 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003051 }
3052
Eliad Peller92e712d2011-12-18 20:25:43 +02003053 /* cancel ROC before scanning */
3054 if (wl12xx_dev_role_started(wlvif))
Eliad Pellerc059beb2012-01-31 11:57:17 +02003055 wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller92e712d2011-12-18 20:25:43 +02003056
Eliad Peller784f6942011-10-05 11:55:39 +02003057 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003058out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003059 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003060out:
3061 mutex_unlock(&wl->mutex);
3062
3063 return ret;
3064}
3065
Eliad Peller73ecce32011-06-27 13:06:45 +03003066static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3067 struct ieee80211_vif *vif)
3068{
3069 struct wl1271 *wl = hw->priv;
3070 int ret;
3071
3072 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3073
3074 mutex_lock(&wl->mutex);
3075
3076 if (wl->state == WL1271_STATE_OFF)
3077 goto out;
3078
3079 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3080 goto out;
3081
3082 ret = wl1271_ps_elp_wakeup(wl);
3083 if (ret < 0)
3084 goto out;
3085
3086 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3087 ret = wl1271_scan_stop(wl);
3088 if (ret < 0)
3089 goto out_sleep;
3090 }
3091 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3092 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003093 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003094 wl->scan.req = NULL;
3095 ieee80211_scan_completed(wl->hw, true);
3096
3097out_sleep:
3098 wl1271_ps_elp_sleep(wl);
3099out:
3100 mutex_unlock(&wl->mutex);
3101
3102 cancel_delayed_work_sync(&wl->scan_complete_work);
3103}
3104
Luciano Coelho33c2c062011-05-10 14:46:02 +03003105static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3106 struct ieee80211_vif *vif,
3107 struct cfg80211_sched_scan_request *req,
3108 struct ieee80211_sched_scan_ies *ies)
3109{
3110 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003111 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003112 int ret;
3113
3114 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3115
3116 mutex_lock(&wl->mutex);
3117
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003118 if (wl->state == WL1271_STATE_OFF) {
3119 ret = -EAGAIN;
3120 goto out;
3121 }
3122
Luciano Coelho33c2c062011-05-10 14:46:02 +03003123 ret = wl1271_ps_elp_wakeup(wl);
3124 if (ret < 0)
3125 goto out;
3126
Eliad Peller536129c2011-10-05 11:55:45 +02003127 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003128 if (ret < 0)
3129 goto out_sleep;
3130
Eliad Peller536129c2011-10-05 11:55:45 +02003131 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003132 if (ret < 0)
3133 goto out_sleep;
3134
3135 wl->sched_scanning = true;
3136
3137out_sleep:
3138 wl1271_ps_elp_sleep(wl);
3139out:
3140 mutex_unlock(&wl->mutex);
3141 return ret;
3142}
3143
3144static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3145 struct ieee80211_vif *vif)
3146{
3147 struct wl1271 *wl = hw->priv;
3148 int ret;
3149
3150 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3151
3152 mutex_lock(&wl->mutex);
3153
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003154 if (wl->state == WL1271_STATE_OFF)
3155 goto out;
3156
Luciano Coelho33c2c062011-05-10 14:46:02 +03003157 ret = wl1271_ps_elp_wakeup(wl);
3158 if (ret < 0)
3159 goto out;
3160
3161 wl1271_scan_sched_scan_stop(wl);
3162
3163 wl1271_ps_elp_sleep(wl);
3164out:
3165 mutex_unlock(&wl->mutex);
3166}
3167
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003168static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3169{
3170 struct wl1271 *wl = hw->priv;
3171 int ret = 0;
3172
3173 mutex_lock(&wl->mutex);
3174
3175 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3176 ret = -EAGAIN;
3177 goto out;
3178 }
3179
Ido Yariva6208652011-03-01 15:14:41 +02003180 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003181 if (ret < 0)
3182 goto out;
3183
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003184 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003185 if (ret < 0)
3186 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3187
3188 wl1271_ps_elp_sleep(wl);
3189
3190out:
3191 mutex_unlock(&wl->mutex);
3192
3193 return ret;
3194}
3195
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003196static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3197{
3198 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003199 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003200 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003201
3202 mutex_lock(&wl->mutex);
3203
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003204 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3205 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003206 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003207 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003208
Ido Yariva6208652011-03-01 15:14:41 +02003209 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003210 if (ret < 0)
3211 goto out;
3212
Eliad Peller6e8cd332011-10-10 10:13:13 +02003213 wl12xx_for_each_wlvif(wl, wlvif) {
3214 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3215 if (ret < 0)
3216 wl1271_warning("set rts threshold failed: %d", ret);
3217 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003218 wl1271_ps_elp_sleep(wl);
3219
3220out:
3221 mutex_unlock(&wl->mutex);
3222
3223 return ret;
3224}
3225
Eliad Peller1fe9f162011-10-05 11:55:48 +02003226static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003227 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003228{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003229 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003230 u8 ssid_len;
3231 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3232 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003233
Eliad Peller889cb362011-05-01 09:56:45 +03003234 if (!ptr) {
3235 wl1271_error("No SSID in IEs!");
3236 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003237 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003238
Eliad Peller889cb362011-05-01 09:56:45 +03003239 ssid_len = ptr[1];
3240 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3241 wl1271_error("SSID is too long!");
3242 return -EINVAL;
3243 }
3244
Eliad Peller1fe9f162011-10-05 11:55:48 +02003245 wlvif->ssid_len = ssid_len;
3246 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003247 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003248}
3249
Eliad Pellerd48055d2011-09-15 12:07:04 +03003250static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3251{
3252 int len;
3253 const u8 *next, *end = skb->data + skb->len;
3254 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3255 skb->len - ieoffset);
3256 if (!ie)
3257 return;
3258 len = ie[1] + 2;
3259 next = ie + len;
3260 memmove(ie, next, end - next);
3261 skb_trim(skb, skb->len - len);
3262}
3263
Eliad Peller26b4bf22011-09-15 12:07:05 +03003264static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3265 unsigned int oui, u8 oui_type,
3266 int ieoffset)
3267{
3268 int len;
3269 const u8 *next, *end = skb->data + skb->len;
3270 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3271 skb->data + ieoffset,
3272 skb->len - ieoffset);
3273 if (!ie)
3274 return;
3275 len = ie[1] + 2;
3276 next = ie + len;
3277 memmove(ie, next, end - next);
3278 skb_trim(skb, skb->len - len);
3279}
3280
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003281static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3282 struct ieee80211_vif *vif)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003283{
Eliad Pellercdaac622012-01-31 11:57:16 +02003284 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003285 struct sk_buff *skb;
3286 int ret;
3287
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003288 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003289 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003290 return -EOPNOTSUPP;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003291
Eliad Pellercdaac622012-01-31 11:57:16 +02003292 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f0022011-11-08 18:46:54 +02003293 CMD_TEMPL_AP_PROBE_RESPONSE,
3294 skb->data,
3295 skb->len, 0,
3296 rates);
3297
3298 dev_kfree_skb(skb);
3299 return ret;
3300}
3301
3302static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3303 struct ieee80211_vif *vif,
3304 u8 *probe_rsp_data,
3305 size_t probe_rsp_len,
3306 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003307{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003308 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3309 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003310 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3311 int ssid_ie_offset, ie_offset, templ_len;
3312 const u8 *ptr;
3313
3314 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003315 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003316 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003317 CMD_TEMPL_AP_PROBE_RESPONSE,
3318 probe_rsp_data,
3319 probe_rsp_len, 0,
3320 rates);
3321
3322 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3323 wl1271_error("probe_rsp template too big");
3324 return -EINVAL;
3325 }
3326
3327 /* start searching from IE offset */
3328 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3329
3330 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3331 probe_rsp_len - ie_offset);
3332 if (!ptr) {
3333 wl1271_error("No SSID in beacon!");
3334 return -EINVAL;
3335 }
3336
3337 ssid_ie_offset = ptr - probe_rsp_data;
3338 ptr += (ptr[1] + 2);
3339
3340 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3341
3342 /* insert SSID from bss_conf */
3343 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3344 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3345 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3346 bss_conf->ssid, bss_conf->ssid_len);
3347 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3348
3349 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3350 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3351 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3352
Eliad Pellercdaac622012-01-31 11:57:16 +02003353 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003354 CMD_TEMPL_AP_PROBE_RESPONSE,
3355 probe_rsp_templ,
3356 templ_len, 0,
3357 rates);
3358}
3359
Arik Nemtsove78a2872010-10-16 19:07:21 +02003360static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003361 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003362 struct ieee80211_bss_conf *bss_conf,
3363 u32 changed)
3364{
Eliad Peller0603d892011-10-05 11:55:51 +02003365 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003366 int ret = 0;
3367
3368 if (changed & BSS_CHANGED_ERP_SLOT) {
3369 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003370 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 else
Eliad Peller0603d892011-10-05 11:55:51 +02003372 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003373 if (ret < 0) {
3374 wl1271_warning("Set slot time failed %d", ret);
3375 goto out;
3376 }
3377 }
3378
3379 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3380 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003381 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003382 else
Eliad Peller0603d892011-10-05 11:55:51 +02003383 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 }
3385
3386 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3387 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003388 ret = wl1271_acx_cts_protect(wl, wlvif,
3389 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003390 else
Eliad Peller0603d892011-10-05 11:55:51 +02003391 ret = wl1271_acx_cts_protect(wl, wlvif,
3392 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003393 if (ret < 0) {
3394 wl1271_warning("Set ctsprotect failed %d", ret);
3395 goto out;
3396 }
3397 }
3398
3399out:
3400 return ret;
3401}
3402
3403static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3404 struct ieee80211_vif *vif,
3405 struct ieee80211_bss_conf *bss_conf,
3406 u32 changed)
3407{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003408 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c2011-10-05 11:55:45 +02003409 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003410 int ret = 0;
3411
3412 if ((changed & BSS_CHANGED_BEACON_INT)) {
3413 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3414 bss_conf->beacon_int);
3415
Eliad Peller6a899792011-10-05 11:55:58 +02003416 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003417 }
3418
Arik Nemtsov560f0022011-11-08 18:46:54 +02003419 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3420 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003421 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3422 wl1271_debug(DEBUG_AP, "probe response updated");
3423 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3424 }
Arik Nemtsov560f0022011-11-08 18:46:54 +02003425 }
3426
Arik Nemtsove78a2872010-10-16 19:07:21 +02003427 if ((changed & BSS_CHANGED_BEACON)) {
3428 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003429 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 int ieoffset = offsetof(struct ieee80211_mgmt,
3431 u.beacon.variable);
3432 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3433 u16 tmpl_id;
3434
Arik Nemtsov560f0022011-11-08 18:46:54 +02003435 if (!beacon) {
3436 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003437 goto out;
Arik Nemtsov560f0022011-11-08 18:46:54 +02003438 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003439
3440 wl1271_debug(DEBUG_MASTER, "beacon updated");
3441
Eliad Peller1fe9f162011-10-05 11:55:48 +02003442 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003443 if (ret < 0) {
3444 dev_kfree_skb(beacon);
3445 goto out;
3446 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003447 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3449 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003450 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003451 beacon->data,
3452 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003453 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003454 if (ret < 0) {
3455 dev_kfree_skb(beacon);
3456 goto out;
3457 }
3458
Arik Nemtsov560f0022011-11-08 18:46:54 +02003459 /*
3460 * In case we already have a probe-resp beacon set explicitly
3461 * by usermode, don't use the beacon data.
3462 */
3463 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3464 goto end_bcn;
3465
Eliad Pellerd48055d2011-09-15 12:07:04 +03003466 /* remove TIM ie from probe response */
3467 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3468
Eliad Peller26b4bf22011-09-15 12:07:05 +03003469 /*
3470 * remove p2p ie from probe response.
3471 * the fw reponds to probe requests that don't include
3472 * the p2p ie. probe requests with p2p ie will be passed,
3473 * and will be responded by the supplicant (the spec
3474 * forbids including the p2p ie when responding to probe
3475 * requests that didn't include it).
3476 */
3477 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3478 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3479
Arik Nemtsove78a2872010-10-16 19:07:21 +02003480 hdr = (struct ieee80211_hdr *) beacon->data;
3481 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3482 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003483 if (is_ap)
Arik Nemtsov560f0022011-11-08 18:46:54 +02003484 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003485 beacon->data,
3486 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003487 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003488 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003489 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003490 CMD_TEMPL_PROBE_RESPONSE,
3491 beacon->data,
3492 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003493 min_rate);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003494end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003495 dev_kfree_skb(beacon);
3496 if (ret < 0)
3497 goto out;
3498 }
3499
3500out:
Arik Nemtsov560f0022011-11-08 18:46:54 +02003501 if (ret != 0)
3502 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003503 return ret;
3504}
3505
3506/* AP mode changes */
3507static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003508 struct ieee80211_vif *vif,
3509 struct ieee80211_bss_conf *bss_conf,
3510 u32 changed)
3511{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003512 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003514
Arik Nemtsove78a2872010-10-16 19:07:21 +02003515 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3516 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003517
Eliad Peller87fbcb02011-10-05 11:55:41 +02003518 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003519 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003520 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003521 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003522
Eliad Peller87fbcb02011-10-05 11:55:41 +02003523 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003524 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003525 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003526 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003527 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003528
Eliad Peller784f6942011-10-05 11:55:39 +02003529 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003530 if (ret < 0)
3531 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003532 }
3533
Arik Nemtsove78a2872010-10-16 19:07:21 +02003534 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3535 if (ret < 0)
3536 goto out;
3537
3538 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3539 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003540 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003541 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0)
3543 goto out;
3544
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003545 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003546 if (ret < 0)
3547 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003548
Eliad Peller53d40d02011-10-10 10:13:02 +02003549 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003550 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003551 }
3552 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003553 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003554 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003555 if (ret < 0)
3556 goto out;
3557
Eliad Peller53d40d02011-10-10 10:13:02 +02003558 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f0022011-11-08 18:46:54 +02003559 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3560 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003561 wl1271_debug(DEBUG_AP, "stopped AP");
3562 }
3563 }
3564 }
3565
Eliad Peller0603d892011-10-05 11:55:51 +02003566 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003567 if (ret < 0)
3568 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003569
3570 /* Handle HT information change */
3571 if ((changed & BSS_CHANGED_HT) &&
3572 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003573 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003574 bss_conf->ht_operation_mode);
3575 if (ret < 0) {
3576 wl1271_warning("Set ht information failed %d", ret);
3577 goto out;
3578 }
3579 }
3580
Arik Nemtsove78a2872010-10-16 19:07:21 +02003581out:
3582 return;
3583}
3584
3585/* STA/IBSS mode changes */
3586static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3587 struct ieee80211_vif *vif,
3588 struct ieee80211_bss_conf *bss_conf,
3589 u32 changed)
3590{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003591 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003592 bool do_join = false, set_assoc = false;
Eliad Peller536129c2011-10-05 11:55:45 +02003593 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003594 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003595 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003596 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003597 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003598 bool sta_exists = false;
3599 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003600
3601 if (is_ibss) {
3602 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3603 changed);
3604 if (ret < 0)
3605 goto out;
3606 }
3607
Eliad Peller227e81e2011-08-14 13:17:26 +03003608 if (changed & BSS_CHANGED_IBSS) {
3609 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003610 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003611 ibss_joined = true;
3612 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003613 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3614 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003615 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003616 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003617 }
3618 }
3619 }
3620
3621 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003622 do_join = true;
3623
3624 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003625 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003626 do_join = true;
3627
Eliad Peller227e81e2011-08-14 13:17:26 +03003628 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003629 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3630 bss_conf->enable_beacon ? "enabled" : "disabled");
3631
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003632 do_join = true;
3633 }
3634
Eliad Pellerc31e4942011-10-23 08:21:55 +02003635 if (changed & BSS_CHANGED_IDLE) {
3636 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3637 if (ret < 0)
3638 wl1271_warning("idle mode change failed %d", ret);
3639 }
3640
Arik Nemtsove78a2872010-10-16 19:07:21 +02003641 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003642 bool enable = false;
3643 if (bss_conf->cqm_rssi_thold)
3644 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003645 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003646 bss_conf->cqm_rssi_thold,
3647 bss_conf->cqm_rssi_hyst);
3648 if (ret < 0)
3649 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003650 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003651 }
3652
Eliad Peller7db4ee62012-01-24 18:18:42 +02003653 if (changed & BSS_CHANGED_BSSID &&
3654 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003655 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003656 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003657 if (ret < 0)
3658 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003659
Eliad Peller784f6942011-10-05 11:55:39 +02003660 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003661 if (ret < 0)
3662 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003663
Eliad Pellerfa287b82010-12-26 09:27:50 +01003664 /* Need to update the BSSID (for filtering etc) */
3665 do_join = true;
3666 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003667
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003668 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3669 rcu_read_lock();
3670 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3671 if (!sta)
3672 goto sta_not_found;
3673
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003674 /* save the supp_rates of the ap */
3675 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3676 if (sta->ht_cap.ht_supported)
3677 sta_rate_set |=
3678 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003679 sta_ht_cap = sta->ht_cap;
3680 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003681
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003682sta_not_found:
3683 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003684 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003685
Arik Nemtsove78a2872010-10-16 19:07:21 +02003686 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003687 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003688 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003689 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003690 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003691 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003692
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003693 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003694 * use basic rates from AP, and determine lowest rate
3695 * to use with control frames.
3696 */
3697 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003698 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003699 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003700 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003701 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003702 wl1271_tx_min_rate_get(wl,
3703 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003704 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003705 wlvif->rate_set =
3706 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003707 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003708 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003709 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003710 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003711 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003712
3713 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003714 * with wl1271, we don't need to update the
3715 * beacon_int and dtim_period, because the firmware
3716 * updates it by itself when the first beacon is
3717 * received after a join.
3718 */
Eliad Peller6840e372011-10-05 11:55:50 +02003719 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003720 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003721 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003722
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003723 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003724 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003725 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003726 dev_kfree_skb(wlvif->probereq);
3727 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003728 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003729 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003730 ieoffset = offsetof(struct ieee80211_mgmt,
3731 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003732 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003733
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003734 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003735 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003736 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003737 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003738 } else {
3739 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003740 bool was_assoc =
Eliad Pellerba8447f2011-10-10 10:13:00 +02003741 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3742 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003743 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003744 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3745 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003746 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003747
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003748 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003749 dev_kfree_skb(wlvif->probereq);
3750 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003751
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003752 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003753 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003754 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003755 wl1271_tx_min_rate_get(wl,
3756 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003757 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003758 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003759 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003760
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003761 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003762 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003763
3764 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003765 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003766 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003767 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003768
3769 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003770 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003771 u32 conf_flags = wl->hw->conf.flags;
3772 /*
3773 * we might have to disable roc, if there was
3774 * no IF_OPER_UP notification.
3775 */
3776 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003777 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003778 if (ret < 0)
3779 goto out;
3780 }
3781 /*
3782 * (we also need to disable roc in case of
3783 * roaming on the same channel. until we will
3784 * have a better flow...)
3785 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003786 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3787 ret = wl12xx_croc(wl,
3788 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003789 if (ret < 0)
3790 goto out;
3791 }
3792
Eliad Peller0603d892011-10-05 11:55:51 +02003793 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003794 if (!(conf_flags & IEEE80211_CONF_IDLE))
3795 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003796 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003797 }
3798 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003799
Eliad Pellerd192d262011-05-24 14:33:08 +03003800 if (changed & BSS_CHANGED_IBSS) {
3801 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3802 bss_conf->ibss_joined);
3803
3804 if (bss_conf->ibss_joined) {
3805 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003806 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003807 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003808 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003809 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003810 wl1271_tx_min_rate_get(wl,
3811 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003812
Shahar Levi06b660e2011-09-05 13:54:36 +03003813 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003814 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3815 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003816 if (ret < 0)
3817 goto out;
3818 }
3819 }
3820
Eliad Peller0603d892011-10-05 11:55:51 +02003821 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003822 if (ret < 0)
3823 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003824
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003825 if (changed & BSS_CHANGED_ARP_FILTER) {
3826 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c2011-10-05 11:55:45 +02003827 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003828
Eliad Pellerc5312772010-12-09 11:31:27 +02003829 if (bss_conf->arp_addr_cnt == 1 &&
3830 bss_conf->arp_filter_enabled) {
3831 /*
3832 * The template should have been configured only upon
3833 * association. however, it seems that the correct ip
3834 * isn't being set (when sending), so we have to
3835 * reconfigure the template upon every ip change.
3836 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003837 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003838 if (ret < 0) {
3839 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003840 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003841 }
3842
Eliad Peller0603d892011-10-05 11:55:51 +02003843 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003844 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003845 addr);
3846 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003847 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003848
3849 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003850 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003851 }
3852
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003853 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003854 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003855 if (ret < 0) {
3856 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003857 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003858 }
Eliad Peller251c1772011-08-14 13:17:17 +03003859
3860 /* ROC until connected (after EAPOL exchange) */
3861 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003862 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003863 if (ret < 0)
3864 goto out;
3865
Eliad Pellerba8447f2011-10-10 10:13:00 +02003866 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003867 ieee80211_get_operstate(vif));
3868 }
3869 /*
3870 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003871 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003872 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003873 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003874 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003875 if (ret < 0)
3876 goto out;
3877 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003878 }
3879
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003880 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003881 if (sta_exists) {
3882 if ((changed & BSS_CHANGED_HT) &&
3883 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003884 ret = wl1271_acx_set_ht_capabilities(wl,
3885 &sta_ht_cap,
3886 true,
Eliad Peller154da672011-10-05 11:55:53 +02003887 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003888 if (ret < 0) {
3889 wl1271_warning("Set ht cap true failed %d",
3890 ret);
3891 goto out;
3892 }
3893 }
3894 /* handle new association without HT and disassociation */
3895 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003896 ret = wl1271_acx_set_ht_capabilities(wl,
3897 &sta_ht_cap,
3898 false,
Eliad Peller154da672011-10-05 11:55:53 +02003899 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003900 if (ret < 0) {
3901 wl1271_warning("Set ht cap false failed %d",
3902 ret);
3903 goto out;
3904 }
3905 }
3906 }
3907
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003908 /* Handle HT information change. Done after join. */
3909 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003910 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003911 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003912 bss_conf->ht_operation_mode);
3913 if (ret < 0) {
3914 wl1271_warning("Set ht information failed %d", ret);
3915 goto out;
3916 }
3917 }
3918
Arik Nemtsove78a2872010-10-16 19:07:21 +02003919out:
3920 return;
3921}
3922
3923static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3924 struct ieee80211_vif *vif,
3925 struct ieee80211_bss_conf *bss_conf,
3926 u32 changed)
3927{
3928 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02003929 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3930 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003931 int ret;
3932
3933 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3934 (int)changed);
3935
3936 mutex_lock(&wl->mutex);
3937
3938 if (unlikely(wl->state == WL1271_STATE_OFF))
3939 goto out;
3940
Eliad Peller10c8cd02011-10-10 10:13:06 +02003941 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3942 goto out;
3943
Ido Yariva6208652011-03-01 15:14:41 +02003944 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003945 if (ret < 0)
3946 goto out;
3947
3948 if (is_ap)
3949 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3950 else
3951 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3952
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003953 wl1271_ps_elp_sleep(wl);
3954
3955out:
3956 mutex_unlock(&wl->mutex);
3957}
3958
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003959static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3960 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003961 const struct ieee80211_tx_queue_params *params)
3962{
3963 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003964 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003965 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003966 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003967
3968 mutex_lock(&wl->mutex);
3969
3970 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3971
Kalle Valo4695dc92010-03-18 12:26:38 +02003972 if (params->uapsd)
3973 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3974 else
3975 ps_scheme = CONF_PS_SCHEME_LEGACY;
3976
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003977 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003978 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003979
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003980 ret = wl1271_ps_elp_wakeup(wl);
3981 if (ret < 0)
3982 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003983
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003984 /*
3985 * the txop is confed in units of 32us by the mac80211,
3986 * we need us
3987 */
Eliad Peller0603d892011-10-05 11:55:51 +02003988 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003989 params->cw_min, params->cw_max,
3990 params->aifs, params->txop << 5);
3991 if (ret < 0)
3992 goto out_sleep;
3993
Eliad Peller0603d892011-10-05 11:55:51 +02003994 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003995 CONF_CHANNEL_TYPE_EDCF,
3996 wl1271_tx_get_queue(queue),
3997 ps_scheme, CONF_ACK_POLICY_LEGACY,
3998 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003999
4000out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004001 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004002
4003out:
4004 mutex_unlock(&wl->mutex);
4005
4006 return ret;
4007}
4008
Eliad Peller37a41b42011-09-21 14:06:11 +03004009static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4010 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004011{
4012
4013 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004014 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004015 u64 mactime = ULLONG_MAX;
4016 int ret;
4017
4018 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4019
4020 mutex_lock(&wl->mutex);
4021
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004022 if (unlikely(wl->state == WL1271_STATE_OFF))
4023 goto out;
4024
Ido Yariva6208652011-03-01 15:14:41 +02004025 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004026 if (ret < 0)
4027 goto out;
4028
Eliad Peller9c531142012-01-31 11:57:18 +02004029 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004030 if (ret < 0)
4031 goto out_sleep;
4032
4033out_sleep:
4034 wl1271_ps_elp_sleep(wl);
4035
4036out:
4037 mutex_unlock(&wl->mutex);
4038 return mactime;
4039}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004040
John W. Linvilleece550d2010-07-28 16:41:06 -04004041static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4042 struct survey_info *survey)
4043{
4044 struct wl1271 *wl = hw->priv;
4045 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004046
John W. Linvilleece550d2010-07-28 16:41:06 -04004047 if (idx != 0)
4048 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004049
John W. Linvilleece550d2010-07-28 16:41:06 -04004050 survey->channel = conf->channel;
4051 survey->filled = SURVEY_INFO_NOISE_DBM;
4052 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004053
John W. Linvilleece550d2010-07-28 16:41:06 -04004054 return 0;
4055}
4056
Arik Nemtsov409622e2011-02-23 00:22:29 +02004057static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004058 struct wl12xx_vif *wlvif,
4059 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004060{
4061 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004062 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004063
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004064
4065 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004066 wl1271_warning("could not allocate HLID - too much stations");
4067 return -EBUSY;
4068 }
4069
4070 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004071 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4072 if (ret < 0) {
4073 wl1271_warning("could not allocate HLID - too many links");
4074 return -EBUSY;
4075 }
4076
4077 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004078 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004079 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004080 return 0;
4081}
4082
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004083void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004084{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004085 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004086 return;
4087
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004088 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004089 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004090 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004091 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004092 __clear_bit(hlid, &wl->ap_ps_map);
4093 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004094 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004095 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004096}
4097
4098static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4099 struct ieee80211_vif *vif,
4100 struct ieee80211_sta *sta)
4101{
4102 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004103 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004104 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004105 int ret = 0;
4106 u8 hlid;
4107
4108 mutex_lock(&wl->mutex);
4109
4110 if (unlikely(wl->state == WL1271_STATE_OFF))
4111 goto out;
4112
Eliad Peller536129c2011-10-05 11:55:45 +02004113 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004114 goto out;
4115
4116 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4117
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004118 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119 if (ret < 0)
4120 goto out;
4121
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004122 wl_sta = (struct wl1271_station *)sta->drv_priv;
4123 hlid = wl_sta->hlid;
4124
Ido Yariva6208652011-03-01 15:14:41 +02004125 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004126 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004127 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128
Eliad Peller1b92f152011-10-10 10:13:09 +02004129 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004130 if (ret < 0)
4131 goto out_sleep;
4132
Eliad Pellerb67476e2011-08-14 13:17:23 +03004133 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4134 if (ret < 0)
4135 goto out_sleep;
4136
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004137 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4138 if (ret < 0)
4139 goto out_sleep;
4140
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004141out_sleep:
4142 wl1271_ps_elp_sleep(wl);
4143
Arik Nemtsov409622e2011-02-23 00:22:29 +02004144out_free_sta:
4145 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004146 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004147
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004148out:
4149 mutex_unlock(&wl->mutex);
4150 return ret;
4151}
4152
4153static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4154 struct ieee80211_vif *vif,
4155 struct ieee80211_sta *sta)
4156{
4157 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004158 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004159 struct wl1271_station *wl_sta;
4160 int ret = 0, id;
4161
4162 mutex_lock(&wl->mutex);
4163
4164 if (unlikely(wl->state == WL1271_STATE_OFF))
4165 goto out;
4166
Eliad Peller536129c2011-10-05 11:55:45 +02004167 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004168 goto out;
4169
4170 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4171
4172 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004173 id = wl_sta->hlid;
4174 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004175 goto out;
4176
Ido Yariva6208652011-03-01 15:14:41 +02004177 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004178 if (ret < 0)
4179 goto out;
4180
Eliad Pellerc690ec82011-08-14 13:17:07 +03004181 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004182 if (ret < 0)
4183 goto out_sleep;
4184
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004185 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004186
4187out_sleep:
4188 wl1271_ps_elp_sleep(wl);
4189
4190out:
4191 mutex_unlock(&wl->mutex);
4192 return ret;
4193}
4194
Luciano Coelho4623ec72011-03-21 19:26:41 +02004195static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4196 struct ieee80211_vif *vif,
4197 enum ieee80211_ampdu_mlme_action action,
4198 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4199 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004200{
4201 struct wl1271 *wl = hw->priv;
Eliad Peller536129c2011-10-05 11:55:45 +02004202 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004203 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004204 u8 hlid, *ba_bitmap;
4205
4206 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4207 tid);
4208
4209 /* sanity check - the fields in FW are only 8bits wide */
4210 if (WARN_ON(tid > 0xFF))
4211 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004212
4213 mutex_lock(&wl->mutex);
4214
4215 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4216 ret = -EAGAIN;
4217 goto out;
4218 }
4219
Eliad Peller536129c2011-10-05 11:55:45 +02004220 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004221 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004222 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c2011-10-05 11:55:45 +02004223 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004224 struct wl1271_station *wl_sta;
4225
4226 wl_sta = (struct wl1271_station *)sta->drv_priv;
4227 hlid = wl_sta->hlid;
4228 ba_bitmap = &wl->links[hlid].ba_bitmap;
4229 } else {
4230 ret = -EINVAL;
4231 goto out;
4232 }
4233
Ido Yariva6208652011-03-01 15:14:41 +02004234 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235 if (ret < 0)
4236 goto out;
4237
Shahar Levi70559a02011-05-22 16:10:22 +03004238 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4239 tid, action);
4240
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004241 switch (action) {
4242 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004243 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004244 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004245 break;
4246 }
4247
4248 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4249 ret = -EBUSY;
4250 wl1271_error("exceeded max RX BA sessions");
4251 break;
4252 }
4253
4254 if (*ba_bitmap & BIT(tid)) {
4255 ret = -EINVAL;
4256 wl1271_error("cannot enable RX BA session on active "
4257 "tid: %d", tid);
4258 break;
4259 }
4260
4261 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4262 hlid);
4263 if (!ret) {
4264 *ba_bitmap |= BIT(tid);
4265 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004266 }
4267 break;
4268
4269 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004270 if (!(*ba_bitmap & BIT(tid))) {
4271 ret = -EINVAL;
4272 wl1271_error("no active RX BA session on tid: %d",
4273 tid);
4274 break;
4275 }
4276
4277 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4278 hlid);
4279 if (!ret) {
4280 *ba_bitmap &= ~BIT(tid);
4281 wl->ba_rx_session_count--;
4282 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004283 break;
4284
4285 /*
4286 * The BA initiator session management in FW independently.
4287 * Falling break here on purpose for all TX APDU commands.
4288 */
4289 case IEEE80211_AMPDU_TX_START:
4290 case IEEE80211_AMPDU_TX_STOP:
4291 case IEEE80211_AMPDU_TX_OPERATIONAL:
4292 ret = -EINVAL;
4293 break;
4294
4295 default:
4296 wl1271_error("Incorrect ampdu action id=%x\n", action);
4297 ret = -EINVAL;
4298 }
4299
4300 wl1271_ps_elp_sleep(wl);
4301
4302out:
4303 mutex_unlock(&wl->mutex);
4304
4305 return ret;
4306}
4307
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004308static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4309 struct ieee80211_vif *vif,
4310 const struct cfg80211_bitrate_mask *mask)
4311{
Eliad Peller83587502011-10-10 10:12:53 +02004312 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004313 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004314 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004315
4316 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4317 mask->control[NL80211_BAND_2GHZ].legacy,
4318 mask->control[NL80211_BAND_5GHZ].legacy);
4319
4320 mutex_lock(&wl->mutex);
4321
4322 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004323 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004324 wl1271_tx_enabled_rates_get(wl,
4325 mask->control[i].legacy,
4326 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004327
4328 if (unlikely(wl->state == WL1271_STATE_OFF))
4329 goto out;
4330
4331 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4332 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4333
4334 ret = wl1271_ps_elp_wakeup(wl);
4335 if (ret < 0)
4336 goto out;
4337
4338 wl1271_set_band_rate(wl, wlvif);
4339 wlvif->basic_rate =
4340 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4341 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4342
4343 wl1271_ps_elp_sleep(wl);
4344 }
4345out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004346 mutex_unlock(&wl->mutex);
4347
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004348 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004349}
4350
Shahar Levi6d158ff2011-09-08 13:01:33 +03004351static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4352 struct ieee80211_channel_switch *ch_switch)
4353{
4354 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004355 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004356 int ret;
4357
4358 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4359
4360 mutex_lock(&wl->mutex);
4361
4362 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004363 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4364 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4365 ieee80211_chswitch_done(vif, false);
4366 }
4367 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004368 }
4369
4370 ret = wl1271_ps_elp_wakeup(wl);
4371 if (ret < 0)
4372 goto out;
4373
Eliad Peller52630c52011-10-10 10:13:08 +02004374 /* TODO: change mac80211 to pass vif as param */
4375 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004376 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004377
Eliad Peller52630c52011-10-10 10:13:08 +02004378 if (!ret)
4379 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4380 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004381
4382 wl1271_ps_elp_sleep(wl);
4383
4384out:
4385 mutex_unlock(&wl->mutex);
4386}
4387
Arik Nemtsov33437892011-04-26 23:35:39 +03004388static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4389{
4390 struct wl1271 *wl = hw->priv;
4391 bool ret = false;
4392
4393 mutex_lock(&wl->mutex);
4394
4395 if (unlikely(wl->state == WL1271_STATE_OFF))
4396 goto out;
4397
4398 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004399 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004400out:
4401 mutex_unlock(&wl->mutex);
4402
4403 return ret;
4404}
4405
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004406/* can't be const, mac80211 writes to this */
4407static struct ieee80211_rate wl1271_rates[] = {
4408 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004409 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4410 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004411 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004412 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4413 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004414 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4415 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004416 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4417 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004418 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4419 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4423 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004424 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4425 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004426 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004427 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4428 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004429 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004430 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4431 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004432 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004433 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4434 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004435 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004436 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4437 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004438 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004439 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4440 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004442 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4443 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004444 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004445 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4446 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004447};
4448
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004449/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004450static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004451 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004452 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004453 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4454 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4455 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004456 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004457 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4458 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4459 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004460 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004461 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4462 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4463 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004464 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004465};
4466
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004467/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004468static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004469 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004470 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004471 7, /* CONF_HW_RXTX_RATE_MCS7 */
4472 6, /* CONF_HW_RXTX_RATE_MCS6 */
4473 5, /* CONF_HW_RXTX_RATE_MCS5 */
4474 4, /* CONF_HW_RXTX_RATE_MCS4 */
4475 3, /* CONF_HW_RXTX_RATE_MCS3 */
4476 2, /* CONF_HW_RXTX_RATE_MCS2 */
4477 1, /* CONF_HW_RXTX_RATE_MCS1 */
4478 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004479
4480 11, /* CONF_HW_RXTX_RATE_54 */
4481 10, /* CONF_HW_RXTX_RATE_48 */
4482 9, /* CONF_HW_RXTX_RATE_36 */
4483 8, /* CONF_HW_RXTX_RATE_24 */
4484
4485 /* TI-specific rate */
4486 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4487
4488 7, /* CONF_HW_RXTX_RATE_18 */
4489 6, /* CONF_HW_RXTX_RATE_12 */
4490 3, /* CONF_HW_RXTX_RATE_11 */
4491 5, /* CONF_HW_RXTX_RATE_9 */
4492 4, /* CONF_HW_RXTX_RATE_6 */
4493 2, /* CONF_HW_RXTX_RATE_5_5 */
4494 1, /* CONF_HW_RXTX_RATE_2 */
4495 0 /* CONF_HW_RXTX_RATE_1 */
4496};
4497
Shahar Levie8b03a22010-10-13 16:09:39 +02004498/* 11n STA capabilities */
4499#define HW_RX_HIGHEST_RATE 72
4500
Shahar Levi00d20102010-11-08 11:20:10 +00004501#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004502 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4503 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004504 .ht_supported = true, \
4505 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4506 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4507 .mcs = { \
4508 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4509 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4510 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4511 }, \
4512}
4513
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004514/* can't be const, mac80211 writes to this */
4515static struct ieee80211_supported_band wl1271_band_2ghz = {
4516 .channels = wl1271_channels,
4517 .n_channels = ARRAY_SIZE(wl1271_channels),
4518 .bitrates = wl1271_rates,
4519 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004520 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004521};
4522
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004523/* 5 GHz data rates for WL1273 */
4524static struct ieee80211_rate wl1271_rates_5ghz[] = {
4525 { .bitrate = 60,
4526 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4527 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4528 { .bitrate = 90,
4529 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4530 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4531 { .bitrate = 120,
4532 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4533 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4534 { .bitrate = 180,
4535 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4536 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4537 { .bitrate = 240,
4538 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4539 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4540 { .bitrate = 360,
4541 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4542 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4543 { .bitrate = 480,
4544 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4545 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4546 { .bitrate = 540,
4547 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4548 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4549};
4550
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004551/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004552static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004553 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4554 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4555 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4556 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4557 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4558 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4559 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4560 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4561 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4562 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4563 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4564 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4565 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4566 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4567 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4568 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4569 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4570 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4571 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4572 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4573 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4574 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4575 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4576 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4577 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4578 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4579 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4580 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4581 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4582 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4583 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4584 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4585 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4586 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004587};
4588
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004589/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004590static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004591 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004592 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004593 7, /* CONF_HW_RXTX_RATE_MCS7 */
4594 6, /* CONF_HW_RXTX_RATE_MCS6 */
4595 5, /* CONF_HW_RXTX_RATE_MCS5 */
4596 4, /* CONF_HW_RXTX_RATE_MCS4 */
4597 3, /* CONF_HW_RXTX_RATE_MCS3 */
4598 2, /* CONF_HW_RXTX_RATE_MCS2 */
4599 1, /* CONF_HW_RXTX_RATE_MCS1 */
4600 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004601
4602 7, /* CONF_HW_RXTX_RATE_54 */
4603 6, /* CONF_HW_RXTX_RATE_48 */
4604 5, /* CONF_HW_RXTX_RATE_36 */
4605 4, /* CONF_HW_RXTX_RATE_24 */
4606
4607 /* TI-specific rate */
4608 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4609
4610 3, /* CONF_HW_RXTX_RATE_18 */
4611 2, /* CONF_HW_RXTX_RATE_12 */
4612 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4613 1, /* CONF_HW_RXTX_RATE_9 */
4614 0, /* CONF_HW_RXTX_RATE_6 */
4615 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4616 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4617 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4618};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004619
4620static struct ieee80211_supported_band wl1271_band_5ghz = {
4621 .channels = wl1271_channels_5ghz,
4622 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4623 .bitrates = wl1271_rates_5ghz,
4624 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004625 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004626};
4627
Tobias Klausera0ea9492010-05-20 10:38:11 +02004628static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004629 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4630 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4631};
4632
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004633static const struct ieee80211_ops wl1271_ops = {
4634 .start = wl1271_op_start,
4635 .stop = wl1271_op_stop,
4636 .add_interface = wl1271_op_add_interface,
4637 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004638 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004639#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004640 .suspend = wl1271_op_suspend,
4641 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004642#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004643 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004644 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004645 .configure_filter = wl1271_op_configure_filter,
4646 .tx = wl1271_op_tx,
4647 .set_key = wl1271_op_set_key,
4648 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004649 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004650 .sched_scan_start = wl1271_op_sched_scan_start,
4651 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004653 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004654 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004655 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004656 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004657 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004658 .sta_add = wl1271_op_sta_add,
4659 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004660 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004661 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004662 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004663 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004664 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004665};
4666
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004667
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004668u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004669{
4670 u8 idx;
4671
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004672 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004673
4674 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4675 wl1271_error("Illegal RX rate from HW: %d", rate);
4676 return 0;
4677 }
4678
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004679 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004680 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4681 wl1271_error("Unsupported RX rate from HW: %d", rate);
4682 return 0;
4683 }
4684
4685 return idx;
4686}
4687
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004688static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4689 struct device_attribute *attr,
4690 char *buf)
4691{
4692 struct wl1271 *wl = dev_get_drvdata(dev);
4693 ssize_t len;
4694
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004695 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004696
4697 mutex_lock(&wl->mutex);
4698 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4699 wl->sg_enabled);
4700 mutex_unlock(&wl->mutex);
4701
4702 return len;
4703
4704}
4705
4706static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4707 struct device_attribute *attr,
4708 const char *buf, size_t count)
4709{
4710 struct wl1271 *wl = dev_get_drvdata(dev);
4711 unsigned long res;
4712 int ret;
4713
Luciano Coelho6277ed62011-04-01 17:49:54 +03004714 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004715 if (ret < 0) {
4716 wl1271_warning("incorrect value written to bt_coex_mode");
4717 return count;
4718 }
4719
4720 mutex_lock(&wl->mutex);
4721
4722 res = !!res;
4723
4724 if (res == wl->sg_enabled)
4725 goto out;
4726
4727 wl->sg_enabled = res;
4728
4729 if (wl->state == WL1271_STATE_OFF)
4730 goto out;
4731
Ido Yariva6208652011-03-01 15:14:41 +02004732 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004733 if (ret < 0)
4734 goto out;
4735
4736 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4737 wl1271_ps_elp_sleep(wl);
4738
4739 out:
4740 mutex_unlock(&wl->mutex);
4741 return count;
4742}
4743
4744static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4745 wl1271_sysfs_show_bt_coex_state,
4746 wl1271_sysfs_store_bt_coex_state);
4747
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004748static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4749 struct device_attribute *attr,
4750 char *buf)
4751{
4752 struct wl1271 *wl = dev_get_drvdata(dev);
4753 ssize_t len;
4754
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004755 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004756
4757 mutex_lock(&wl->mutex);
4758 if (wl->hw_pg_ver >= 0)
4759 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4760 else
4761 len = snprintf(buf, len, "n/a\n");
4762 mutex_unlock(&wl->mutex);
4763
4764 return len;
4765}
4766
Gery Kahn6f07b722011-07-18 14:21:49 +03004767static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004768 wl1271_sysfs_show_hw_pg_ver, NULL);
4769
Ido Yariv95dac04f2011-06-06 14:57:06 +03004770static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4771 struct bin_attribute *bin_attr,
4772 char *buffer, loff_t pos, size_t count)
4773{
4774 struct device *dev = container_of(kobj, struct device, kobj);
4775 struct wl1271 *wl = dev_get_drvdata(dev);
4776 ssize_t len;
4777 int ret;
4778
4779 ret = mutex_lock_interruptible(&wl->mutex);
4780 if (ret < 0)
4781 return -ERESTARTSYS;
4782
4783 /* Let only one thread read the log at a time, blocking others */
4784 while (wl->fwlog_size == 0) {
4785 DEFINE_WAIT(wait);
4786
4787 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4788 &wait,
4789 TASK_INTERRUPTIBLE);
4790
4791 if (wl->fwlog_size != 0) {
4792 finish_wait(&wl->fwlog_waitq, &wait);
4793 break;
4794 }
4795
4796 mutex_unlock(&wl->mutex);
4797
4798 schedule();
4799 finish_wait(&wl->fwlog_waitq, &wait);
4800
4801 if (signal_pending(current))
4802 return -ERESTARTSYS;
4803
4804 ret = mutex_lock_interruptible(&wl->mutex);
4805 if (ret < 0)
4806 return -ERESTARTSYS;
4807 }
4808
4809 /* Check if the fwlog is still valid */
4810 if (wl->fwlog_size < 0) {
4811 mutex_unlock(&wl->mutex);
4812 return 0;
4813 }
4814
4815 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4816 len = min(count, (size_t)wl->fwlog_size);
4817 wl->fwlog_size -= len;
4818 memcpy(buffer, wl->fwlog, len);
4819
4820 /* Make room for new messages */
4821 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4822
4823 mutex_unlock(&wl->mutex);
4824
4825 return len;
4826}
4827
4828static struct bin_attribute fwlog_attr = {
4829 .attr = {.name = "fwlog", .mode = S_IRUSR},
4830 .read = wl1271_sysfs_read_fwlog,
4831};
4832
Luciano Coelho5e037e72011-12-23 09:32:17 +02004833static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4834{
4835 bool supported = false;
4836 u8 major, minor;
4837
4838 if (wl->chip.id == CHIP_ID_1283_PG20) {
4839 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4840 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4841
4842 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4843 if (major > 2 || (major == 2 && minor >= 1))
4844 supported = true;
4845 } else {
4846 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4847 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4848
4849 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4850 if (major == 3 && minor >= 1)
4851 supported = true;
4852 }
4853
4854 wl1271_debug(DEBUG_PROBE,
4855 "PG Ver major = %d minor = %d, MAC %s present",
4856 major, minor, supported ? "is" : "is not");
4857
4858 return supported;
4859}
4860
4861static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4862 u32 oui, u32 nic, int n)
4863{
4864 int i;
4865
4866 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4867 oui, nic, n);
4868
4869 if (nic + n - 1 > 0xffffff)
4870 wl1271_warning("NIC part of the MAC address wraps around!");
4871
4872 for (i = 0; i < n; i++) {
4873 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4874 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4875 wl->addresses[i].addr[2] = (u8) oui;
4876 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4877 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4878 wl->addresses[i].addr[5] = (u8) nic;
4879 nic++;
4880 }
4881
4882 wl->hw->wiphy->n_addresses = n;
4883 wl->hw->wiphy->addresses = wl->addresses;
4884}
4885
4886static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4887{
4888 u32 mac1, mac2;
4889
4890 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4891
4892 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4893 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4894
4895 /* these are the two parts of the BD_ADDR */
4896 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4897 ((mac1 & 0xff000000) >> 24);
4898 wl->fuse_nic_addr = mac1 & 0xffffff;
4899
4900 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4901}
4902
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004903static int wl12xx_get_hw_info(struct wl1271 *wl)
4904{
4905 int ret;
4906 u32 die_info;
4907
4908 ret = wl12xx_set_power_on(wl);
4909 if (ret < 0)
4910 goto out;
4911
4912 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4913
4914 if (wl->chip.id == CHIP_ID_1283_PG20)
4915 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4916 else
4917 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4918
4919 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4920
Luciano Coelho5e037e72011-12-23 09:32:17 +02004921 if (!wl12xx_mac_in_fuse(wl)) {
4922 wl->fuse_oui_addr = 0;
4923 wl->fuse_nic_addr = 0;
4924 } else {
4925 wl12xx_get_fuse_mac(wl);
4926 }
4927
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004928 wl1271_power_off(wl);
4929out:
4930 return ret;
4931}
4932
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004933static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004934{
4935 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004936 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004937
4938 if (wl->mac80211_registered)
4939 return 0;
4940
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004941 ret = wl12xx_get_hw_info(wl);
4942 if (ret < 0) {
4943 wl1271_error("couldn't get hw info");
4944 goto out;
4945 }
4946
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004947 ret = wl1271_fetch_nvs(wl);
4948 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004949 /* NOTE: The wl->nvs->nvs element must be first, in
4950 * order to simplify the casting, we assume it is at
4951 * the beginning of the wl->nvs structure.
4952 */
4953 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004954
Luciano Coelho5e037e72011-12-23 09:32:17 +02004955 oui_addr =
4956 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4957 nic_addr =
4958 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004959 }
4960
Luciano Coelho5e037e72011-12-23 09:32:17 +02004961 /* if the MAC address is zeroed in the NVS derive from fuse */
4962 if (oui_addr == 0 && nic_addr == 0) {
4963 oui_addr = wl->fuse_oui_addr;
4964 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4965 nic_addr = wl->fuse_nic_addr + 1;
4966 }
4967
4968 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969
4970 ret = ieee80211_register_hw(wl->hw);
4971 if (ret < 0) {
4972 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004973 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004974 }
4975
4976 wl->mac80211_registered = true;
4977
Eliad Pellerd60080a2010-11-24 12:53:16 +02004978 wl1271_debugfs_init(wl);
4979
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004980 register_netdevice_notifier(&wl1271_dev_notifier);
4981
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004982 wl1271_notice("loaded");
4983
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004984out:
4985 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004986}
4987
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004988static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004989{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004990 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02004991 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004992
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004993 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004994 ieee80211_unregister_hw(wl->hw);
4995 wl->mac80211_registered = false;
4996
4997}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004998
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004999static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005000{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005001 static const u32 cipher_suites[] = {
5002 WLAN_CIPHER_SUITE_WEP40,
5003 WLAN_CIPHER_SUITE_WEP104,
5004 WLAN_CIPHER_SUITE_TKIP,
5005 WLAN_CIPHER_SUITE_CCMP,
5006 WL1271_CIPHER_SUITE_GEM,
5007 };
5008
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005009 /* The tx descriptor buffer and the TKIP space. */
5010 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
5011 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005012
5013 /* unit us */
5014 /* FIXME: find a proper value */
5015 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005016 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005017
5018 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005019 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005020 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005021 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005022 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005023 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005024 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005025 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005026 IEEE80211_HW_AP_LINK_PS |
5027 IEEE80211_HW_AMPDU_AGGREGATION |
5028 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005029
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005030 wl->hw->wiphy->cipher_suites = cipher_suites;
5031 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5032
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005033 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005034 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5035 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005036 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005037 wl->hw->wiphy->max_sched_scan_ssids = 16;
5038 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005039 /*
5040 * Maximum length of elements in scanning probe request templates
5041 * should be the maximum length possible for a template, without
5042 * the IEEE80211 header of the template
5043 */
Eliad Peller154037d2011-08-14 13:17:12 +03005044 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005045 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005046
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005047 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5048 sizeof(struct ieee80211_header);
5049
Eliad Peller1ec23f72011-08-25 14:26:54 +03005050 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5051
Luciano Coelho4a31c112011-03-21 23:16:14 +02005052 /* make sure all our channels fit in the scanned_ch bitmask */
5053 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5054 ARRAY_SIZE(wl1271_channels_5ghz) >
5055 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005056 /*
5057 * We keep local copies of the band structs because we need to
5058 * modify them on a per-device basis.
5059 */
5060 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5061 sizeof(wl1271_band_2ghz));
5062 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5063 sizeof(wl1271_band_5ghz));
5064
5065 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5066 &wl->bands[IEEE80211_BAND_2GHZ];
5067 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5068 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005069
Kalle Valo12bd8942010-03-18 12:26:33 +02005070 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005071 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005072
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005073 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5074
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005075 /* the FW answers probe-requests in AP-mode */
5076 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5077 wl->hw->wiphy->probe_resp_offload =
5078 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5079 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5080 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5081
Felipe Balbia390e852011-10-06 10:07:44 +03005082 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005083
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005084 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005085 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005086
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005087 wl->hw->max_rx_aggregation_subframes = 8;
5088
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005089 return 0;
5090}
5091
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005092#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005093
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005094static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005095{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005096 struct ieee80211_hw *hw;
5097 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005098 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005099 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005100
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005101 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005102
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005103 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5104 if (!hw) {
5105 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005106 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005107 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005108 }
5109
5110 wl = hw->priv;
5111 memset(wl, 0, sizeof(*wl));
5112
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005113 INIT_LIST_HEAD(&wl->list);
Eliad Peller87627212011-10-10 10:12:54 +02005114 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005115
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005116 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005117
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005118 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005119 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005120 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5121
Ido Yariva6208652011-03-01 15:14:41 +02005122 skb_queue_head_init(&wl->deferred_rx_queue);
5123 skb_queue_head_init(&wl->deferred_tx_queue);
5124
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005125 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005126 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005127 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5128 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5129 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005130
Eliad Peller92ef8962011-06-07 12:50:46 +03005131 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5132 if (!wl->freezable_wq) {
5133 ret = -ENOMEM;
5134 goto err_hw;
5135 }
5136
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005137 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005138 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005139 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005140 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005141 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005142 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005143 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005144 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005145 wl->ap_ps_map = 0;
5146 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005147 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005148 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005149 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005150 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005151 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005152 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005153 wl->fwlog_size = 0;
5154 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005155
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005156 /* The system link is always allocated */
5157 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5158
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005159 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005160 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005161 wl->tx_frames[i] = NULL;
5162
5163 spin_lock_init(&wl->wl_lock);
5164
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005165 wl->state = WL1271_STATE_OFF;
5166 mutex_init(&wl->mutex);
5167
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005168 /* Apply default driver configuration. */
5169 wl1271_conf_init(wl);
5170
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005171 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5172 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5173 if (!wl->aggr_buf) {
5174 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005175 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005176 }
5177
Ido Yariv990f5de2011-03-31 10:06:59 +02005178 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5179 if (!wl->dummy_packet) {
5180 ret = -ENOMEM;
5181 goto err_aggr;
5182 }
5183
Ido Yariv95dac04f2011-06-06 14:57:06 +03005184 /* Allocate one page for the FW log */
5185 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5186 if (!wl->fwlog) {
5187 ret = -ENOMEM;
5188 goto err_dummy_packet;
5189 }
5190
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005191 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005192
Ido Yariv990f5de2011-03-31 10:06:59 +02005193err_dummy_packet:
5194 dev_kfree_skb(wl->dummy_packet);
5195
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005196err_aggr:
5197 free_pages((unsigned long)wl->aggr_buf, order);
5198
Eliad Peller92ef8962011-06-07 12:50:46 +03005199err_wq:
5200 destroy_workqueue(wl->freezable_wq);
5201
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005202err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005203 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005204 ieee80211_free_hw(hw);
5205
5206err_hw_alloc:
5207
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005208 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005209}
5210
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005211static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005212{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005213 /* Unblock any fwlog readers */
5214 mutex_lock(&wl->mutex);
5215 wl->fwlog_size = -1;
5216 wake_up_interruptible_all(&wl->fwlog_waitq);
5217 mutex_unlock(&wl->mutex);
5218
Felipe Balbif79f8902011-10-06 13:05:25 +03005219 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005220
Felipe Balbif79f8902011-10-06 13:05:25 +03005221 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005222
Felipe Balbif79f8902011-10-06 13:05:25 +03005223 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005224 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005225 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005226 free_pages((unsigned long)wl->aggr_buf,
5227 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005228
5229 wl1271_debugfs_exit(wl);
5230
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005231 vfree(wl->fw);
5232 wl->fw = NULL;
5233 kfree(wl->nvs);
5234 wl->nvs = NULL;
5235
5236 kfree(wl->fw_status);
5237 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005238 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005239
5240 ieee80211_free_hw(wl->hw);
5241
5242 return 0;
5243}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005244
Felipe Balbia390e852011-10-06 10:07:44 +03005245static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5246{
5247 struct wl1271 *wl = cookie;
5248 unsigned long flags;
5249
5250 wl1271_debug(DEBUG_IRQ, "IRQ");
5251
5252 /* complete the ELP completion */
5253 spin_lock_irqsave(&wl->wl_lock, flags);
5254 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5255 if (wl->elp_compl) {
5256 complete(wl->elp_compl);
5257 wl->elp_compl = NULL;
5258 }
5259
5260 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5261 /* don't enqueue a work right now. mark it as pending */
5262 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5263 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5264 disable_irq_nosync(wl->irq);
5265 pm_wakeup_event(wl->dev, 0);
5266 spin_unlock_irqrestore(&wl->wl_lock, flags);
5267 return IRQ_HANDLED;
5268 }
5269 spin_unlock_irqrestore(&wl->wl_lock, flags);
5270
5271 return IRQ_WAKE_THREAD;
5272}
5273
Felipe Balbice2a2172011-10-05 14:12:55 +03005274static int __devinit wl12xx_probe(struct platform_device *pdev)
5275{
Felipe Balbia390e852011-10-06 10:07:44 +03005276 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5277 struct ieee80211_hw *hw;
5278 struct wl1271 *wl;
5279 unsigned long irqflags;
5280 int ret = -ENODEV;
5281
5282 hw = wl1271_alloc_hw();
5283 if (IS_ERR(hw)) {
5284 wl1271_error("can't allocate hw");
5285 ret = PTR_ERR(hw);
5286 goto out;
5287 }
5288
5289 wl = hw->priv;
5290 wl->irq = platform_get_irq(pdev, 0);
5291 wl->ref_clock = pdata->board_ref_clock;
5292 wl->tcxo_clock = pdata->board_tcxo_clock;
5293 wl->platform_quirks = pdata->platform_quirks;
5294 wl->set_power = pdata->set_power;
5295 wl->dev = &pdev->dev;
5296 wl->if_ops = pdata->ops;
5297
5298 platform_set_drvdata(pdev, wl);
5299
5300 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5301 irqflags = IRQF_TRIGGER_RISING;
5302 else
5303 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5304
5305 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5306 irqflags,
5307 pdev->name, wl);
5308 if (ret < 0) {
5309 wl1271_error("request_irq() failed: %d", ret);
5310 goto out_free_hw;
5311 }
5312
5313 ret = enable_irq_wake(wl->irq);
5314 if (!ret) {
5315 wl->irq_wake_enabled = true;
5316 device_init_wakeup(wl->dev, 1);
5317 if (pdata->pwr_in_suspend)
5318 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5319
5320 }
5321 disable_irq(wl->irq);
5322
5323 ret = wl1271_init_ieee80211(wl);
5324 if (ret)
5325 goto out_irq;
5326
5327 ret = wl1271_register_hw(wl);
5328 if (ret)
5329 goto out_irq;
5330
Felipe Balbif79f8902011-10-06 13:05:25 +03005331 /* Create sysfs file to control bt coex state */
5332 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5333 if (ret < 0) {
5334 wl1271_error("failed to create sysfs file bt_coex_state");
5335 goto out_irq;
5336 }
5337
5338 /* Create sysfs file to get HW PG version */
5339 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5340 if (ret < 0) {
5341 wl1271_error("failed to create sysfs file hw_pg_ver");
5342 goto out_bt_coex_state;
5343 }
5344
5345 /* Create sysfs file for the FW log */
5346 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5347 if (ret < 0) {
5348 wl1271_error("failed to create sysfs file fwlog");
5349 goto out_hw_pg_ver;
5350 }
5351
Felipe Balbice2a2172011-10-05 14:12:55 +03005352 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005353
Felipe Balbif79f8902011-10-06 13:05:25 +03005354out_hw_pg_ver:
5355 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5356
5357out_bt_coex_state:
5358 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5359
Felipe Balbia390e852011-10-06 10:07:44 +03005360out_irq:
5361 free_irq(wl->irq, wl);
5362
5363out_free_hw:
5364 wl1271_free_hw(wl);
5365
5366out:
5367 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005368}
5369
5370static int __devexit wl12xx_remove(struct platform_device *pdev)
5371{
Felipe Balbia390e852011-10-06 10:07:44 +03005372 struct wl1271 *wl = platform_get_drvdata(pdev);
5373
5374 if (wl->irq_wake_enabled) {
5375 device_init_wakeup(wl->dev, 0);
5376 disable_irq_wake(wl->irq);
5377 }
5378 wl1271_unregister_hw(wl);
5379 free_irq(wl->irq, wl);
5380 wl1271_free_hw(wl);
5381
Felipe Balbice2a2172011-10-05 14:12:55 +03005382 return 0;
5383}
5384
5385static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005386 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005387 { } /* Terminating Entry */
5388};
5389MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5390
5391static struct platform_driver wl12xx_driver = {
5392 .probe = wl12xx_probe,
5393 .remove = __devexit_p(wl12xx_remove),
5394 .id_table = wl12xx_id_table,
5395 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005396 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005397 .owner = THIS_MODULE,
5398 }
5399};
5400
5401static int __init wl12xx_init(void)
5402{
5403 return platform_driver_register(&wl12xx_driver);
5404}
5405module_init(wl12xx_init);
5406
5407static void __exit wl12xx_exit(void)
5408{
5409 platform_driver_unregister(&wl12xx_driver);
5410}
5411module_exit(wl12xx_exit);
5412
Guy Eilam491bbd62011-01-12 10:33:29 +01005413u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005414EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005415module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005416MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5417
Ido Yariv95dac04f2011-06-06 14:57:06 +03005418module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005419MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005420 "FW logger options: continuous, ondemand, dbgpins or disable");
5421
Eliad Peller2a5bff02011-08-25 18:10:59 +03005422module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5423MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5424
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005425MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005426MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005427MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");