blob: fa61dfd2084c222e7b4dbcf36b28c7029319d9bb [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-Cohen958b20e02011-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,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300250 .keep_alive_interval = 55000,
251 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300252 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200253 .itrim = {
254 .enable = false,
255 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200256 },
257 .pm_config = {
258 .host_clk_settling_time = 5000,
259 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300260 },
261 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300262 .trigger_pacing = 1,
263 .avg_weight_rssi_beacon = 20,
264 .avg_weight_rssi_data = 10,
265 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100266 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 },
268 .scan = {
269 .min_dwell_time_active = 7500,
270 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100271 .min_dwell_time_passive = 100000,
272 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200273 .num_probe_reqs = 2,
274 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .sched_scan = {
276 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300277 .min_dwell_time_active = 30,
278 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300279 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300280 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300281 .num_probe_reqs = 2,
282 .rssi_threshold = -90,
283 .snr_threshold = 0,
284 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200285 .rf = {
286 .tx_per_channel_power_compensation_2 = {
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288 },
289 .tx_per_channel_power_compensation_5 = {
290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293 },
294 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100295 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300296 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100297 .tx_ba_win_size = 64,
298 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300299 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100300 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200301 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200302 .num_stations = 1,
303 .ssid_profiles = 1,
304 .rx_block_num = 70,
305 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300306 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200307 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200308 .min_req_rx_blocks = 22,
309 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200310 },
311 .mem_wl128x = {
312 .num_stations = 1,
313 .ssid_profiles = 1,
314 .rx_block_num = 40,
315 .tx_min_block_num = 40,
316 .dynamic_memory = 1,
317 .min_req_tx_blocks = 45,
318 .min_req_rx_blocks = 22,
319 .tx_min = 27,
320 },
Shahar Leviff868432011-04-11 15:41:46 +0300321 .fm_coex = {
322 .enable = true,
323 .swallow_period = 5,
324 .n_divider_fref_set_1 = 0xff, /* default */
325 .n_divider_fref_set_2 = 12,
326 .m_divider_fref_set_1 = 148,
327 .m_divider_fref_set_2 = 0xffff, /* default */
328 .coex_pll_stabilization_time = 0xffffffff, /* default */
329 .ldo_stabilization_time = 0xffff, /* default */
330 .fm_disturbed_band_margin = 0xff, /* default */
331 .swallow_clk_diff = 0xff, /* default */
332 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300333 .rx_streaming = {
334 .duration = 150,
335 .queues = 0x1,
336 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300337 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300338 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300339 .fwlog = {
340 .mode = WL12XX_FWLOG_ON_DEMAND,
341 .mem_blocks = 2,
342 .severity = 0,
343 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
344 .output = WL12XX_FWLOG_OUTPUT_HOST,
345 .threshold = 0,
346 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300347 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300348 .rate = {
349 .rate_retry_score = 32000,
350 .per_add = 8192,
351 .per_th1 = 2048,
352 .per_th2 = 4096,
353 .max_per = 8100,
354 .inverse_curiosity_factor = 5,
355 .tx_fail_low_th = 4,
356 .tx_fail_high_th = 10,
357 .per_alpha_shift = 4,
358 .per_add_shift = 13,
359 .per_beta1_shift = 10,
360 .per_beta2_shift = 8,
361 .rate_check_up = 2,
362 .rate_check_down = 12,
363 .rate_retry_policy = {
364 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00,
367 },
368 },
Eliad Peller94877752011-08-28 15:11:56 +0300369 .hangover = {
370 .recover_time = 0,
371 .hangover_period = 20,
372 .dynamic_mode = 1,
373 .early_termination_mode = 1,
374 .max_period = 20,
375 .min_period = 1,
376 .increase_delta = 1,
377 .decrease_delta = 2,
378 .quiet_time = 4,
379 .increase_time = 1,
380 .window_size = 16,
381 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300382};
383
Ido Yariv95dac04f2011-06-06 14:57:06 +0300384static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300385static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300386
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300387static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +0200388 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300389 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200390static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200391static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200392
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200393static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300394static LIST_HEAD(wl_list);
395
Eliad Pellerba8447f62011-10-10 10:13:00 +0200396static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
397 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300398{
399 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200400
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300401 if (operstate != IF_OPER_UP)
402 return 0;
403
Eliad Peller8181aec2011-10-10 10:13:04 +0200404 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300405 return 0;
406
Eliad Peller154da672011-10-05 11:55:53 +0200407 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300408 if (ret < 0)
409 return ret;
410
Eliad Peller0603d892011-10-05 11:55:51 +0200411 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300412
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300413 wl1271_info("Association completed.");
414 return 0;
415}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300416static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
417 void *arg)
418{
419 struct net_device *dev = arg;
420 struct wireless_dev *wdev;
421 struct wiphy *wiphy;
422 struct ieee80211_hw *hw;
423 struct wl1271 *wl;
424 struct wl1271 *wl_temp;
Eliad Pellerba8447f62011-10-10 10:13:00 +0200425 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300426 int ret = 0;
427
428 /* Check that this notification is for us. */
429 if (what != NETDEV_CHANGE)
430 return NOTIFY_DONE;
431
432 wdev = dev->ieee80211_ptr;
433 if (wdev == NULL)
434 return NOTIFY_DONE;
435
436 wiphy = wdev->wiphy;
437 if (wiphy == NULL)
438 return NOTIFY_DONE;
439
440 hw = wiphy_priv(wiphy);
441 if (hw == NULL)
442 return NOTIFY_DONE;
443
444 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200445 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300446 list_for_each_entry(wl, &wl_list, list) {
447 if (wl == wl_temp)
448 break;
449 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200450 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300451 if (wl != wl_temp)
452 return NOTIFY_DONE;
453
454 mutex_lock(&wl->mutex);
455
456 if (wl->state == WL1271_STATE_OFF)
457 goto out;
458
Eliad Peller6ab70912011-12-18 20:25:45 +0200459 if (dev->operstate != IF_OPER_UP)
460 goto out;
461 /*
462 * The correct behavior should be just getting the appropriate wlvif
463 * from the given dev, but currently we don't have a mac80211
464 * interface for it.
465 */
Eliad Pellerba8447f62011-10-10 10:13:00 +0200466 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200467 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
468
Eliad Pellerba8447f62011-10-10 10:13:00 +0200469 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
470 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300471
Eliad Pellerba8447f62011-10-10 10:13:00 +0200472 ret = wl1271_ps_elp_wakeup(wl);
473 if (ret < 0)
474 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475
Eliad Peller6ab70912011-12-18 20:25:45 +0200476 wl1271_check_operstate(wl, wlvif,
477 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300478
Eliad Pellerba8447f62011-10-10 10:13:00 +0200479 wl1271_ps_elp_sleep(wl);
480 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300481out:
482 mutex_unlock(&wl->mutex);
483
484 return NOTIFY_OK;
485}
486
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100487static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200488 struct regulatory_request *request)
489{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100490 struct ieee80211_supported_band *band;
491 struct ieee80211_channel *ch;
492 int i;
493
494 band = wiphy->bands[IEEE80211_BAND_5GHZ];
495 for (i = 0; i < band->n_channels; i++) {
496 ch = &band->channels[i];
497 if (ch->flags & IEEE80211_CHAN_DISABLED)
498 continue;
499
500 if (ch->flags & IEEE80211_CHAN_RADAR)
501 ch->flags |= IEEE80211_CHAN_NO_IBSS |
502 IEEE80211_CHAN_PASSIVE_SCAN;
503
504 }
505
506 return 0;
507}
508
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
510 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300511{
512 int ret = 0;
513
514 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200515 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300516 if (ret < 0)
517 goto out;
518
519 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200520 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300521 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200522 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300523out:
524 return ret;
525}
526
527/*
528 * this function is being called when the rx_streaming interval
529 * has beed changed or rx_streaming should be disabled
530 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200531int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532{
533 int ret = 0;
534 int period = wl->conf.rx_streaming.interval;
535
536 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200537 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300538 goto out;
539
540 /* reconfigure/disable according to new streaming_period */
541 if (period &&
Eliad Pellerba8447f62011-10-10 10:13:00 +0200542 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300543 (wl->conf.rx_streaming.always ||
544 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200545 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300546 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200547 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300548 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200549 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300550 }
551out:
552 return ret;
553}
554
555static void wl1271_rx_streaming_enable_work(struct work_struct *work)
556{
557 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200558 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
559 rx_streaming_enable_work);
560 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300561
562 mutex_lock(&wl->mutex);
563
Eliad Peller0744bdb2011-10-10 10:13:05 +0200564 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f62011-10-10 10:13:00 +0200565 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300566 (!wl->conf.rx_streaming.always &&
567 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
568 goto out;
569
570 if (!wl->conf.rx_streaming.interval)
571 goto out;
572
573 ret = wl1271_ps_elp_wakeup(wl);
574 if (ret < 0)
575 goto out;
576
Eliad Peller9eb599e2011-10-10 10:12:59 +0200577 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300578 if (ret < 0)
579 goto out_sleep;
580
581 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200582 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300583 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
584
585out_sleep:
586 wl1271_ps_elp_sleep(wl);
587out:
588 mutex_unlock(&wl->mutex);
589}
590
591static void wl1271_rx_streaming_disable_work(struct work_struct *work)
592{
593 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200594 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
595 rx_streaming_disable_work);
596 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300597
598 mutex_lock(&wl->mutex);
599
Eliad Peller0744bdb2011-10-10 10:13:05 +0200600 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300601 goto out;
602
603 ret = wl1271_ps_elp_wakeup(wl);
604 if (ret < 0)
605 goto out;
606
Eliad Peller9eb599e2011-10-10 10:12:59 +0200607 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300608 if (ret)
609 goto out_sleep;
610
611out_sleep:
612 wl1271_ps_elp_sleep(wl);
613out:
614 mutex_unlock(&wl->mutex);
615}
616
617static void wl1271_rx_streaming_timer(unsigned long data)
618{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200619 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
620 struct wl1271 *wl = wlvif->wl;
621 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300622}
623
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300624static void wl1271_conf_init(struct wl1271 *wl)
625{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300626
627 /*
628 * This function applies the default configuration to the driver. This
629 * function is invoked upon driver load (spi probe.)
630 *
631 * The configuration is stored in a run-time structure in order to
632 * facilitate for run-time adjustment of any of the parameters. Making
633 * changes to the configuration structure will apply the new values on
634 * the next interface up (wl1271_op_start.)
635 */
636
637 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300638 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300639
Ido Yariv95dac04f2011-06-06 14:57:06 +0300640 /* Adjust settings according to optional module parameters */
641 if (fwlog_param) {
642 if (!strcmp(fwlog_param, "continuous")) {
643 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
644 } else if (!strcmp(fwlog_param, "ondemand")) {
645 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
646 } else if (!strcmp(fwlog_param, "dbgpins")) {
647 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
648 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
649 } else if (!strcmp(fwlog_param, "disable")) {
650 wl->conf.fwlog.mem_blocks = 0;
651 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
652 } else {
653 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
654 }
655 }
656}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300657
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300658static int wl1271_plt_init(struct wl1271 *wl)
659{
Eliad Peller188e7f52011-12-06 12:15:06 +0200660 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300661
Shahar Levi49d750ca2011-03-06 16:32:09 +0200662 if (wl->chip.id == CHIP_ID_1283_PG20)
663 ret = wl128x_cmd_general_parms(wl);
664 else
665 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200666 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200667 return ret;
668
Shahar Levi49d750ca2011-03-06 16:32:09 +0200669 if (wl->chip.id == CHIP_ID_1283_PG20)
670 ret = wl128x_cmd_radio_parms(wl);
671 else
672 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200673 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200674 return ret;
675
Shahar Levi49d750ca2011-03-06 16:32:09 +0200676 if (wl->chip.id != CHIP_ID_1283_PG20) {
677 ret = wl1271_cmd_ext_radio_parms(wl);
678 if (ret < 0)
679 return ret;
680 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200681 if (ret < 0)
682 return ret;
683
Shahar Levi48a61472011-03-06 16:32:08 +0200684 /* Chip-specific initializations */
685 ret = wl1271_chip_specific_init(wl);
686 if (ret < 0)
687 return ret;
688
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300689 ret = wl1271_acx_init_mem_config(wl);
690 if (ret < 0)
691 return ret;
692
Eliad Peller7f0979882011-08-14 13:17:06 +0300693 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600694 if (ret < 0)
695 goto out_free_memmap;
696
Luciano Coelho12419cc2010-02-18 13:25:44 +0200697 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200698 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300699 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200700 goto out_free_memmap;
701
702 /* Configure for CAM power saving (ie. always active) */
703 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
704 if (ret < 0)
705 goto out_free_memmap;
706
707 /* configure PM */
708 ret = wl1271_acx_pm_config(wl);
709 if (ret < 0)
710 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300711
712 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200713
714 out_free_memmap:
715 kfree(wl->target_mem_map);
716 wl->target_mem_map = NULL;
717
718 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300719}
720
Eliad Peller6e8cd332011-10-10 10:13:13 +0200721static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
722 struct wl12xx_vif *wlvif,
723 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200724{
Arik Nemtsovda032092011-08-25 12:43:15 +0300725 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200726
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300728 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200729
730 /*
731 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300732 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200733 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300734 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200735 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200736
Arik Nemtsovda032092011-08-25 12:43:15 +0300737 /*
738 * Start high-level PS if the STA is asleep with enough blocks in FW.
739 * Make an exception if this is the only connected station. In this
740 * case FW-memory congestion is not a problem.
741 */
742 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200743 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200744}
745
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200747 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300748 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200750 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200751 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300752 u8 hlid, cnt;
753
754 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200755
756 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
757 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
758 wl1271_debug(DEBUG_PSM,
759 "link ps prev 0x%x cur 0x%x changed 0x%x",
760 wl->ap_fw_ps_map, cur_fw_ps_map,
761 wl->ap_fw_ps_map ^ cur_fw_ps_map);
762
763 wl->ap_fw_ps_map = cur_fw_ps_map;
764 }
765
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200766 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
767 lnk = &wl->links[hlid];
768 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200770 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
771 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200772
Eliad Peller6e8cd332011-10-10 10:13:13 +0200773 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
774 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200775 }
776}
777
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778static void wl12xx_fw_status(struct wl1271 *wl,
779 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200781 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200782 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200783 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300784 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300785 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300786
Eliad Peller4d56ad92011-08-14 13:17:05 +0300787 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200788
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300789 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
790 "drv_rx_counter = %d, tx_results_counter = %d)",
791 status->intr,
792 status->fw_rx_counter,
793 status->drv_rx_counter,
794 status->tx_results_counter);
795
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300796 for (i = 0; i < NUM_TX_QUEUES; i++) {
797 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300798 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300799 (status->tx_released_pkts[i] -
800 wl->tx_pkts_freed[i]) & 0xff;
801
802 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
803 }
804
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300805 /* prevent wrap-around in total blocks counter */
806 if (likely(wl->tx_blocks_freed <=
807 le32_to_cpu(status->total_released_blks)))
808 freed_blocks = le32_to_cpu(status->total_released_blks) -
809 wl->tx_blocks_freed;
810 else
811 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
812 le32_to_cpu(status->total_released_blks);
813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200815
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300816 wl->tx_allocated_blocks -= freed_blocks;
817
Eliad Peller4d56ad92011-08-14 13:17:05 +0300818 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200819
Eliad Peller4d56ad92011-08-14 13:17:05 +0300820 /*
821 * The FW might change the total number of TX memblocks before
822 * we get a notification about blocks being released. Thus, the
823 * available blocks calculation might yield a temporary result
824 * which is lower than the actual available blocks. Keeping in
825 * mind that only blocks that were allocated can be moved from
826 * TX to RX, tx_blocks_available should never decrease here.
827 */
828 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
829 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300830
Ido Yariva5225502010-10-12 14:49:10 +0200831 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200832 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200833 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834
Eliad Peller4d56ad92011-08-14 13:17:05 +0300835 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200836 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200837 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200838 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300839
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300840 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200841 getnstimeofday(&ts);
842 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
843 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300844}
845
Ido Yariva6208652011-03-01 15:14:41 +0200846static void wl1271_flush_deferred_work(struct wl1271 *wl)
847{
848 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200849
Ido Yariva6208652011-03-01 15:14:41 +0200850 /* Pass all received frames to the network stack */
851 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
852 ieee80211_rx_ni(wl->hw, skb);
853
854 /* Return sent skbs to the network stack */
855 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300856 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200857}
858
859static void wl1271_netstack_work(struct work_struct *work)
860{
861 struct wl1271 *wl =
862 container_of(work, struct wl1271, netstack_work);
863
864 do {
865 wl1271_flush_deferred_work(wl);
866 } while (skb_queue_len(&wl->deferred_rx_queue));
867}
868
869#define WL1271_IRQ_MAX_LOOPS 256
870
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300871static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300872{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300873 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300874 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200875 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200876 struct wl1271 *wl = (struct wl1271 *)cookie;
877 bool done = false;
878 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200879 unsigned long flags;
880
881 /* TX might be handled here, avoid redundant work */
882 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
883 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300884
Ido Yariv341b7cd2011-03-31 10:07:01 +0200885 /*
886 * In case edge triggered interrupt must be used, we cannot iterate
887 * more than once without introducing race conditions with the hardirq.
888 */
889 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
890 loopcount = 1;
891
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300892 mutex_lock(&wl->mutex);
893
894 wl1271_debug(DEBUG_IRQ, "IRQ work");
895
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200896 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300897 goto out;
898
Ido Yariva6208652011-03-01 15:14:41 +0200899 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300900 if (ret < 0)
901 goto out;
902
Ido Yariva6208652011-03-01 15:14:41 +0200903 while (!done && loopcount--) {
904 /*
905 * In order to avoid a race with the hardirq, clear the flag
906 * before acknowledging the chip. Since the mutex is held,
907 * wl1271_ps_elp_wakeup cannot be called concurrently.
908 */
909 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
910 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911
Eliad Peller4d56ad92011-08-14 13:17:05 +0300912 wl12xx_fw_status(wl, wl->fw_status);
913 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200914 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200915 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200916 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200917 continue;
918 }
919
Eliad Pellerccc83b02010-10-27 14:09:57 +0200920 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
921 wl1271_error("watchdog interrupt received! "
922 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300923 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200924
925 /* restarting the chip. ignore any other interrupt. */
926 goto out;
927 }
928
Ido Yariva6208652011-03-01 15:14:41 +0200929 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200930 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
931
Eliad Peller4d56ad92011-08-14 13:17:05 +0300932 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200933
Ido Yariva5225502010-10-12 14:49:10 +0200934 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200935 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200936 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300937 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200939 /*
940 * In order to avoid starvation of the TX path,
941 * call the work function directly.
942 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200943 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200944 } else {
945 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200946 }
947
Ido Yariv8aad2462011-03-01 15:14:38 +0200948 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300949 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200950 (wl->tx_results_count & 0xff))
951 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200952
953 /* Make sure the deferred queues don't get too long */
954 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
955 skb_queue_len(&wl->deferred_rx_queue);
956 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
957 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200958 }
959
960 if (intr & WL1271_ACX_INTR_EVENT_A) {
961 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
962 wl1271_event_handle(wl, 0);
963 }
964
965 if (intr & WL1271_ACX_INTR_EVENT_B) {
966 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
967 wl1271_event_handle(wl, 1);
968 }
969
970 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
971 wl1271_debug(DEBUG_IRQ,
972 "WL1271_ACX_INTR_INIT_COMPLETE");
973
974 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
975 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300976 }
977
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300978 wl1271_ps_elp_sleep(wl);
979
980out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200981 spin_lock_irqsave(&wl->wl_lock, flags);
982 /* In case TX was not handled here, queue TX work */
983 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
984 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300985 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200986 ieee80211_queue_work(wl->hw, &wl->tx_work);
987 spin_unlock_irqrestore(&wl->wl_lock, flags);
988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300989 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200990
991 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992}
993
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300994static int wl1271_fetch_firmware(struct wl1271 *wl)
995{
996 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200997 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300998 int ret;
999
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001000 if (wl->chip.id == CHIP_ID_1283_PG20)
1001 fw_name = WL128X_FW_NAME;
1002 else
1003 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +02001004
1005 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1006
Felipe Balbia390e852011-10-06 10:07:44 +03001007 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001008
1009 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001010 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001011 return ret;
1012 }
1013
1014 if (fw->size % 4) {
1015 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1016 fw->size);
1017 ret = -EILSEQ;
1018 goto out;
1019 }
1020
Arik Nemtsov166d5042010-10-16 21:44:57 +02001021 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001022 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001023 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001024
1025 if (!wl->fw) {
1026 wl1271_error("could not allocate memory for the firmware");
1027 ret = -ENOMEM;
1028 goto out;
1029 }
1030
1031 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001032 ret = 0;
1033
1034out:
1035 release_firmware(fw);
1036
1037 return ret;
1038}
1039
1040static int wl1271_fetch_nvs(struct wl1271 *wl)
1041{
1042 const struct firmware *fw;
1043 int ret;
1044
Felipe Balbia390e852011-10-06 10:07:44 +03001045 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001046
1047 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001048 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1049 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001050 return ret;
1051 }
1052
Shahar Levibc765bf2011-03-06 16:32:10 +02001053 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001054
1055 if (!wl->nvs) {
1056 wl1271_error("could not allocate memory for the nvs file");
1057 ret = -ENOMEM;
1058 goto out;
1059 }
1060
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001061 wl->nvs_len = fw->size;
1062
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001063out:
1064 release_firmware(fw);
1065
1066 return ret;
1067}
1068
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001069void wl12xx_queue_recovery_work(struct wl1271 *wl)
1070{
1071 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1072 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1073}
1074
Ido Yariv95dac04f2011-06-06 14:57:06 +03001075size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1076{
1077 size_t len = 0;
1078
1079 /* The FW log is a length-value list, find where the log end */
1080 while (len < maxlen) {
1081 if (memblock[len] == 0)
1082 break;
1083 if (len + memblock[len] + 1 > maxlen)
1084 break;
1085 len += memblock[len] + 1;
1086 }
1087
1088 /* Make sure we have enough room */
1089 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1090
1091 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1092 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1093 wl->fwlog_size += len;
1094
1095 return len;
1096}
1097
1098static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1099{
1100 u32 addr;
1101 u32 first_addr;
1102 u8 *block;
1103
1104 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1105 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1106 (wl->conf.fwlog.mem_blocks == 0))
1107 return;
1108
1109 wl1271_info("Reading FW panic log");
1110
1111 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1112 if (!block)
1113 return;
1114
1115 /*
1116 * Make sure the chip is awake and the logger isn't active.
1117 * This might fail if the firmware hanged.
1118 */
1119 if (!wl1271_ps_elp_wakeup(wl))
1120 wl12xx_cmd_stop_fwlog(wl);
1121
1122 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001123 wl12xx_fw_status(wl, wl->fw_status);
1124 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001125 if (!first_addr)
1126 goto out;
1127
1128 /* Traverse the memory blocks linked list */
1129 addr = first_addr;
1130 do {
1131 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1132 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1133 false);
1134
1135 /*
1136 * Memory blocks are linked to one another. The first 4 bytes
1137 * of each memory block hold the hardware address of the next
1138 * one. The last memory block points to the first one.
1139 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001140 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001141 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1142 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1143 break;
1144 } while (addr && (addr != first_addr));
1145
1146 wake_up_interruptible(&wl->fwlog_waitq);
1147
1148out:
1149 kfree(block);
1150}
1151
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152static void wl1271_recovery_work(struct work_struct *work)
1153{
1154 struct wl1271 *wl =
1155 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001156 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001157 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001158
1159 mutex_lock(&wl->mutex);
1160
1161 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001162 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001163
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001164 /* Avoid a recursive recovery */
1165 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1166
Ido Yariv95dac04f2011-06-06 14:57:06 +03001167 wl12xx_read_fwlog_panic(wl);
1168
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001169 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1170 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001171
Eliad Peller2a5bff02011-08-25 18:10:59 +03001172 BUG_ON(bug_on_recovery);
1173
Oz Krakowskib992c682011-06-26 10:36:02 +03001174 /*
1175 * Advance security sequence number to overcome potential progress
1176 * in the firmware during recovery. This doens't hurt if the network is
1177 * not encrypted.
1178 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001179 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f62011-10-10 10:13:00 +02001180 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001181 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001182 wlvif->tx_security_seq +=
1183 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1184 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001185
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001186 /* Prevent spurious TX during FW restart */
1187 ieee80211_stop_queues(wl->hw);
1188
Luciano Coelho33c2c062011-05-10 14:46:02 +03001189 if (wl->sched_scanning) {
1190 ieee80211_sched_scan_stopped(wl->hw);
1191 wl->sched_scanning = false;
1192 }
1193
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001194 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001195 while (!list_empty(&wl->wlvif_list)) {
1196 wlvif = list_first_entry(&wl->wlvif_list,
1197 struct wl12xx_vif, list);
1198 vif = wl12xx_wlvif_to_vif(wlvif);
1199 __wl1271_op_remove_interface(wl, vif, false);
1200 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001201 mutex_unlock(&wl->mutex);
1202 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001203
1204 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1205
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001206 ieee80211_restart_hw(wl->hw);
1207
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001208 /*
1209 * Its safe to enable TX now - the queues are stopped after a request
1210 * to restart the HW.
1211 */
1212 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001213 return;
1214out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001215 mutex_unlock(&wl->mutex);
1216}
1217
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218static void wl1271_fw_wakeup(struct wl1271 *wl)
1219{
1220 u32 elp_reg;
1221
1222 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001223 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001224}
1225
1226static int wl1271_setup(struct wl1271 *wl)
1227{
1228 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1229 if (!wl->fw_status)
1230 return -ENOMEM;
1231
1232 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1233 if (!wl->tx_res_if) {
1234 kfree(wl->fw_status);
1235 return -ENOMEM;
1236 }
1237
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238 return 0;
1239}
1240
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001241static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001242{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001243 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001244
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001245 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001246 ret = wl1271_power_on(wl);
1247 if (ret < 0)
1248 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001249 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001250 wl1271_io_reset(wl);
1251 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001252
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001253 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001254
1255 /* ELP module wake up */
1256 wl1271_fw_wakeup(wl);
1257
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001258out:
1259 return ret;
1260}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001261
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001262static int wl1271_chip_wakeup(struct wl1271 *wl)
1263{
1264 int ret = 0;
1265
1266 ret = wl12xx_set_power_on(wl);
1267 if (ret < 0)
1268 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001269
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001270 /*
1271 * For wl127x based devices we could use the default block
1272 * size (512 bytes), but due to a bug in the sdio driver, we
1273 * need to set it explicitly after the chip is powered on. To
1274 * simplify the code and since the performance impact is
1275 * negligible, we use the same block size for all different
1276 * chip types.
1277 */
1278 if (!wl1271_set_block_size(wl))
1279 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001280
1281 switch (wl->chip.id) {
1282 case CHIP_ID_1271_PG10:
1283 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1284 wl->chip.id);
1285
1286 ret = wl1271_setup(wl);
1287 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001288 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001289 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001290 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001291
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001292 case CHIP_ID_1271_PG20:
1293 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1294 wl->chip.id);
1295
1296 ret = wl1271_setup(wl);
1297 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001298 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001299 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001300 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001301
Shahar Levi0830cee2011-03-06 16:32:20 +02001302 case CHIP_ID_1283_PG20:
1303 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1304 wl->chip.id);
1305
1306 ret = wl1271_setup(wl);
1307 if (ret < 0)
1308 goto out;
1309 break;
1310 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001311 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001312 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001313 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001314 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 }
1316
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001317 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001318 ret = wl1271_fetch_firmware(wl);
1319 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001320 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001321 }
1322
1323 /* No NVS from netlink, try to get it from the filesystem */
1324 if (wl->nvs == NULL) {
1325 ret = wl1271_fetch_nvs(wl);
1326 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001327 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328 }
1329
1330out:
1331 return ret;
1332}
1333
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001334int wl1271_plt_start(struct wl1271 *wl)
1335{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001336 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001337 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001338 int ret;
1339
1340 mutex_lock(&wl->mutex);
1341
1342 wl1271_notice("power up");
1343
1344 if (wl->state != WL1271_STATE_OFF) {
1345 wl1271_error("cannot go into PLT state because not "
1346 "in off state: %d", wl->state);
1347 ret = -EBUSY;
1348 goto out;
1349 }
1350
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001351 while (retries) {
1352 retries--;
1353 ret = wl1271_chip_wakeup(wl);
1354 if (ret < 0)
1355 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001356
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001357 ret = wl1271_boot(wl);
1358 if (ret < 0)
1359 goto power_off;
1360
1361 ret = wl1271_plt_init(wl);
1362 if (ret < 0)
1363 goto irq_disable;
1364
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001365 wl->state = WL1271_STATE_PLT;
1366 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001367 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001368
Gery Kahn6f07b722011-07-18 14:21:49 +03001369 /* update hw/fw version info in wiphy struct */
1370 wiphy->hw_version = wl->chip.id;
1371 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1372 sizeof(wiphy->fw_version));
1373
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001374 goto out;
1375
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001376irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001377 mutex_unlock(&wl->mutex);
1378 /* Unlocking the mutex in the middle of handling is
1379 inherently unsafe. In this case we deem it safe to do,
1380 because we need to let any possibly pending IRQ out of
1381 the system (and while we are WL1271_STATE_OFF the IRQ
1382 work function will not do anything.) Also, any other
1383 possible concurrent operations will fail due to the
1384 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001385 wl1271_disable_interrupts(wl);
1386 wl1271_flush_deferred_work(wl);
1387 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001388 mutex_lock(&wl->mutex);
1389power_off:
1390 wl1271_power_off(wl);
1391 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001392
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001393 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1394 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001395out:
1396 mutex_unlock(&wl->mutex);
1397
1398 return ret;
1399}
1400
Ido Yarivf3df1332012-01-11 09:42:39 +02001401int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001402{
1403 int ret = 0;
1404
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001405 wl1271_notice("power down");
1406
Ido Yariv46b0cc92012-01-11 09:42:41 +02001407 /*
1408 * Interrupts must be disabled before setting the state to OFF.
1409 * Otherwise, the interrupt handler might be called and exit without
1410 * reading the interrupt status.
1411 */
1412 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001413 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001414 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001415 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001416
1417 /*
1418 * This will not necessarily enable interrupts as interrupts
1419 * may have been disabled when op_stop was called. It will,
1420 * however, balance the above call to disable_interrupts().
1421 */
1422 wl1271_enable_interrupts(wl);
1423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 wl1271_error("cannot power down because not in PLT "
1425 "state: %d", wl->state);
1426 ret = -EBUSY;
1427 goto out;
1428 }
1429
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001430 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001431
Ido Yariva6208652011-03-01 15:14:41 +02001432 wl1271_flush_deferred_work(wl);
1433 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001434 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001435 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001436
1437 mutex_lock(&wl->mutex);
1438 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001439 wl->flags = 0;
1440 wl->state = WL1271_STATE_OFF;
1441 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001442 mutex_unlock(&wl->mutex);
1443
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001444out:
1445 return ret;
1446}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001447
Johannes Berg7bb45682011-02-24 14:42:06 +01001448static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001449{
1450 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001451 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1452 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001453 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001454 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001455 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001456 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001457
Eliad Peller0f168012011-10-11 13:52:25 +02001458 if (vif)
1459 wlvif = wl12xx_vif_to_data(vif);
1460
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001461 mapping = skb_get_queue_mapping(skb);
1462 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001463
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001464 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001465
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001466 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001467
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001468 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001469 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001470 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001471 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001472 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001473 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001474 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001475
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001476 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1477 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1478
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001479 wl->tx_queue_count[q]++;
1480
1481 /*
1482 * The workqueue is slow to process the tx_queue and we need stop
1483 * the queue here, otherwise the queue will get too long.
1484 */
1485 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1486 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1487 ieee80211_stop_queue(wl->hw, mapping);
1488 set_bit(q, &wl->stopped_queues_map);
1489 }
1490
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001491 /*
1492 * The chip specific setup must run before the first TX packet -
1493 * before that, the tx_work will not be initialized!
1494 */
1495
Ido Yarivb07d4032011-03-01 15:14:43 +02001496 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1497 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001498 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001499
Arik Nemtsov04216da2011-08-14 13:17:38 +03001500out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001501 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001502}
1503
Shahar Leviae47c452011-03-06 16:32:14 +02001504int wl1271_tx_dummy_packet(struct wl1271 *wl)
1505{
Ido Yariv990f5de2011-03-31 10:06:59 +02001506 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001507 int q;
1508
1509 /* no need to queue a new dummy packet if one is already pending */
1510 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1511 return 0;
1512
1513 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001514
Ido Yariv990f5de2011-03-31 10:06:59 +02001515 spin_lock_irqsave(&wl->wl_lock, flags);
1516 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001517 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001518 spin_unlock_irqrestore(&wl->wl_lock, flags);
1519
1520 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1521 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001522 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001523
1524 /*
1525 * If the FW TX is busy, TX work will be scheduled by the threaded
1526 * interrupt handler function
1527 */
1528 return 0;
1529}
1530
1531/*
1532 * The size of the dummy packet should be at least 1400 bytes. However, in
1533 * order to minimize the number of bus transactions, aligning it to 512 bytes
1534 * boundaries could be beneficial, performance wise
1535 */
1536#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1537
Luciano Coelhocf27d862011-04-01 21:08:23 +03001538static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001539{
1540 struct sk_buff *skb;
1541 struct ieee80211_hdr_3addr *hdr;
1542 unsigned int dummy_packet_size;
1543
1544 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1545 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1546
1547 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001548 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001549 wl1271_warning("Failed to allocate a dummy packet skb");
1550 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001551 }
1552
1553 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1554
1555 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1556 memset(hdr, 0, sizeof(*hdr));
1557 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001558 IEEE80211_STYPE_NULLFUNC |
1559 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001560
Ido Yariv990f5de2011-03-31 10:06:59 +02001561 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001562
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001563 /* Dummy packets require the TID to be management */
1564 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001565
1566 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001567 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001568 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001569
Ido Yariv990f5de2011-03-31 10:06:59 +02001570 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001571}
1572
Ido Yariv990f5de2011-03-31 10:06:59 +02001573
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001574static struct notifier_block wl1271_dev_notifier = {
1575 .notifier_call = wl1271_dev_notify,
1576};
1577
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001578#ifdef CONFIG_PM
Eyal Shapiradae728f2012-02-02 12:03:39 +02001579static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1580 struct wl12xx_vif *wlvif)
1581{
1582 int ret = 0;
1583
1584 mutex_lock(&wl->mutex);
1585
1586 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
1587 goto out_unlock;
1588
1589 ret = wl1271_ps_elp_wakeup(wl);
1590 if (ret < 0)
1591 goto out_unlock;
1592
1593 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1594 wl->conf.conn.suspend_wake_up_event,
1595 wl->conf.conn.suspend_listen_interval);
1596
1597 if (ret < 0)
1598 wl1271_error("suspend: set wake up conditions failed: %d", ret);
1599
1600
1601 wl1271_ps_elp_sleep(wl);
1602
1603out_unlock:
1604 mutex_unlock(&wl->mutex);
1605 return ret;
1606
1607}
Eliad Peller94390642011-05-13 11:57:13 +03001608
Eliad Peller0603d892011-10-05 11:55:51 +02001609static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1610 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001611{
Eliad Pellere85d1622011-06-27 13:06:43 +03001612 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001613
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001614 mutex_lock(&wl->mutex);
1615
Eliad Peller53d40d02011-10-10 10:13:02 +02001616 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001617 goto out_unlock;
1618
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001619 ret = wl1271_ps_elp_wakeup(wl);
1620 if (ret < 0)
1621 goto out_unlock;
1622
Eliad Peller0603d892011-10-05 11:55:51 +02001623 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001624
1625 wl1271_ps_elp_sleep(wl);
1626out_unlock:
1627 mutex_unlock(&wl->mutex);
1628 return ret;
1629
1630}
1631
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001632static int wl1271_configure_suspend(struct wl1271 *wl,
1633 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001634{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001635 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
1636 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c82011-10-05 11:55:45 +02001637 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001638 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001639 return 0;
1640}
1641
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001642static void wl1271_configure_resume(struct wl1271 *wl,
1643 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001644{
Eyal Shapiradae728f2012-02-02 12:03:39 +02001645 int ret = 0;
Eliad Peller536129c82011-10-05 11:55:45 +02001646 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eyal Shapiradae728f2012-02-02 12:03:39 +02001647 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001648
Eyal Shapiradae728f2012-02-02 12:03:39 +02001649 if ((!is_ap) && (!is_sta))
Eliad Peller94390642011-05-13 11:57:13 +03001650 return;
1651
1652 mutex_lock(&wl->mutex);
1653 ret = wl1271_ps_elp_wakeup(wl);
1654 if (ret < 0)
1655 goto out;
1656
Eyal Shapiradae728f2012-02-02 12:03:39 +02001657 if (is_sta) {
1658 ret = wl1271_acx_wake_up_conditions(wl, wlvif,
1659 wl->conf.conn.wake_up_event,
1660 wl->conf.conn.listen_interval);
1661
1662 if (ret < 0)
1663 wl1271_error("resume: wake up conditions failed: %d",
1664 ret);
1665
1666 } else if (is_ap) {
1667 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
1668 }
Eliad Peller94390642011-05-13 11:57:13 +03001669
1670 wl1271_ps_elp_sleep(wl);
1671out:
1672 mutex_unlock(&wl->mutex);
1673}
1674
Eliad Peller402e48612011-05-13 11:57:09 +03001675static int wl1271_op_suspend(struct ieee80211_hw *hw,
1676 struct cfg80211_wowlan *wow)
1677{
1678 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001679 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001680 int ret;
1681
Eliad Peller402e48612011-05-13 11:57:09 +03001682 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001683 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001684
Eliad Peller4a859df2011-06-06 12:21:52 +03001685 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001686 wl12xx_for_each_wlvif(wl, wlvif) {
1687 ret = wl1271_configure_suspend(wl, wlvif);
1688 if (ret < 0) {
1689 wl1271_warning("couldn't prepare device to suspend");
1690 return ret;
1691 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001692 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001693 /* flush any remaining work */
1694 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001695
1696 /*
1697 * disable and re-enable interrupts in order to flush
1698 * the threaded_irq
1699 */
1700 wl1271_disable_interrupts(wl);
1701
1702 /*
1703 * set suspended flag to avoid triggering a new threaded_irq
1704 * work. no need for spinlock as interrupts are disabled.
1705 */
1706 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1707
1708 wl1271_enable_interrupts(wl);
1709 flush_work(&wl->tx_work);
Eliad Peller4a859df2011-06-06 12:21:52 +03001710 flush_delayed_work(&wl->elp_work);
1711
Eliad Peller402e48612011-05-13 11:57:09 +03001712 return 0;
1713}
1714
1715static int wl1271_op_resume(struct ieee80211_hw *hw)
1716{
1717 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001718 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001719 unsigned long flags;
1720 bool run_irq_work = false;
1721
Eliad Peller402e48612011-05-13 11:57:09 +03001722 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1723 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001724 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001725
1726 /*
1727 * re-enable irq_work enqueuing, and call irq_work directly if
1728 * there is a pending work.
1729 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001730 spin_lock_irqsave(&wl->wl_lock, flags);
1731 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1732 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1733 run_irq_work = true;
1734 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001735
Eliad Peller4a859df2011-06-06 12:21:52 +03001736 if (run_irq_work) {
1737 wl1271_debug(DEBUG_MAC80211,
1738 "run postponed irq_work directly");
1739 wl1271_irq(0, wl);
1740 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001741 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001742 wl12xx_for_each_wlvif(wl, wlvif) {
1743 wl1271_configure_resume(wl, wlvif);
1744 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001745 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001746
Eliad Peller402e48612011-05-13 11:57:09 +03001747 return 0;
1748}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001749#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001750
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001751static int wl1271_op_start(struct ieee80211_hw *hw)
1752{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001753 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1754
1755 /*
1756 * We have to delay the booting of the hardware because
1757 * we need to know the local MAC address before downloading and
1758 * initializing the firmware. The MAC address cannot be changed
1759 * after boot, and without the proper MAC address, the firmware
1760 * will not function properly.
1761 *
1762 * The MAC address is first known when the corresponding interface
1763 * is added. That is where we will initialize the hardware.
1764 */
1765
Eyal Shapirad18da7f2012-01-31 11:57:25 +02001766 return 0;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001767}
1768
1769static void wl1271_op_stop(struct ieee80211_hw *hw)
1770{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001771 struct wl1271 *wl = hw->priv;
1772 int i;
1773
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001774 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001775
Ido Yariv46b0cc92012-01-11 09:42:41 +02001776 /*
1777 * Interrupts must be disabled before setting the state to OFF.
1778 * Otherwise, the interrupt handler might be called and exit without
1779 * reading the interrupt status.
1780 */
1781 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001782 mutex_lock(&wl->mutex);
1783 if (wl->state == WL1271_STATE_OFF) {
1784 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001785
1786 /*
1787 * This will not necessarily enable interrupts as interrupts
1788 * may have been disabled when op_stop was called. It will,
1789 * however, balance the above call to disable_interrupts().
1790 */
1791 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001792 return;
1793 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001794
Eliad Pellerbaf62772011-10-10 10:12:52 +02001795 /*
1796 * this must be before the cancel_work calls below, so that the work
1797 * functions don't perform further work.
1798 */
1799 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001800 mutex_unlock(&wl->mutex);
1801
1802 mutex_lock(&wl_list_mutex);
1803 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001804 mutex_unlock(&wl_list_mutex);
1805
Eliad Pellerbaf62772011-10-10 10:12:52 +02001806 wl1271_flush_deferred_work(wl);
1807 cancel_delayed_work_sync(&wl->scan_complete_work);
1808 cancel_work_sync(&wl->netstack_work);
1809 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001810 cancel_delayed_work_sync(&wl->elp_work);
1811
1812 /* let's notify MAC80211 about the remaining pending TX frames */
1813 wl12xx_tx_reset(wl, true);
1814 mutex_lock(&wl->mutex);
1815
1816 wl1271_power_off(wl);
1817
1818 wl->band = IEEE80211_BAND_2GHZ;
1819
1820 wl->rx_counter = 0;
1821 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1822 wl->tx_blocks_available = 0;
1823 wl->tx_allocated_blocks = 0;
1824 wl->tx_results_count = 0;
1825 wl->tx_packets_count = 0;
1826 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001827 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1828 wl->ap_fw_ps_map = 0;
1829 wl->ap_ps_map = 0;
1830 wl->sched_scanning = false;
1831 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1832 memset(wl->links_map, 0, sizeof(wl->links_map));
1833 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1834 wl->active_sta_count = 0;
1835
1836 /* The system link is always allocated */
1837 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1838
1839 /*
1840 * this is performed after the cancel_work calls and the associated
1841 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1842 * get executed before all these vars have been reset.
1843 */
1844 wl->flags = 0;
1845
1846 wl->tx_blocks_freed = 0;
1847
1848 for (i = 0; i < NUM_TX_QUEUES; i++) {
1849 wl->tx_pkts_freed[i] = 0;
1850 wl->tx_allocated_pkts[i] = 0;
1851 }
1852
1853 wl1271_debugfs_reset(wl);
1854
1855 kfree(wl->fw_status);
1856 wl->fw_status = NULL;
1857 kfree(wl->tx_res_if);
1858 wl->tx_res_if = NULL;
1859 kfree(wl->target_mem_map);
1860 wl->target_mem_map = NULL;
1861
1862 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001863}
1864
Eliad Pellere5a359f2011-10-10 10:13:15 +02001865static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1866{
1867 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1868 WL12XX_MAX_RATE_POLICIES);
1869 if (policy >= WL12XX_MAX_RATE_POLICIES)
1870 return -EBUSY;
1871
1872 __set_bit(policy, wl->rate_policies_map);
1873 *idx = policy;
1874 return 0;
1875}
1876
1877static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1878{
1879 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1880 return;
1881
1882 __clear_bit(*idx, wl->rate_policies_map);
1883 *idx = WL12XX_MAX_RATE_POLICIES;
1884}
1885
Eliad Peller536129c82011-10-05 11:55:45 +02001886static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001887{
Eliad Peller536129c82011-10-05 11:55:45 +02001888 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001889 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001890 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001891 return WL1271_ROLE_P2P_GO;
1892 else
1893 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001894
1895 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001896 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001897 return WL1271_ROLE_P2P_CL;
1898 else
1899 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001900
Eliad Peller227e81e2011-08-14 13:17:26 +03001901 case BSS_TYPE_IBSS:
1902 return WL1271_ROLE_IBSS;
1903
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001904 default:
Eliad Peller536129c82011-10-05 11:55:45 +02001905 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 }
1907 return WL12XX_INVALID_ROLE_TYPE;
1908}
1909
Eliad Peller83587502011-10-10 10:12:53 +02001910static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001911{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001912 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001913 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001914
Eliad Peller48e93e42011-10-10 10:12:58 +02001915 /* clear everything but the persistent data */
1916 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001917
1918 switch (ieee80211_vif_type_p2p(vif)) {
1919 case NL80211_IFTYPE_P2P_CLIENT:
1920 wlvif->p2p = 1;
1921 /* fall-through */
1922 case NL80211_IFTYPE_STATION:
1923 wlvif->bss_type = BSS_TYPE_STA_BSS;
1924 break;
1925 case NL80211_IFTYPE_ADHOC:
1926 wlvif->bss_type = BSS_TYPE_IBSS;
1927 break;
1928 case NL80211_IFTYPE_P2P_GO:
1929 wlvif->p2p = 1;
1930 /* fall-through */
1931 case NL80211_IFTYPE_AP:
1932 wlvif->bss_type = BSS_TYPE_AP_BSS;
1933 break;
1934 default:
1935 wlvif->bss_type = MAX_BSS_TYPE;
1936 return -EOPNOTSUPP;
1937 }
1938
Eliad Peller0603d892011-10-05 11:55:51 +02001939 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001940 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001941 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001942
Eliad Pellere936bbe2011-10-05 11:55:56 +02001943 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1944 wlvif->bss_type == BSS_TYPE_IBSS) {
1945 /* init sta/ibss data */
1946 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001947 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1948 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1949 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001950 } else {
1951 /* init ap data */
1952 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1953 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001954 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1955 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1956 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1957 wl12xx_allocate_rate_policy(wl,
1958 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001959 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001960
Eliad Peller83587502011-10-10 10:12:53 +02001961 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1962 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001963 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001964 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001965 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001966 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1967
Eliad Peller1b92f152011-10-10 10:13:09 +02001968 /*
1969 * mac80211 configures some values globally, while we treat them
1970 * per-interface. thus, on init, we have to copy them from wl
1971 */
1972 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001973 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001974 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001975
Eliad Peller9eb599e2011-10-10 10:12:59 +02001976 INIT_WORK(&wlvif->rx_streaming_enable_work,
1977 wl1271_rx_streaming_enable_work);
1978 INIT_WORK(&wlvif->rx_streaming_disable_work,
1979 wl1271_rx_streaming_disable_work);
Eliad Peller876272142011-10-10 10:12:54 +02001980 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001981
Eliad Peller9eb599e2011-10-10 10:12:59 +02001982 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
1983 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001984 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001985}
1986
Eliad Peller1d095472011-10-10 10:12:49 +02001987static bool wl12xx_init_fw(struct wl1271 *wl)
1988{
1989 int retries = WL1271_BOOT_RETRIES;
1990 bool booted = false;
1991 struct wiphy *wiphy = wl->hw->wiphy;
1992 int ret;
1993
1994 while (retries) {
1995 retries--;
1996 ret = wl1271_chip_wakeup(wl);
1997 if (ret < 0)
1998 goto power_off;
1999
2000 ret = wl1271_boot(wl);
2001 if (ret < 0)
2002 goto power_off;
2003
2004 ret = wl1271_hw_init(wl);
2005 if (ret < 0)
2006 goto irq_disable;
2007
2008 booted = true;
2009 break;
2010
2011irq_disable:
2012 mutex_unlock(&wl->mutex);
2013 /* Unlocking the mutex in the middle of handling is
2014 inherently unsafe. In this case we deem it safe to do,
2015 because we need to let any possibly pending IRQ out of
2016 the system (and while we are WL1271_STATE_OFF the IRQ
2017 work function will not do anything.) Also, any other
2018 possible concurrent operations will fail due to the
2019 current state, hence the wl1271 struct should be safe. */
2020 wl1271_disable_interrupts(wl);
2021 wl1271_flush_deferred_work(wl);
2022 cancel_work_sync(&wl->netstack_work);
2023 mutex_lock(&wl->mutex);
2024power_off:
2025 wl1271_power_off(wl);
2026 }
2027
2028 if (!booted) {
2029 wl1271_error("firmware boot failed despite %d retries",
2030 WL1271_BOOT_RETRIES);
2031 goto out;
2032 }
2033
2034 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2035
2036 /* update hw/fw version info in wiphy struct */
2037 wiphy->hw_version = wl->chip.id;
2038 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2039 sizeof(wiphy->fw_version));
2040
2041 /*
2042 * Now we know if 11a is supported (info from the NVS), so disable
2043 * 11a channels if not supported
2044 */
2045 if (!wl->enable_11a)
2046 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2047
2048 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2049 wl->enable_11a ? "" : "not ");
2050
2051 wl->state = WL1271_STATE_ON;
2052out:
2053 return booted;
2054}
2055
Eliad Peller92e712d2011-12-18 20:25:43 +02002056static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2057{
2058 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2059}
2060
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002061static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2062 struct ieee80211_vif *vif)
2063{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002064 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002065 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002066 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002067 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002068 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002069
Johannes Bergea086352012-01-19 09:29:58 +01002070 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2071 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002072
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002073 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002074 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002075
2076 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002077 ret = wl1271_ps_elp_wakeup(wl);
2078 if (ret < 0)
2079 goto out_unlock;
2080
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002081 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002082 wl1271_debug(DEBUG_MAC80211,
2083 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002084 ret = -EBUSY;
2085 goto out;
2086 }
2087
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002088 /*
2089 * in some very corner case HW recovery scenarios its possible to
2090 * get here before __wl1271_op_remove_interface is complete, so
2091 * opt out if that is the case.
2092 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002093 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2094 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002095 ret = -EBUSY;
2096 goto out;
2097 }
2098
Eliad Peller83587502011-10-10 10:12:53 +02002099 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002100 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002101 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102
Eliad Peller252efa42011-10-05 11:56:00 +02002103 wlvif->wl = wl;
Eliad Peller536129c82011-10-05 11:55:45 +02002104 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002105 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2106 ret = -EINVAL;
2107 goto out;
2108 }
Eliad Peller1d095472011-10-10 10:12:49 +02002109
Eliad Peller784f6942011-10-05 11:55:39 +02002110 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002111 * TODO: after the nvs issue will be solved, move this block
2112 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002113 */
Eliad Peller1d095472011-10-10 10:12:49 +02002114 if (wl->state == WL1271_STATE_OFF) {
2115 /*
2116 * we still need this in order to configure the fw
2117 * while uploading the nvs
2118 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002119 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002120
Eliad Peller1d095472011-10-10 10:12:49 +02002121 booted = wl12xx_init_fw(wl);
2122 if (!booted) {
2123 ret = -EINVAL;
2124 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002125 }
Eliad Peller1d095472011-10-10 10:12:49 +02002126 }
Eliad Peller04e80792011-08-14 13:17:09 +03002127
Eliad Peller1d095472011-10-10 10:12:49 +02002128 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2129 wlvif->bss_type == BSS_TYPE_IBSS) {
2130 /*
2131 * The device role is a special role used for
2132 * rx and tx frames prior to association (as
2133 * the STA role can get packets only from
2134 * its associated bssid)
2135 */
Eliad Peller784f6942011-10-05 11:55:39 +02002136 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002137 WL1271_ROLE_DEVICE,
2138 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002139 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002140 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002141 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002142
Eliad Peller1d095472011-10-10 10:12:49 +02002143 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2144 role_type, &wlvif->role_id);
2145 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002146 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002147
2148 ret = wl1271_init_vif_specific(wl, vif);
2149 if (ret < 0)
2150 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002151
2152 wl->vif = vif;
Eliad Peller876272142011-10-10 10:12:54 +02002153 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002154 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002155
2156 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2157 wl->ap_count++;
2158 else
2159 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002160out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002161 wl1271_ps_elp_sleep(wl);
2162out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002163 mutex_unlock(&wl->mutex);
2164
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002165 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002166 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002167 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002168 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002169
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002170 return ret;
2171}
2172
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002173static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +02002174 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002175 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002176{
Eliad Peller536129c82011-10-05 11:55:45 +02002177 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002178 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002179
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002180 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181
Eliad Peller10c8cd02011-10-10 10:13:06 +02002182 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2183 return;
2184
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002185 wl->vif = NULL;
2186
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002187 /* because of hardware recovery, we may get here twice */
2188 if (wl->state != WL1271_STATE_ON)
2189 return;
2190
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002191 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002192
Eliad Pellerbaf62772011-10-10 10:12:52 +02002193 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2194 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002195 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002196 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002197 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002198 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002199 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002200 }
2201
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002202 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2203 /* disable active roles */
2204 ret = wl1271_ps_elp_wakeup(wl);
2205 if (ret < 0)
2206 goto deinit;
2207
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002208 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2209 wlvif->bss_type == BSS_TYPE_IBSS) {
2210 if (wl12xx_dev_role_started(wlvif))
2211 wl12xx_stop_dev(wl, wlvif);
2212
Eliad Peller7edebf52011-10-05 11:55:52 +02002213 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002214 if (ret < 0)
2215 goto deinit;
2216 }
2217
Eliad Peller0603d892011-10-05 11:55:51 +02002218 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002219 if (ret < 0)
2220 goto deinit;
2221
2222 wl1271_ps_elp_sleep(wl);
2223 }
2224deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002225 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002226 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002227
2228 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2229 wlvif->bss_type == BSS_TYPE_IBSS) {
2230 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2231 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2232 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2233 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2234 } else {
2235 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2236 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2237 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2238 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2239 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2240 wl12xx_free_rate_policy(wl,
2241 &wlvif->ap.ucast_rate_idx[i]);
2242 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002243
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002244 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002245 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002246 if (wl->last_wlvif == wlvif)
2247 wl->last_wlvif = NULL;
Eliad Peller876272142011-10-10 10:12:54 +02002248 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002249 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002250 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002251 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002252
Eliad Pellera4e41302011-10-11 11:49:15 +02002253 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2254 wl->ap_count--;
2255 else
2256 wl->sta_count--;
2257
Eliad Pellerbaf62772011-10-10 10:12:52 +02002258 mutex_unlock(&wl->mutex);
Eyal Shapirad6bf9ad2012-01-31 11:57:20 +02002259
Eliad Peller9eb599e2011-10-10 10:12:59 +02002260 del_timer_sync(&wlvif->rx_streaming_timer);
2261 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2262 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002263
Eliad Pellerbaf62772011-10-10 10:12:52 +02002264 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002265}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002266
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002267static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2268 struct ieee80211_vif *vif)
2269{
2270 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002271 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002272 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002273
2274 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002275
2276 if (wl->state == WL1271_STATE_OFF ||
2277 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2278 goto out;
2279
Juuso Oikarinen67353292010-11-18 15:19:02 +02002280 /*
2281 * wl->vif can be null here if someone shuts down the interface
2282 * just when hardware recovery has been started.
2283 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002284 wl12xx_for_each_wlvif(wl, iter) {
2285 if (iter != wlvif)
2286 continue;
2287
Eliad Peller536129c82011-10-05 11:55:45 +02002288 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002289 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002290 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002291 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002292out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002293 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002294 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002295}
2296
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002297static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2298 struct ieee80211_vif *vif,
2299 enum nl80211_iftype new_type, bool p2p)
2300{
2301 wl1271_op_remove_interface(hw, vif);
2302
2303 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2304 vif->p2p = p2p;
2305 return wl1271_op_add_interface(hw, vif);
2306}
2307
Eliad Peller87fbcb02011-10-05 11:55:41 +02002308static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2309 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002310{
2311 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002312 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002313
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002314 /*
2315 * One of the side effects of the JOIN command is that is clears
2316 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2317 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002318 * Currently the only valid scenario for JOIN during association
2319 * is on roaming, in which case we will also be given new keys.
2320 * Keep the below message for now, unless it starts bothering
2321 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002322 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002323 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002324 wl1271_info("JOIN while associated.");
2325
2326 if (set_assoc)
Eliad Pellerba8447f62011-10-10 10:13:00 +02002327 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002328
Eliad Peller227e81e2011-08-14 13:17:26 +03002329 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002330 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002331 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002332 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002333 if (ret < 0)
2334 goto out;
2335
Eliad Pellerba8447f62011-10-10 10:13:00 +02002336 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002337 goto out;
2338
2339 /*
2340 * The join command disable the keep-alive mode, shut down its process,
2341 * and also clear the template config, so we need to reset it all after
2342 * the join. The acx_aid starts the keep-alive process, and the order
2343 * of the commands below is relevant.
2344 */
Eliad Peller0603d892011-10-05 11:55:51 +02002345 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002346 if (ret < 0)
2347 goto out;
2348
Eliad Peller0603d892011-10-05 11:55:51 +02002349 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002350 if (ret < 0)
2351 goto out;
2352
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002353 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002354 if (ret < 0)
2355 goto out;
2356
Eliad Peller0603d892011-10-05 11:55:51 +02002357 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2358 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002359 ACX_KEEP_ALIVE_TPL_VALID);
2360 if (ret < 0)
2361 goto out;
2362
2363out:
2364 return ret;
2365}
2366
Eliad Peller0603d892011-10-05 11:55:51 +02002367static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002368{
2369 int ret;
2370
Eliad Peller52630c52011-10-10 10:13:08 +02002371 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002372 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2373
Shahar Levi6d158ff2011-09-08 13:01:33 +03002374 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002375 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002376 }
2377
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002378 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002379 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002380 if (ret < 0)
2381 goto out;
2382
Oz Krakowskib992c682011-06-26 10:36:02 +03002383 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002384 wlvif->tx_security_last_seq_lsb = 0;
2385 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002386
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002387out:
2388 return ret;
2389}
2390
Eliad Peller87fbcb02011-10-05 11:55:41 +02002391static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002392{
Eliad Peller1b92f152011-10-10 10:13:09 +02002393 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002394 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002395}
2396
Eliad Peller87fbcb02011-10-05 11:55:41 +02002397static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2398 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002399{
2400 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002401 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2402
2403 if (idle == cur_idle)
2404 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002405
2406 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002407 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002408 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002409 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002410 if (ret < 0)
2411 goto out;
2412 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002413 wlvif->rate_set =
2414 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2415 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002416 if (ret < 0)
2417 goto out;
2418 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002419 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002420 ACX_KEEP_ALIVE_TPL_INVALID);
2421 if (ret < 0)
2422 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002423 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002424 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002425 /* The current firmware only supports sched_scan in idle */
2426 if (wl->sched_scanning) {
2427 wl1271_scan_sched_scan_stop(wl);
2428 ieee80211_sched_scan_stopped(wl->hw);
2429 }
2430
Eliad Peller679a6732011-10-11 11:55:44 +02002431 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002432 if (ret < 0)
2433 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002434 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002435 }
2436
2437out:
2438 return ret;
2439}
2440
Eliad Peller9f259c42011-10-10 10:13:12 +02002441static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2442 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002443{
Eliad Peller9f259c42011-10-10 10:13:12 +02002444 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2445 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002446
2447 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2448
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002449 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002450 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002451 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002452 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002453 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002454 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002455 wlvif->band = conf->channel->band;
2456 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002457
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002458 if (!is_ap) {
2459 /*
2460 * FIXME: the mac80211 should really provide a fixed
2461 * rate to use here. for now, just use the smallest
2462 * possible rate for the band as a fixed rate for
2463 * association frames and other control messages.
2464 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002465 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002466 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002467
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002468 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002469 wl1271_tx_min_rate_get(wl,
2470 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002471 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002472 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002473 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002474 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002475
Eliad Pellerba8447f62011-10-10 10:13:00 +02002476 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2477 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002478 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002479 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002480 ret = wl12xx_croc(wl,
2481 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002482 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002483 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002484 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002485 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002486 if (ret < 0)
2487 wl1271_warning("cmd join on channel "
2488 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002489 } else {
2490 /*
2491 * change the ROC channel. do it only if we are
2492 * not idle. otherwise, CROC will be called
2493 * anyway.
2494 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002495 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002496 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002497 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002498 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002499 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002500
Eliad Peller679a6732011-10-11 11:55:44 +02002501 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002502 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002503 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002504 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002505 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002506 }
2507 }
2508
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002509 if ((changed & IEEE80211_CONF_CHANGE_PS) && !is_ap) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002510
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002511 if ((conf->flags & IEEE80211_CONF_PS) &&
2512 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
2513 !test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) {
2514
2515 wl1271_debug(DEBUG_PSM, "auto ps enabled");
2516
Eliad Peller0603d892011-10-05 11:55:51 +02002517 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002518 STATION_AUTO_PS_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002519 if (ret < 0)
2520 wl1271_warning("enter auto ps failed %d", ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002521
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002522 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
2523 test_bit(WLVIF_FLAG_IN_AUTO_PS, &wlvif->flags)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002524
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002525 wl1271_debug(DEBUG_PSM, "auto ps disabled");
2526
Eliad Peller0603d892011-10-05 11:55:51 +02002527 ret = wl1271_ps_set_mode(wl, wlvif,
Eyal Shapira248a0012012-01-31 11:57:23 +02002528 STATION_ACTIVE_MODE);
Eyal Shapirad18da7f2012-01-31 11:57:25 +02002529 if (ret < 0)
2530 wl1271_warning("exit auto ps failed %d", ret);
2531 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002532 }
2533
Eliad Peller6bd65022011-10-10 10:13:11 +02002534 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002535 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002536 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002537 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002538
Eliad Peller6bd65022011-10-10 10:13:11 +02002539 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002540 }
2541
Eliad Peller9f259c42011-10-10 10:13:12 +02002542 return 0;
2543}
2544
2545static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2546{
2547 struct wl1271 *wl = hw->priv;
2548 struct wl12xx_vif *wlvif;
2549 struct ieee80211_conf *conf = &hw->conf;
2550 int channel, ret = 0;
2551
2552 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2553
2554 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2555 " changed 0x%x",
2556 channel,
2557 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2558 conf->power_level,
2559 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2560 changed);
2561
2562 /*
2563 * mac80211 will go to idle nearly immediately after transmitting some
2564 * frames, such as the deauth. To make sure those frames reach the air,
2565 * wait here until the TX queue is fully flushed.
2566 */
2567 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2568 (conf->flags & IEEE80211_CONF_IDLE))
2569 wl1271_tx_flush(wl);
2570
2571 mutex_lock(&wl->mutex);
2572
2573 /* we support configuring the channel and band even while off */
2574 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2575 wl->band = conf->channel->band;
2576 wl->channel = channel;
2577 }
2578
2579 if (changed & IEEE80211_CONF_CHANGE_POWER)
2580 wl->power_level = conf->power_level;
2581
2582 if (unlikely(wl->state == WL1271_STATE_OFF))
2583 goto out;
2584
2585 ret = wl1271_ps_elp_wakeup(wl);
2586 if (ret < 0)
2587 goto out;
2588
2589 /* configure each interface */
2590 wl12xx_for_each_wlvif(wl, wlvif) {
2591 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2592 if (ret < 0)
2593 goto out_sleep;
2594 }
2595
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002596out_sleep:
2597 wl1271_ps_elp_sleep(wl);
2598
2599out:
2600 mutex_unlock(&wl->mutex);
2601
2602 return ret;
2603}
2604
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002605struct wl1271_filter_params {
2606 bool enabled;
2607 int mc_list_length;
2608 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2609};
2610
Jiri Pirko22bedad32010-04-01 21:22:57 +00002611static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2612 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002613{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002614 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002615 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002616 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002617
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002618 if (unlikely(wl->state == WL1271_STATE_OFF))
2619 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002620
Juuso Oikarinen74441132009-10-13 12:47:53 +03002621 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002622 if (!fp) {
2623 wl1271_error("Out of memory setting filters.");
2624 return 0;
2625 }
2626
2627 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002628 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002629 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2630 fp->enabled = false;
2631 } else {
2632 fp->enabled = true;
2633 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002634 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002635 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002636 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002637 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002638 }
2639
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002640 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002641}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002642
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002643#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2644 FIF_ALLMULTI | \
2645 FIF_FCSFAIL | \
2646 FIF_BCN_PRBRESP_PROMISC | \
2647 FIF_CONTROL | \
2648 FIF_OTHER_BSS)
2649
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002650static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2651 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002652 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002653{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002654 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002655 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002656 struct wl12xx_vif *wlvif;
Eliad Peller536129c82011-10-05 11:55:45 +02002657
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002658 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002659
Arik Nemtsov7d057862010-10-16 19:25:35 +02002660 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2661 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002662
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002663 mutex_lock(&wl->mutex);
2664
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002665 *total &= WL1271_SUPPORTED_FILTERS;
2666 changed &= WL1271_SUPPORTED_FILTERS;
2667
2668 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002669 goto out;
2670
Ido Yariva6208652011-03-01 15:14:41 +02002671 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002672 if (ret < 0)
2673 goto out;
2674
Eliad Peller6e8cd332011-10-10 10:13:13 +02002675 wl12xx_for_each_wlvif(wl, wlvif) {
2676 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2677 if (*total & FIF_ALLMULTI)
2678 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2679 false,
2680 NULL, 0);
2681 else if (fp)
2682 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2683 fp->enabled,
2684 fp->mc_list,
2685 fp->mc_list_length);
2686 if (ret < 0)
2687 goto out_sleep;
2688 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002689 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002691 /*
2692 * the fw doesn't provide an api to configure the filters. instead,
2693 * the filters configuration is based on the active roles / ROC
2694 * state.
2695 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002696
2697out_sleep:
2698 wl1271_ps_elp_sleep(wl);
2699
2700out:
2701 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002702 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002703}
2704
Eliad Peller170d0e62011-10-05 11:56:06 +02002705static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2706 u8 id, u8 key_type, u8 key_size,
2707 const u8 *key, u8 hlid, u32 tx_seq_32,
2708 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002709{
2710 struct wl1271_ap_key *ap_key;
2711 int i;
2712
2713 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2714
2715 if (key_size > MAX_KEY_SIZE)
2716 return -EINVAL;
2717
2718 /*
2719 * Find next free entry in ap_keys. Also check we are not replacing
2720 * an existing key.
2721 */
2722 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002723 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002724 break;
2725
Eliad Peller170d0e62011-10-05 11:56:06 +02002726 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002727 wl1271_warning("trying to record key replacement");
2728 return -EINVAL;
2729 }
2730 }
2731
2732 if (i == MAX_NUM_KEYS)
2733 return -EBUSY;
2734
2735 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2736 if (!ap_key)
2737 return -ENOMEM;
2738
2739 ap_key->id = id;
2740 ap_key->key_type = key_type;
2741 ap_key->key_size = key_size;
2742 memcpy(ap_key->key, key, key_size);
2743 ap_key->hlid = hlid;
2744 ap_key->tx_seq_32 = tx_seq_32;
2745 ap_key->tx_seq_16 = tx_seq_16;
2746
Eliad Peller170d0e62011-10-05 11:56:06 +02002747 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002748 return 0;
2749}
2750
Eliad Peller170d0e62011-10-05 11:56:06 +02002751static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002752{
2753 int i;
2754
2755 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002756 kfree(wlvif->ap.recorded_keys[i]);
2757 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002758 }
2759}
2760
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002761static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002762{
2763 int i, ret = 0;
2764 struct wl1271_ap_key *key;
2765 bool wep_key_added = false;
2766
2767 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002768 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002769 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002770 break;
2771
Eliad Peller170d0e62011-10-05 11:56:06 +02002772 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002773 hlid = key->hlid;
2774 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002775 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002776
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002777 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002778 key->id, key->key_type,
2779 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002780 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002781 key->tx_seq_16);
2782 if (ret < 0)
2783 goto out;
2784
2785 if (key->key_type == KEY_WEP)
2786 wep_key_added = true;
2787 }
2788
2789 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002790 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002791 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002792 if (ret < 0)
2793 goto out;
2794 }
2795
2796out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002797 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002798 return ret;
2799}
2800
Eliad Peller536129c82011-10-05 11:55:45 +02002801static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2802 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002803 u8 key_size, const u8 *key, u32 tx_seq_32,
2804 u16 tx_seq_16, struct ieee80211_sta *sta)
2805{
2806 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002807 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002808
2809 if (is_ap) {
2810 struct wl1271_station *wl_sta;
2811 u8 hlid;
2812
2813 if (sta) {
2814 wl_sta = (struct wl1271_station *)sta->drv_priv;
2815 hlid = wl_sta->hlid;
2816 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002817 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002818 }
2819
Eliad Peller53d40d02011-10-10 10:13:02 +02002820 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002821 /*
2822 * We do not support removing keys after AP shutdown.
2823 * Pretend we do to make mac80211 happy.
2824 */
2825 if (action != KEY_ADD_OR_REPLACE)
2826 return 0;
2827
Eliad Peller170d0e62011-10-05 11:56:06 +02002828 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002829 key_type, key_size,
2830 key, hlid, tx_seq_32,
2831 tx_seq_16);
2832 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002833 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 id, key_type, key_size,
2835 key, hlid, tx_seq_32,
2836 tx_seq_16);
2837 }
2838
2839 if (ret < 0)
2840 return ret;
2841 } else {
2842 const u8 *addr;
2843 static const u8 bcast_addr[ETH_ALEN] = {
2844 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2845 };
2846
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002847 /*
2848 * A STA set to GEM cipher requires 2 tx spare blocks.
2849 * Return to default value when GEM cipher key is removed
2850 */
2851 if (key_type == KEY_GEM) {
2852 if (action == KEY_ADD_OR_REPLACE)
2853 wl->tx_spare_blocks = 2;
2854 else if (action == KEY_REMOVE)
2855 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2856 }
2857
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002858 addr = sta ? sta->addr : bcast_addr;
2859
2860 if (is_zero_ether_addr(addr)) {
2861 /* We dont support TX only encryption */
2862 return -EOPNOTSUPP;
2863 }
2864
2865 /* The wl1271 does not allow to remove unicast keys - they
2866 will be cleared automatically on next CMD_JOIN. Ignore the
2867 request silently, as we dont want the mac80211 to emit
2868 an error message. */
2869 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2870 return 0;
2871
Eliad Peller010d3d32011-08-14 13:17:31 +03002872 /* don't remove key if hlid was already deleted */
2873 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002874 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002875 return 0;
2876
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002877 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002878 id, key_type, key_size,
2879 key, addr, tx_seq_32,
2880 tx_seq_16);
2881 if (ret < 0)
2882 return ret;
2883
2884 /* the default WEP key needs to be configured at least once */
2885 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002886 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002887 wlvif->default_key,
2888 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002889 if (ret < 0)
2890 return ret;
2891 }
2892 }
2893
2894 return 0;
2895}
2896
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002897static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2898 struct ieee80211_vif *vif,
2899 struct ieee80211_sta *sta,
2900 struct ieee80211_key_conf *key_conf)
2901{
2902 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002903 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002904 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002905 u32 tx_seq_32 = 0;
2906 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002907 u8 key_type;
2908
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002909 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2910
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002911 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002912 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002913 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002914 key_conf->keylen, key_conf->flags);
2915 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2916
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002917 mutex_lock(&wl->mutex);
2918
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002919 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2920 ret = -EAGAIN;
2921 goto out_unlock;
2922 }
2923
Ido Yariva6208652011-03-01 15:14:41 +02002924 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002925 if (ret < 0)
2926 goto out_unlock;
2927
Johannes Berg97359d12010-08-10 09:46:38 +02002928 switch (key_conf->cipher) {
2929 case WLAN_CIPHER_SUITE_WEP40:
2930 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002931 key_type = KEY_WEP;
2932
2933 key_conf->hw_key_idx = key_conf->keyidx;
2934 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002935 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002936 key_type = KEY_TKIP;
2937
2938 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002939 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2940 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002941 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002942 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943 key_type = KEY_AES;
2944
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002945 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002946 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2947 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002949 case WL1271_CIPHER_SUITE_GEM:
2950 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002951 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2952 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002953 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002954 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002955 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956
2957 ret = -EOPNOTSUPP;
2958 goto out_sleep;
2959 }
2960
2961 switch (cmd) {
2962 case SET_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02002963 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002964 key_conf->keyidx, key_type,
2965 key_conf->keylen, key_conf->key,
2966 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 if (ret < 0) {
2968 wl1271_error("Could not add or replace key");
2969 goto out_sleep;
2970 }
2971 break;
2972
2973 case DISABLE_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02002974 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002975 key_conf->keyidx, key_type,
2976 key_conf->keylen, key_conf->key,
2977 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002978 if (ret < 0) {
2979 wl1271_error("Could not remove key");
2980 goto out_sleep;
2981 }
2982 break;
2983
2984 default:
2985 wl1271_error("Unsupported key cmd 0x%x", cmd);
2986 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987 break;
2988 }
2989
2990out_sleep:
2991 wl1271_ps_elp_sleep(wl);
2992
2993out_unlock:
2994 mutex_unlock(&wl->mutex);
2995
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002996 return ret;
2997}
2998
2999static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003000 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003001 struct cfg80211_scan_request *req)
3002{
3003 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003004 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3005
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003006 int ret;
3007 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003008 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009
3010 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3011
3012 if (req->n_ssids) {
3013 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003014 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003015 }
3016
3017 mutex_lock(&wl->mutex);
3018
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003019 if (wl->state == WL1271_STATE_OFF) {
3020 /*
3021 * We cannot return -EBUSY here because cfg80211 will expect
3022 * a call to ieee80211_scan_completed if we do - in this case
3023 * there won't be any call.
3024 */
3025 ret = -EAGAIN;
3026 goto out;
3027 }
3028
Ido Yariva6208652011-03-01 15:14:41 +02003029 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003030 if (ret < 0)
3031 goto out;
3032
Eliad Peller92e712d2011-12-18 20:25:43 +02003033 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3034 test_bit(wlvif->role_id, wl->roc_map)) {
3035 /* don't allow scanning right now */
3036 ret = -EBUSY;
3037 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003038 }
3039
Eliad Peller92e712d2011-12-18 20:25:43 +02003040 /* cancel ROC before scanning */
3041 if (wl12xx_dev_role_started(wlvif))
Eliad Pellerc059beb2012-01-31 11:57:17 +02003042 wl12xx_croc(wl, wlvif->dev_role_id);
Eliad Peller92e712d2011-12-18 20:25:43 +02003043
Eliad Peller784f6942011-10-05 11:55:39 +02003044 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003045out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003047out:
3048 mutex_unlock(&wl->mutex);
3049
3050 return ret;
3051}
3052
Eliad Peller73ecce32011-06-27 13:06:45 +03003053static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3054 struct ieee80211_vif *vif)
3055{
3056 struct wl1271 *wl = hw->priv;
3057 int ret;
3058
3059 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3060
3061 mutex_lock(&wl->mutex);
3062
3063 if (wl->state == WL1271_STATE_OFF)
3064 goto out;
3065
3066 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3067 goto out;
3068
3069 ret = wl1271_ps_elp_wakeup(wl);
3070 if (ret < 0)
3071 goto out;
3072
3073 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3074 ret = wl1271_scan_stop(wl);
3075 if (ret < 0)
3076 goto out_sleep;
3077 }
3078 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3079 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003080 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003081 wl->scan.req = NULL;
3082 ieee80211_scan_completed(wl->hw, true);
3083
3084out_sleep:
3085 wl1271_ps_elp_sleep(wl);
3086out:
3087 mutex_unlock(&wl->mutex);
3088
3089 cancel_delayed_work_sync(&wl->scan_complete_work);
3090}
3091
Luciano Coelho33c2c062011-05-10 14:46:02 +03003092static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3093 struct ieee80211_vif *vif,
3094 struct cfg80211_sched_scan_request *req,
3095 struct ieee80211_sched_scan_ies *ies)
3096{
3097 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003098 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003099 int ret;
3100
3101 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3102
3103 mutex_lock(&wl->mutex);
3104
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003105 if (wl->state == WL1271_STATE_OFF) {
3106 ret = -EAGAIN;
3107 goto out;
3108 }
3109
Luciano Coelho33c2c062011-05-10 14:46:02 +03003110 ret = wl1271_ps_elp_wakeup(wl);
3111 if (ret < 0)
3112 goto out;
3113
Eliad Peller536129c82011-10-05 11:55:45 +02003114 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003115 if (ret < 0)
3116 goto out_sleep;
3117
Eliad Peller536129c82011-10-05 11:55:45 +02003118 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003119 if (ret < 0)
3120 goto out_sleep;
3121
3122 wl->sched_scanning = true;
3123
3124out_sleep:
3125 wl1271_ps_elp_sleep(wl);
3126out:
3127 mutex_unlock(&wl->mutex);
3128 return ret;
3129}
3130
3131static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3132 struct ieee80211_vif *vif)
3133{
3134 struct wl1271 *wl = hw->priv;
3135 int ret;
3136
3137 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3138
3139 mutex_lock(&wl->mutex);
3140
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003141 if (wl->state == WL1271_STATE_OFF)
3142 goto out;
3143
Luciano Coelho33c2c062011-05-10 14:46:02 +03003144 ret = wl1271_ps_elp_wakeup(wl);
3145 if (ret < 0)
3146 goto out;
3147
3148 wl1271_scan_sched_scan_stop(wl);
3149
3150 wl1271_ps_elp_sleep(wl);
3151out:
3152 mutex_unlock(&wl->mutex);
3153}
3154
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003155static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3156{
3157 struct wl1271 *wl = hw->priv;
3158 int ret = 0;
3159
3160 mutex_lock(&wl->mutex);
3161
3162 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3163 ret = -EAGAIN;
3164 goto out;
3165 }
3166
Ido Yariva6208652011-03-01 15:14:41 +02003167 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003168 if (ret < 0)
3169 goto out;
3170
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003171 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003172 if (ret < 0)
3173 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3174
3175 wl1271_ps_elp_sleep(wl);
3176
3177out:
3178 mutex_unlock(&wl->mutex);
3179
3180 return ret;
3181}
3182
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003183static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3184{
3185 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003186 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003187 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003188
3189 mutex_lock(&wl->mutex);
3190
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003191 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3192 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003193 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003194 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003195
Ido Yariva6208652011-03-01 15:14:41 +02003196 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003197 if (ret < 0)
3198 goto out;
3199
Eliad Peller6e8cd332011-10-10 10:13:13 +02003200 wl12xx_for_each_wlvif(wl, wlvif) {
3201 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3202 if (ret < 0)
3203 wl1271_warning("set rts threshold failed: %d", ret);
3204 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003205 wl1271_ps_elp_sleep(wl);
3206
3207out:
3208 mutex_unlock(&wl->mutex);
3209
3210 return ret;
3211}
3212
Eliad Peller1fe9f162011-10-05 11:55:48 +02003213static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003214 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003215{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003216 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003217 u8 ssid_len;
3218 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3219 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003220
Eliad Peller889cb362011-05-01 09:56:45 +03003221 if (!ptr) {
3222 wl1271_error("No SSID in IEs!");
3223 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003224 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003225
Eliad Peller889cb362011-05-01 09:56:45 +03003226 ssid_len = ptr[1];
3227 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3228 wl1271_error("SSID is too long!");
3229 return -EINVAL;
3230 }
3231
Eliad Peller1fe9f162011-10-05 11:55:48 +02003232 wlvif->ssid_len = ssid_len;
3233 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003234 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003235}
3236
Eliad Pellerd48055d2011-09-15 12:07:04 +03003237static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3238{
3239 int len;
3240 const u8 *next, *end = skb->data + skb->len;
3241 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3242 skb->len - ieoffset);
3243 if (!ie)
3244 return;
3245 len = ie[1] + 2;
3246 next = ie + len;
3247 memmove(ie, next, end - next);
3248 skb_trim(skb, skb->len - len);
3249}
3250
Eliad Peller26b4bf22011-09-15 12:07:05 +03003251static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3252 unsigned int oui, u8 oui_type,
3253 int ieoffset)
3254{
3255 int len;
3256 const u8 *next, *end = skb->data + skb->len;
3257 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3258 skb->data + ieoffset,
3259 skb->len - ieoffset);
3260 if (!ie)
3261 return;
3262 len = ie[1] + 2;
3263 next = ie + len;
3264 memmove(ie, next, end - next);
3265 skb_trim(skb, skb->len - len);
3266}
3267
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003268static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3269 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003270{
Eliad Pellercdaac622012-01-31 11:57:16 +02003271 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003272 struct sk_buff *skb;
3273 int ret;
3274
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003275 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003276 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003277 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003278
Eliad Pellercdaac622012-01-31 11:57:16 +02003279 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003280 CMD_TEMPL_AP_PROBE_RESPONSE,
3281 skb->data,
3282 skb->len, 0,
3283 rates);
3284
3285 dev_kfree_skb(skb);
3286 return ret;
3287}
3288
3289static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3290 struct ieee80211_vif *vif,
3291 u8 *probe_rsp_data,
3292 size_t probe_rsp_len,
3293 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003294{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003295 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3296 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003297 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3298 int ssid_ie_offset, ie_offset, templ_len;
3299 const u8 *ptr;
3300
3301 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003302 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003303 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003304 CMD_TEMPL_AP_PROBE_RESPONSE,
3305 probe_rsp_data,
3306 probe_rsp_len, 0,
3307 rates);
3308
3309 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3310 wl1271_error("probe_rsp template too big");
3311 return -EINVAL;
3312 }
3313
3314 /* start searching from IE offset */
3315 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3316
3317 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3318 probe_rsp_len - ie_offset);
3319 if (!ptr) {
3320 wl1271_error("No SSID in beacon!");
3321 return -EINVAL;
3322 }
3323
3324 ssid_ie_offset = ptr - probe_rsp_data;
3325 ptr += (ptr[1] + 2);
3326
3327 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3328
3329 /* insert SSID from bss_conf */
3330 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3331 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3332 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3333 bss_conf->ssid, bss_conf->ssid_len);
3334 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3335
3336 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3337 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3338 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3339
Eliad Pellercdaac622012-01-31 11:57:16 +02003340 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003341 CMD_TEMPL_AP_PROBE_RESPONSE,
3342 probe_rsp_templ,
3343 templ_len, 0,
3344 rates);
3345}
3346
Arik Nemtsove78a2872010-10-16 19:07:21 +02003347static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003348 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003349 struct ieee80211_bss_conf *bss_conf,
3350 u32 changed)
3351{
Eliad Peller0603d892011-10-05 11:55:51 +02003352 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003353 int ret = 0;
3354
3355 if (changed & BSS_CHANGED_ERP_SLOT) {
3356 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003357 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003358 else
Eliad Peller0603d892011-10-05 11:55:51 +02003359 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003360 if (ret < 0) {
3361 wl1271_warning("Set slot time failed %d", ret);
3362 goto out;
3363 }
3364 }
3365
3366 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3367 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003368 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003369 else
Eliad Peller0603d892011-10-05 11:55:51 +02003370 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003371 }
3372
3373 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3374 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003375 ret = wl1271_acx_cts_protect(wl, wlvif,
3376 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003377 else
Eliad Peller0603d892011-10-05 11:55:51 +02003378 ret = wl1271_acx_cts_protect(wl, wlvif,
3379 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 if (ret < 0) {
3381 wl1271_warning("Set ctsprotect failed %d", ret);
3382 goto out;
3383 }
3384 }
3385
3386out:
3387 return ret;
3388}
3389
3390static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3391 struct ieee80211_vif *vif,
3392 struct ieee80211_bss_conf *bss_conf,
3393 u32 changed)
3394{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003395 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003396 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003397 int ret = 0;
3398
3399 if ((changed & BSS_CHANGED_BEACON_INT)) {
3400 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3401 bss_conf->beacon_int);
3402
Eliad Peller6a899792011-10-05 11:55:58 +02003403 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003404 }
3405
Arik Nemtsov560f002412011-11-08 18:46:54 +02003406 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3407 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003408 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3409 wl1271_debug(DEBUG_AP, "probe response updated");
3410 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3411 }
Arik Nemtsov560f002412011-11-08 18:46:54 +02003412 }
3413
Arik Nemtsove78a2872010-10-16 19:07:21 +02003414 if ((changed & BSS_CHANGED_BEACON)) {
3415 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003416 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003417 int ieoffset = offsetof(struct ieee80211_mgmt,
3418 u.beacon.variable);
3419 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3420 u16 tmpl_id;
3421
Arik Nemtsov560f002412011-11-08 18:46:54 +02003422 if (!beacon) {
3423 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003424 goto out;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003425 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003426
3427 wl1271_debug(DEBUG_MASTER, "beacon updated");
3428
Eliad Peller1fe9f162011-10-05 11:55:48 +02003429 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003430 if (ret < 0) {
3431 dev_kfree_skb(beacon);
3432 goto out;
3433 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003434 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3436 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003437 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003438 beacon->data,
3439 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003440 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003441 if (ret < 0) {
3442 dev_kfree_skb(beacon);
3443 goto out;
3444 }
3445
Arik Nemtsov560f002412011-11-08 18:46:54 +02003446 /*
3447 * In case we already have a probe-resp beacon set explicitly
3448 * by usermode, don't use the beacon data.
3449 */
3450 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3451 goto end_bcn;
3452
Eliad Pellerd48055d2011-09-15 12:07:04 +03003453 /* remove TIM ie from probe response */
3454 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3455
Eliad Peller26b4bf22011-09-15 12:07:05 +03003456 /*
3457 * remove p2p ie from probe response.
3458 * the fw reponds to probe requests that don't include
3459 * the p2p ie. probe requests with p2p ie will be passed,
3460 * and will be responded by the supplicant (the spec
3461 * forbids including the p2p ie when responding to probe
3462 * requests that didn't include it).
3463 */
3464 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3465 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3466
Arik Nemtsove78a2872010-10-16 19:07:21 +02003467 hdr = (struct ieee80211_hdr *) beacon->data;
3468 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3469 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003470 if (is_ap)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003471 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003472 beacon->data,
3473 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003474 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003475 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003476 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003477 CMD_TEMPL_PROBE_RESPONSE,
3478 beacon->data,
3479 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003480 min_rate);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003481end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003482 dev_kfree_skb(beacon);
3483 if (ret < 0)
3484 goto out;
3485 }
3486
3487out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003488 if (ret != 0)
3489 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003490 return ret;
3491}
3492
3493/* AP mode changes */
3494static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003495 struct ieee80211_vif *vif,
3496 struct ieee80211_bss_conf *bss_conf,
3497 u32 changed)
3498{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003499 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003500 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003501
Arik Nemtsove78a2872010-10-16 19:07:21 +02003502 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3503 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003504
Eliad Peller87fbcb02011-10-05 11:55:41 +02003505 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003506 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003507 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003508 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003509
Eliad Peller87fbcb02011-10-05 11:55:41 +02003510 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003511 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003512 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003514 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003515
Eliad Peller784f6942011-10-05 11:55:39 +02003516 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003517 if (ret < 0)
3518 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003519 }
3520
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3522 if (ret < 0)
3523 goto out;
3524
3525 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3526 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003527 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003528 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003529 if (ret < 0)
3530 goto out;
3531
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003532 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003533 if (ret < 0)
3534 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003535
Eliad Peller53d40d02011-10-10 10:13:02 +02003536 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003537 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003538 }
3539 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003540 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003541 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0)
3543 goto out;
3544
Eliad Peller53d40d02011-10-10 10:13:02 +02003545 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003546 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3547 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003548 wl1271_debug(DEBUG_AP, "stopped AP");
3549 }
3550 }
3551 }
3552
Eliad Peller0603d892011-10-05 11:55:51 +02003553 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003554 if (ret < 0)
3555 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003556
3557 /* Handle HT information change */
3558 if ((changed & BSS_CHANGED_HT) &&
3559 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003560 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003561 bss_conf->ht_operation_mode);
3562 if (ret < 0) {
3563 wl1271_warning("Set ht information failed %d", ret);
3564 goto out;
3565 }
3566 }
3567
Arik Nemtsove78a2872010-10-16 19:07:21 +02003568out:
3569 return;
3570}
3571
3572/* STA/IBSS mode changes */
3573static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3574 struct ieee80211_vif *vif,
3575 struct ieee80211_bss_conf *bss_conf,
3576 u32 changed)
3577{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003578 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003580 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003581 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003582 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003583 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003584 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003585 bool sta_exists = false;
3586 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003587
3588 if (is_ibss) {
3589 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3590 changed);
3591 if (ret < 0)
3592 goto out;
3593 }
3594
Eliad Peller227e81e2011-08-14 13:17:26 +03003595 if (changed & BSS_CHANGED_IBSS) {
3596 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003597 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003598 ibss_joined = true;
3599 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003600 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3601 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003602 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003603 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003604 }
3605 }
3606 }
3607
3608 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003609 do_join = true;
3610
3611 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003613 do_join = true;
3614
Eliad Peller227e81e2011-08-14 13:17:26 +03003615 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003616 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3617 bss_conf->enable_beacon ? "enabled" : "disabled");
3618
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003619 do_join = true;
3620 }
3621
Eliad Pellerc31e4942011-10-23 08:21:55 +02003622 if (changed & BSS_CHANGED_IDLE) {
3623 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3624 if (ret < 0)
3625 wl1271_warning("idle mode change failed %d", ret);
3626 }
3627
Arik Nemtsove78a2872010-10-16 19:07:21 +02003628 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003629 bool enable = false;
3630 if (bss_conf->cqm_rssi_thold)
3631 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003632 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003633 bss_conf->cqm_rssi_thold,
3634 bss_conf->cqm_rssi_hyst);
3635 if (ret < 0)
3636 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003637 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003638 }
3639
Eliad Peller7db4ee62012-01-24 18:18:42 +02003640 if (changed & BSS_CHANGED_BSSID &&
3641 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003642 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003643 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003644 if (ret < 0)
3645 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003646
Eliad Peller784f6942011-10-05 11:55:39 +02003647 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003648 if (ret < 0)
3649 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003650
Eliad Pellerfa287b82010-12-26 09:27:50 +01003651 /* Need to update the BSSID (for filtering etc) */
3652 do_join = true;
3653 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003654
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003655 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3656 rcu_read_lock();
3657 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3658 if (!sta)
3659 goto sta_not_found;
3660
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003661 /* save the supp_rates of the ap */
3662 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3663 if (sta->ht_cap.ht_supported)
3664 sta_rate_set |=
3665 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003666 sta_ht_cap = sta->ht_cap;
3667 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003668
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003669sta_not_found:
3670 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003671 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003672
Arik Nemtsove78a2872010-10-16 19:07:21 +02003673 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003674 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003675 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003676 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003677 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003678 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003679
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003680 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003681 * use basic rates from AP, and determine lowest rate
3682 * to use with control frames.
3683 */
3684 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003685 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003686 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003687 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003688 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003689 wl1271_tx_min_rate_get(wl,
3690 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003691 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003692 wlvif->rate_set =
3693 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003694 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003695 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003696 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003697 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003698 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003699
3700 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003701 * with wl1271, we don't need to update the
3702 * beacon_int and dtim_period, because the firmware
3703 * updates it by itself when the first beacon is
3704 * received after a join.
3705 */
Eliad Peller6840e372011-10-05 11:55:50 +02003706 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003707 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003708 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003709
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003710 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003711 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003712 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003713 dev_kfree_skb(wlvif->probereq);
3714 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003715 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003716 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003717 ieoffset = offsetof(struct ieee80211_mgmt,
3718 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003719 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003720
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003721 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003722 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003723 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003724 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003725 } else {
3726 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003727 bool was_assoc =
Eliad Pellerba8447f62011-10-10 10:13:00 +02003728 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3729 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003730 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003731 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3732 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003733 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003734
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003735 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003736 dev_kfree_skb(wlvif->probereq);
3737 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003738
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003739 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003740 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003741 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003742 wl1271_tx_min_rate_get(wl,
3743 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003744 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003745 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003746 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003747
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003748 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003749 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003750
3751 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003752 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003753 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003754 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003755
3756 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003757 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003758 u32 conf_flags = wl->hw->conf.flags;
3759 /*
3760 * we might have to disable roc, if there was
3761 * no IF_OPER_UP notification.
3762 */
3763 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003764 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003765 if (ret < 0)
3766 goto out;
3767 }
3768 /*
3769 * (we also need to disable roc in case of
3770 * roaming on the same channel. until we will
3771 * have a better flow...)
3772 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003773 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3774 ret = wl12xx_croc(wl,
3775 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003776 if (ret < 0)
3777 goto out;
3778 }
3779
Eliad Peller0603d892011-10-05 11:55:51 +02003780 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003781 if (!(conf_flags & IEEE80211_CONF_IDLE))
3782 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003783 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003784 }
3785 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003786
Eliad Pellerd192d262011-05-24 14:33:08 +03003787 if (changed & BSS_CHANGED_IBSS) {
3788 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3789 bss_conf->ibss_joined);
3790
3791 if (bss_conf->ibss_joined) {
3792 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003793 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003794 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003795 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003796 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003797 wl1271_tx_min_rate_get(wl,
3798 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003799
Shahar Levi06b660e2011-09-05 13:54:36 +03003800 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003801 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3802 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003803 if (ret < 0)
3804 goto out;
3805 }
3806 }
3807
Eliad Peller0603d892011-10-05 11:55:51 +02003808 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003809 if (ret < 0)
3810 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003811
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003812 if (changed & BSS_CHANGED_ARP_FILTER) {
3813 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003814 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003815
Eliad Pellerc5312772010-12-09 11:31:27 +02003816 if (bss_conf->arp_addr_cnt == 1 &&
3817 bss_conf->arp_filter_enabled) {
3818 /*
3819 * The template should have been configured only upon
3820 * association. however, it seems that the correct ip
3821 * isn't being set (when sending), so we have to
3822 * reconfigure the template upon every ip change.
3823 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003824 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003825 if (ret < 0) {
3826 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003827 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003828 }
3829
Eliad Peller0603d892011-10-05 11:55:51 +02003830 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003831 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003832 addr);
3833 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003834 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003835
3836 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003837 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003838 }
3839
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003840 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003841 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003842 if (ret < 0) {
3843 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003844 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003845 }
Eliad Peller251c1772011-08-14 13:17:17 +03003846
3847 /* ROC until connected (after EAPOL exchange) */
3848 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003849 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003850 if (ret < 0)
3851 goto out;
3852
Eliad Pellerba8447f62011-10-10 10:13:00 +02003853 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003854 ieee80211_get_operstate(vif));
3855 }
3856 /*
3857 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003858 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003859 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003860 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003861 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003862 if (ret < 0)
3863 goto out;
3864 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003865 }
3866
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003867 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003868 if (sta_exists) {
3869 if ((changed & BSS_CHANGED_HT) &&
3870 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003871 ret = wl1271_acx_set_ht_capabilities(wl,
3872 &sta_ht_cap,
3873 true,
Eliad Peller154da672011-10-05 11:55:53 +02003874 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003875 if (ret < 0) {
3876 wl1271_warning("Set ht cap true failed %d",
3877 ret);
3878 goto out;
3879 }
3880 }
3881 /* handle new association without HT and disassociation */
3882 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003883 ret = wl1271_acx_set_ht_capabilities(wl,
3884 &sta_ht_cap,
3885 false,
Eliad Peller154da672011-10-05 11:55:53 +02003886 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003887 if (ret < 0) {
3888 wl1271_warning("Set ht cap false failed %d",
3889 ret);
3890 goto out;
3891 }
3892 }
3893 }
3894
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003895 /* Handle HT information change. Done after join. */
3896 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003897 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003898 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003899 bss_conf->ht_operation_mode);
3900 if (ret < 0) {
3901 wl1271_warning("Set ht information failed %d", ret);
3902 goto out;
3903 }
3904 }
3905
Arik Nemtsove78a2872010-10-16 19:07:21 +02003906out:
3907 return;
3908}
3909
3910static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3911 struct ieee80211_vif *vif,
3912 struct ieee80211_bss_conf *bss_conf,
3913 u32 changed)
3914{
3915 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003916 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3917 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003918 int ret;
3919
3920 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3921 (int)changed);
3922
3923 mutex_lock(&wl->mutex);
3924
3925 if (unlikely(wl->state == WL1271_STATE_OFF))
3926 goto out;
3927
Eliad Peller10c8cd02011-10-10 10:13:06 +02003928 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3929 goto out;
3930
Ido Yariva6208652011-03-01 15:14:41 +02003931 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003932 if (ret < 0)
3933 goto out;
3934
3935 if (is_ap)
3936 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3937 else
3938 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003940 wl1271_ps_elp_sleep(wl);
3941
3942out:
3943 mutex_unlock(&wl->mutex);
3944}
3945
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003946static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3947 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003948 const struct ieee80211_tx_queue_params *params)
3949{
3950 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02003951 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02003952 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003953 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02003954
3955 mutex_lock(&wl->mutex);
3956
3957 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
3958
Kalle Valo4695dc92010-03-18 12:26:38 +02003959 if (params->uapsd)
3960 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
3961 else
3962 ps_scheme = CONF_PS_SCHEME_LEGACY;
3963
Eliad Peller5b37ddf2011-12-18 20:25:40 +02003964 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003965 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003966
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003967 ret = wl1271_ps_elp_wakeup(wl);
3968 if (ret < 0)
3969 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02003970
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003971 /*
3972 * the txop is confed in units of 32us by the mac80211,
3973 * we need us
3974 */
Eliad Peller0603d892011-10-05 11:55:51 +02003975 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003976 params->cw_min, params->cw_max,
3977 params->aifs, params->txop << 5);
3978 if (ret < 0)
3979 goto out_sleep;
3980
Eliad Peller0603d892011-10-05 11:55:51 +02003981 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003982 CONF_CHANNEL_TYPE_EDCF,
3983 wl1271_tx_get_queue(queue),
3984 ps_scheme, CONF_ACK_POLICY_LEGACY,
3985 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02003986
3987out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02003988 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02003989
3990out:
3991 mutex_unlock(&wl->mutex);
3992
3993 return ret;
3994}
3995
Eliad Peller37a41b42011-09-21 14:06:11 +03003996static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
3997 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03003998{
3999
4000 struct wl1271 *wl = hw->priv;
Eliad Peller9c531142012-01-31 11:57:18 +02004001 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004002 u64 mactime = ULLONG_MAX;
4003 int ret;
4004
4005 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4006
4007 mutex_lock(&wl->mutex);
4008
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004009 if (unlikely(wl->state == WL1271_STATE_OFF))
4010 goto out;
4011
Ido Yariva6208652011-03-01 15:14:41 +02004012 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004013 if (ret < 0)
4014 goto out;
4015
Eliad Peller9c531142012-01-31 11:57:18 +02004016 ret = wl12xx_acx_tsf_info(wl, wlvif, &mactime);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004017 if (ret < 0)
4018 goto out_sleep;
4019
4020out_sleep:
4021 wl1271_ps_elp_sleep(wl);
4022
4023out:
4024 mutex_unlock(&wl->mutex);
4025 return mactime;
4026}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004027
John W. Linvilleece550d2010-07-28 16:41:06 -04004028static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4029 struct survey_info *survey)
4030{
4031 struct wl1271 *wl = hw->priv;
4032 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004033
John W. Linvilleece550d2010-07-28 16:41:06 -04004034 if (idx != 0)
4035 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004036
John W. Linvilleece550d2010-07-28 16:41:06 -04004037 survey->channel = conf->channel;
4038 survey->filled = SURVEY_INFO_NOISE_DBM;
4039 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004040
John W. Linvilleece550d2010-07-28 16:41:06 -04004041 return 0;
4042}
4043
Arik Nemtsov409622e2011-02-23 00:22:29 +02004044static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004045 struct wl12xx_vif *wlvif,
4046 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004047{
4048 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004049 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004050
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004051
4052 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004053 wl1271_warning("could not allocate HLID - too much stations");
4054 return -EBUSY;
4055 }
4056
4057 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004058 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4059 if (ret < 0) {
4060 wl1271_warning("could not allocate HLID - too many links");
4061 return -EBUSY;
4062 }
4063
4064 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004065 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004066 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004067 return 0;
4068}
4069
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004070void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004071{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004072 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004073 return;
4074
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004075 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004076 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004077 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004078 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004079 __clear_bit(hlid, &wl->ap_ps_map);
4080 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004081 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004082 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004083}
4084
4085static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4086 struct ieee80211_vif *vif,
4087 struct ieee80211_sta *sta)
4088{
4089 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004090 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004091 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004092 int ret = 0;
4093 u8 hlid;
4094
4095 mutex_lock(&wl->mutex);
4096
4097 if (unlikely(wl->state == WL1271_STATE_OFF))
4098 goto out;
4099
Eliad Peller536129c82011-10-05 11:55:45 +02004100 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004101 goto out;
4102
4103 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4104
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004105 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004106 if (ret < 0)
4107 goto out;
4108
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004109 wl_sta = (struct wl1271_station *)sta->drv_priv;
4110 hlid = wl_sta->hlid;
4111
Ido Yariva6208652011-03-01 15:14:41 +02004112 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004113 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004114 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004115
Eliad Peller1b92f152011-10-10 10:13:09 +02004116 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004117 if (ret < 0)
4118 goto out_sleep;
4119
Eliad Pellerb67476e2011-08-14 13:17:23 +03004120 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4121 if (ret < 0)
4122 goto out_sleep;
4123
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004124 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4125 if (ret < 0)
4126 goto out_sleep;
4127
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004128out_sleep:
4129 wl1271_ps_elp_sleep(wl);
4130
Arik Nemtsov409622e2011-02-23 00:22:29 +02004131out_free_sta:
4132 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004133 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004134
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004135out:
4136 mutex_unlock(&wl->mutex);
4137 return ret;
4138}
4139
4140static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4141 struct ieee80211_vif *vif,
4142 struct ieee80211_sta *sta)
4143{
4144 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004145 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004146 struct wl1271_station *wl_sta;
4147 int ret = 0, id;
4148
4149 mutex_lock(&wl->mutex);
4150
4151 if (unlikely(wl->state == WL1271_STATE_OFF))
4152 goto out;
4153
Eliad Peller536129c82011-10-05 11:55:45 +02004154 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004155 goto out;
4156
4157 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4158
4159 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004160 id = wl_sta->hlid;
4161 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004162 goto out;
4163
Ido Yariva6208652011-03-01 15:14:41 +02004164 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 if (ret < 0)
4166 goto out;
4167
Eliad Pellerc690ec82011-08-14 13:17:07 +03004168 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004169 if (ret < 0)
4170 goto out_sleep;
4171
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004172 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004173
4174out_sleep:
4175 wl1271_ps_elp_sleep(wl);
4176
4177out:
4178 mutex_unlock(&wl->mutex);
4179 return ret;
4180}
4181
Luciano Coelho4623ec72011-03-21 19:26:41 +02004182static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4183 struct ieee80211_vif *vif,
4184 enum ieee80211_ampdu_mlme_action action,
4185 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4186 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004187{
4188 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004189 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004190 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004191 u8 hlid, *ba_bitmap;
4192
4193 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4194 tid);
4195
4196 /* sanity check - the fields in FW are only 8bits wide */
4197 if (WARN_ON(tid > 0xFF))
4198 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004199
4200 mutex_lock(&wl->mutex);
4201
4202 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4203 ret = -EAGAIN;
4204 goto out;
4205 }
4206
Eliad Peller536129c82011-10-05 11:55:45 +02004207 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004208 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004209 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004210 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004211 struct wl1271_station *wl_sta;
4212
4213 wl_sta = (struct wl1271_station *)sta->drv_priv;
4214 hlid = wl_sta->hlid;
4215 ba_bitmap = &wl->links[hlid].ba_bitmap;
4216 } else {
4217 ret = -EINVAL;
4218 goto out;
4219 }
4220
Ido Yariva6208652011-03-01 15:14:41 +02004221 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004222 if (ret < 0)
4223 goto out;
4224
Shahar Levi70559a02011-05-22 16:10:22 +03004225 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4226 tid, action);
4227
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004228 switch (action) {
4229 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004230 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004231 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004232 break;
4233 }
4234
4235 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4236 ret = -EBUSY;
4237 wl1271_error("exceeded max RX BA sessions");
4238 break;
4239 }
4240
4241 if (*ba_bitmap & BIT(tid)) {
4242 ret = -EINVAL;
4243 wl1271_error("cannot enable RX BA session on active "
4244 "tid: %d", tid);
4245 break;
4246 }
4247
4248 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4249 hlid);
4250 if (!ret) {
4251 *ba_bitmap |= BIT(tid);
4252 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004253 }
4254 break;
4255
4256 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004257 if (!(*ba_bitmap & BIT(tid))) {
4258 ret = -EINVAL;
4259 wl1271_error("no active RX BA session on tid: %d",
4260 tid);
4261 break;
4262 }
4263
4264 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4265 hlid);
4266 if (!ret) {
4267 *ba_bitmap &= ~BIT(tid);
4268 wl->ba_rx_session_count--;
4269 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004270 break;
4271
4272 /*
4273 * The BA initiator session management in FW independently.
4274 * Falling break here on purpose for all TX APDU commands.
4275 */
4276 case IEEE80211_AMPDU_TX_START:
4277 case IEEE80211_AMPDU_TX_STOP:
4278 case IEEE80211_AMPDU_TX_OPERATIONAL:
4279 ret = -EINVAL;
4280 break;
4281
4282 default:
4283 wl1271_error("Incorrect ampdu action id=%x\n", action);
4284 ret = -EINVAL;
4285 }
4286
4287 wl1271_ps_elp_sleep(wl);
4288
4289out:
4290 mutex_unlock(&wl->mutex);
4291
4292 return ret;
4293}
4294
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004295static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4296 struct ieee80211_vif *vif,
4297 const struct cfg80211_bitrate_mask *mask)
4298{
Eliad Peller83587502011-10-10 10:12:53 +02004299 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004300 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004301 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004302
4303 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4304 mask->control[NL80211_BAND_2GHZ].legacy,
4305 mask->control[NL80211_BAND_5GHZ].legacy);
4306
4307 mutex_lock(&wl->mutex);
4308
4309 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004310 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004311 wl1271_tx_enabled_rates_get(wl,
4312 mask->control[i].legacy,
4313 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004314
4315 if (unlikely(wl->state == WL1271_STATE_OFF))
4316 goto out;
4317
4318 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4319 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4320
4321 ret = wl1271_ps_elp_wakeup(wl);
4322 if (ret < 0)
4323 goto out;
4324
4325 wl1271_set_band_rate(wl, wlvif);
4326 wlvif->basic_rate =
4327 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4328 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4329
4330 wl1271_ps_elp_sleep(wl);
4331 }
4332out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004333 mutex_unlock(&wl->mutex);
4334
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004335 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004336}
4337
Shahar Levi6d158ff2011-09-08 13:01:33 +03004338static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4339 struct ieee80211_channel_switch *ch_switch)
4340{
4341 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004342 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004343 int ret;
4344
4345 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4346
4347 mutex_lock(&wl->mutex);
4348
4349 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004350 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4351 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4352 ieee80211_chswitch_done(vif, false);
4353 }
4354 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004355 }
4356
4357 ret = wl1271_ps_elp_wakeup(wl);
4358 if (ret < 0)
4359 goto out;
4360
Eliad Peller52630c52011-10-10 10:13:08 +02004361 /* TODO: change mac80211 to pass vif as param */
4362 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller8332f0f2012-01-31 11:57:19 +02004363 ret = wl12xx_cmd_channel_switch(wl, wlvif, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004364
Eliad Peller52630c52011-10-10 10:13:08 +02004365 if (!ret)
4366 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4367 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004368
4369 wl1271_ps_elp_sleep(wl);
4370
4371out:
4372 mutex_unlock(&wl->mutex);
4373}
4374
Arik Nemtsov33437892011-04-26 23:35:39 +03004375static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4376{
4377 struct wl1271 *wl = hw->priv;
4378 bool ret = false;
4379
4380 mutex_lock(&wl->mutex);
4381
4382 if (unlikely(wl->state == WL1271_STATE_OFF))
4383 goto out;
4384
4385 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004386 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004387out:
4388 mutex_unlock(&wl->mutex);
4389
4390 return ret;
4391}
4392
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004393/* can't be const, mac80211 writes to this */
4394static struct ieee80211_rate wl1271_rates[] = {
4395 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004396 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4397 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004398 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004399 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4400 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004401 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4402 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004403 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4404 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004405 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4406 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004407 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4408 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004409 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4410 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004411 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4412 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004413 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004414 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4415 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004416 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004417 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4418 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004419 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004420 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4421 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004422 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004423 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4424 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004425 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004426 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4427 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004428 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004429 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4430 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004431 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004432 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4433 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004434};
4435
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004436/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004437static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004438 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004439 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004440 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4441 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4442 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004443 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004444 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4445 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4446 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004447 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004448 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4449 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4450 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004451 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004452};
4453
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004454/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004455static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004456 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004457 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004458 7, /* CONF_HW_RXTX_RATE_MCS7 */
4459 6, /* CONF_HW_RXTX_RATE_MCS6 */
4460 5, /* CONF_HW_RXTX_RATE_MCS5 */
4461 4, /* CONF_HW_RXTX_RATE_MCS4 */
4462 3, /* CONF_HW_RXTX_RATE_MCS3 */
4463 2, /* CONF_HW_RXTX_RATE_MCS2 */
4464 1, /* CONF_HW_RXTX_RATE_MCS1 */
4465 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004466
4467 11, /* CONF_HW_RXTX_RATE_54 */
4468 10, /* CONF_HW_RXTX_RATE_48 */
4469 9, /* CONF_HW_RXTX_RATE_36 */
4470 8, /* CONF_HW_RXTX_RATE_24 */
4471
4472 /* TI-specific rate */
4473 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4474
4475 7, /* CONF_HW_RXTX_RATE_18 */
4476 6, /* CONF_HW_RXTX_RATE_12 */
4477 3, /* CONF_HW_RXTX_RATE_11 */
4478 5, /* CONF_HW_RXTX_RATE_9 */
4479 4, /* CONF_HW_RXTX_RATE_6 */
4480 2, /* CONF_HW_RXTX_RATE_5_5 */
4481 1, /* CONF_HW_RXTX_RATE_2 */
4482 0 /* CONF_HW_RXTX_RATE_1 */
4483};
4484
Shahar Levie8b03a22010-10-13 16:09:39 +02004485/* 11n STA capabilities */
4486#define HW_RX_HIGHEST_RATE 72
4487
Shahar Levi00d20102010-11-08 11:20:10 +00004488#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004489 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4490 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004491 .ht_supported = true, \
4492 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4493 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4494 .mcs = { \
4495 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4496 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4497 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4498 }, \
4499}
4500
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004501/* can't be const, mac80211 writes to this */
4502static struct ieee80211_supported_band wl1271_band_2ghz = {
4503 .channels = wl1271_channels,
4504 .n_channels = ARRAY_SIZE(wl1271_channels),
4505 .bitrates = wl1271_rates,
4506 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004507 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004508};
4509
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004510/* 5 GHz data rates for WL1273 */
4511static struct ieee80211_rate wl1271_rates_5ghz[] = {
4512 { .bitrate = 60,
4513 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4514 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4515 { .bitrate = 90,
4516 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4517 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4518 { .bitrate = 120,
4519 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4520 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4521 { .bitrate = 180,
4522 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4523 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4524 { .bitrate = 240,
4525 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4526 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4527 { .bitrate = 360,
4528 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4529 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4530 { .bitrate = 480,
4531 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4532 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4533 { .bitrate = 540,
4534 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4535 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4536};
4537
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004538/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004539static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004540 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4541 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4542 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4543 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4544 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4545 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4546 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4547 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4548 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4549 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4550 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4551 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4552 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4553 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4554 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4555 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4556 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4557 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4558 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4559 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4560 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4561 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4562 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4563 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4564 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4565 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4566 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4567 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4568 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4569 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4570 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4571 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4572 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4573 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004574};
4575
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004576/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004577static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004578 /* MCS rates are used only with 11n */
Pontus Fuchsdefe02c2012-01-31 17:54:41 +02004579 7, /* CONF_HW_RXTX_RATE_MCS7_SGI */
Shahar Levi18357852010-10-13 16:09:41 +02004580 7, /* CONF_HW_RXTX_RATE_MCS7 */
4581 6, /* CONF_HW_RXTX_RATE_MCS6 */
4582 5, /* CONF_HW_RXTX_RATE_MCS5 */
4583 4, /* CONF_HW_RXTX_RATE_MCS4 */
4584 3, /* CONF_HW_RXTX_RATE_MCS3 */
4585 2, /* CONF_HW_RXTX_RATE_MCS2 */
4586 1, /* CONF_HW_RXTX_RATE_MCS1 */
4587 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004588
4589 7, /* CONF_HW_RXTX_RATE_54 */
4590 6, /* CONF_HW_RXTX_RATE_48 */
4591 5, /* CONF_HW_RXTX_RATE_36 */
4592 4, /* CONF_HW_RXTX_RATE_24 */
4593
4594 /* TI-specific rate */
4595 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4596
4597 3, /* CONF_HW_RXTX_RATE_18 */
4598 2, /* CONF_HW_RXTX_RATE_12 */
4599 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4600 1, /* CONF_HW_RXTX_RATE_9 */
4601 0, /* CONF_HW_RXTX_RATE_6 */
4602 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4603 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4604 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4605};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004606
4607static struct ieee80211_supported_band wl1271_band_5ghz = {
4608 .channels = wl1271_channels_5ghz,
4609 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4610 .bitrates = wl1271_rates_5ghz,
4611 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004612 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004613};
4614
Tobias Klausera0ea9492010-05-20 10:38:11 +02004615static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004616 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4617 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4618};
4619
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004620static const struct ieee80211_ops wl1271_ops = {
4621 .start = wl1271_op_start,
4622 .stop = wl1271_op_stop,
4623 .add_interface = wl1271_op_add_interface,
4624 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004625 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004626#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004627 .suspend = wl1271_op_suspend,
4628 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004629#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004630 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004631 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004632 .configure_filter = wl1271_op_configure_filter,
4633 .tx = wl1271_op_tx,
4634 .set_key = wl1271_op_set_key,
4635 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004636 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004637 .sched_scan_start = wl1271_op_sched_scan_start,
4638 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004639 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004640 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004641 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004642 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004643 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004644 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004645 .sta_add = wl1271_op_sta_add,
4646 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004647 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004648 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004649 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004650 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004651 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004652};
4653
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004654
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004655u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004656{
4657 u8 idx;
4658
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004659 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004660
4661 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4662 wl1271_error("Illegal RX rate from HW: %d", rate);
4663 return 0;
4664 }
4665
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004666 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004667 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4668 wl1271_error("Unsupported RX rate from HW: %d", rate);
4669 return 0;
4670 }
4671
4672 return idx;
4673}
4674
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004675static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4676 struct device_attribute *attr,
4677 char *buf)
4678{
4679 struct wl1271 *wl = dev_get_drvdata(dev);
4680 ssize_t len;
4681
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004682 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004683
4684 mutex_lock(&wl->mutex);
4685 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4686 wl->sg_enabled);
4687 mutex_unlock(&wl->mutex);
4688
4689 return len;
4690
4691}
4692
4693static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4694 struct device_attribute *attr,
4695 const char *buf, size_t count)
4696{
4697 struct wl1271 *wl = dev_get_drvdata(dev);
4698 unsigned long res;
4699 int ret;
4700
Luciano Coelho6277ed62011-04-01 17:49:54 +03004701 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004702 if (ret < 0) {
4703 wl1271_warning("incorrect value written to bt_coex_mode");
4704 return count;
4705 }
4706
4707 mutex_lock(&wl->mutex);
4708
4709 res = !!res;
4710
4711 if (res == wl->sg_enabled)
4712 goto out;
4713
4714 wl->sg_enabled = res;
4715
4716 if (wl->state == WL1271_STATE_OFF)
4717 goto out;
4718
Ido Yariva6208652011-03-01 15:14:41 +02004719 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004720 if (ret < 0)
4721 goto out;
4722
4723 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4724 wl1271_ps_elp_sleep(wl);
4725
4726 out:
4727 mutex_unlock(&wl->mutex);
4728 return count;
4729}
4730
4731static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4732 wl1271_sysfs_show_bt_coex_state,
4733 wl1271_sysfs_store_bt_coex_state);
4734
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004735static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4736 struct device_attribute *attr,
4737 char *buf)
4738{
4739 struct wl1271 *wl = dev_get_drvdata(dev);
4740 ssize_t len;
4741
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004742 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004743
4744 mutex_lock(&wl->mutex);
4745 if (wl->hw_pg_ver >= 0)
4746 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4747 else
4748 len = snprintf(buf, len, "n/a\n");
4749 mutex_unlock(&wl->mutex);
4750
4751 return len;
4752}
4753
Gery Kahn6f07b722011-07-18 14:21:49 +03004754static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004755 wl1271_sysfs_show_hw_pg_ver, NULL);
4756
Ido Yariv95dac04f2011-06-06 14:57:06 +03004757static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4758 struct bin_attribute *bin_attr,
4759 char *buffer, loff_t pos, size_t count)
4760{
4761 struct device *dev = container_of(kobj, struct device, kobj);
4762 struct wl1271 *wl = dev_get_drvdata(dev);
4763 ssize_t len;
4764 int ret;
4765
4766 ret = mutex_lock_interruptible(&wl->mutex);
4767 if (ret < 0)
4768 return -ERESTARTSYS;
4769
4770 /* Let only one thread read the log at a time, blocking others */
4771 while (wl->fwlog_size == 0) {
4772 DEFINE_WAIT(wait);
4773
4774 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4775 &wait,
4776 TASK_INTERRUPTIBLE);
4777
4778 if (wl->fwlog_size != 0) {
4779 finish_wait(&wl->fwlog_waitq, &wait);
4780 break;
4781 }
4782
4783 mutex_unlock(&wl->mutex);
4784
4785 schedule();
4786 finish_wait(&wl->fwlog_waitq, &wait);
4787
4788 if (signal_pending(current))
4789 return -ERESTARTSYS;
4790
4791 ret = mutex_lock_interruptible(&wl->mutex);
4792 if (ret < 0)
4793 return -ERESTARTSYS;
4794 }
4795
4796 /* Check if the fwlog is still valid */
4797 if (wl->fwlog_size < 0) {
4798 mutex_unlock(&wl->mutex);
4799 return 0;
4800 }
4801
4802 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4803 len = min(count, (size_t)wl->fwlog_size);
4804 wl->fwlog_size -= len;
4805 memcpy(buffer, wl->fwlog, len);
4806
4807 /* Make room for new messages */
4808 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4809
4810 mutex_unlock(&wl->mutex);
4811
4812 return len;
4813}
4814
4815static struct bin_attribute fwlog_attr = {
4816 .attr = {.name = "fwlog", .mode = S_IRUSR},
4817 .read = wl1271_sysfs_read_fwlog,
4818};
4819
Luciano Coelho5e037e72011-12-23 09:32:17 +02004820static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4821{
4822 bool supported = false;
4823 u8 major, minor;
4824
4825 if (wl->chip.id == CHIP_ID_1283_PG20) {
4826 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4827 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4828
4829 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4830 if (major > 2 || (major == 2 && minor >= 1))
4831 supported = true;
4832 } else {
4833 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4834 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4835
4836 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4837 if (major == 3 && minor >= 1)
4838 supported = true;
4839 }
4840
4841 wl1271_debug(DEBUG_PROBE,
4842 "PG Ver major = %d minor = %d, MAC %s present",
4843 major, minor, supported ? "is" : "is not");
4844
4845 return supported;
4846}
4847
4848static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4849 u32 oui, u32 nic, int n)
4850{
4851 int i;
4852
4853 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4854 oui, nic, n);
4855
4856 if (nic + n - 1 > 0xffffff)
4857 wl1271_warning("NIC part of the MAC address wraps around!");
4858
4859 for (i = 0; i < n; i++) {
4860 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4861 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4862 wl->addresses[i].addr[2] = (u8) oui;
4863 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4864 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4865 wl->addresses[i].addr[5] = (u8) nic;
4866 nic++;
4867 }
4868
4869 wl->hw->wiphy->n_addresses = n;
4870 wl->hw->wiphy->addresses = wl->addresses;
4871}
4872
4873static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4874{
4875 u32 mac1, mac2;
4876
4877 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4878
4879 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4880 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4881
4882 /* these are the two parts of the BD_ADDR */
4883 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4884 ((mac1 & 0xff000000) >> 24);
4885 wl->fuse_nic_addr = mac1 & 0xffffff;
4886
4887 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4888}
4889
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004890static int wl12xx_get_hw_info(struct wl1271 *wl)
4891{
4892 int ret;
4893 u32 die_info;
4894
4895 ret = wl12xx_set_power_on(wl);
4896 if (ret < 0)
4897 goto out;
4898
4899 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4900
4901 if (wl->chip.id == CHIP_ID_1283_PG20)
4902 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4903 else
4904 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4905
4906 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4907
Luciano Coelho5e037e72011-12-23 09:32:17 +02004908 if (!wl12xx_mac_in_fuse(wl)) {
4909 wl->fuse_oui_addr = 0;
4910 wl->fuse_nic_addr = 0;
4911 } else {
4912 wl12xx_get_fuse_mac(wl);
4913 }
4914
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004915 wl1271_power_off(wl);
4916out:
4917 return ret;
4918}
4919
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004920static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004921{
4922 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004923 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004924
4925 if (wl->mac80211_registered)
4926 return 0;
4927
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004928 ret = wl12xx_get_hw_info(wl);
4929 if (ret < 0) {
4930 wl1271_error("couldn't get hw info");
4931 goto out;
4932 }
4933
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004934 ret = wl1271_fetch_nvs(wl);
4935 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004936 /* NOTE: The wl->nvs->nvs element must be first, in
4937 * order to simplify the casting, we assume it is at
4938 * the beginning of the wl->nvs structure.
4939 */
4940 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004941
Luciano Coelho5e037e72011-12-23 09:32:17 +02004942 oui_addr =
4943 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4944 nic_addr =
4945 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004946 }
4947
Luciano Coelho5e037e72011-12-23 09:32:17 +02004948 /* if the MAC address is zeroed in the NVS derive from fuse */
4949 if (oui_addr == 0 && nic_addr == 0) {
4950 oui_addr = wl->fuse_oui_addr;
4951 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4952 nic_addr = wl->fuse_nic_addr + 1;
4953 }
4954
4955 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004956
4957 ret = ieee80211_register_hw(wl->hw);
4958 if (ret < 0) {
4959 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004960 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004961 }
4962
4963 wl->mac80211_registered = true;
4964
Eliad Pellerd60080a2010-11-24 12:53:16 +02004965 wl1271_debugfs_init(wl);
4966
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004967 register_netdevice_notifier(&wl1271_dev_notifier);
4968
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004969 wl1271_notice("loaded");
4970
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004971out:
4972 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004973}
4974
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004975static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004976{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004977 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02004978 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01004979
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03004980 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004981 ieee80211_unregister_hw(wl->hw);
4982 wl->mac80211_registered = false;
4983
4984}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02004985
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004986static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004987{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02004988 static const u32 cipher_suites[] = {
4989 WLAN_CIPHER_SUITE_WEP40,
4990 WLAN_CIPHER_SUITE_WEP104,
4991 WLAN_CIPHER_SUITE_TKIP,
4992 WLAN_CIPHER_SUITE_CCMP,
4993 WL1271_CIPHER_SUITE_GEM,
4994 };
4995
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03004996 /* The tx descriptor buffer and the TKIP space. */
4997 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
4998 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004999
5000 /* unit us */
5001 /* FIXME: find a proper value */
5002 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005003 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005004
5005 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005006 IEEE80211_HW_SUPPORTS_PS |
Eyal Shapiraf1d63a52012-01-31 11:57:21 +02005007 IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005008 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005009 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005010 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005011 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005012 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005013 IEEE80211_HW_AP_LINK_PS |
5014 IEEE80211_HW_AMPDU_AGGREGATION |
5015 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005016
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005017 wl->hw->wiphy->cipher_suites = cipher_suites;
5018 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5019
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005020 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005021 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5022 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005023 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005024 wl->hw->wiphy->max_sched_scan_ssids = 16;
5025 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005026 /*
5027 * Maximum length of elements in scanning probe request templates
5028 * should be the maximum length possible for a template, without
5029 * the IEEE80211 header of the template
5030 */
Eliad Peller154037d2011-08-14 13:17:12 +03005031 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005032 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005033
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005034 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5035 sizeof(struct ieee80211_header);
5036
Eliad Peller1ec23f72011-08-25 14:26:54 +03005037 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5038
Luciano Coelho4a31c112011-03-21 23:16:14 +02005039 /* make sure all our channels fit in the scanned_ch bitmask */
5040 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5041 ARRAY_SIZE(wl1271_channels_5ghz) >
5042 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005043 /*
5044 * We keep local copies of the band structs because we need to
5045 * modify them on a per-device basis.
5046 */
5047 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5048 sizeof(wl1271_band_2ghz));
5049 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5050 sizeof(wl1271_band_5ghz));
5051
5052 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5053 &wl->bands[IEEE80211_BAND_2GHZ];
5054 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5055 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005056
Kalle Valo12bd8942010-03-18 12:26:33 +02005057 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005058 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005059
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005060 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5061
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005062 /* the FW answers probe-requests in AP-mode */
5063 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5064 wl->hw->wiphy->probe_resp_offload =
5065 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5066 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5067 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5068
Felipe Balbia390e852011-10-06 10:07:44 +03005069 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005070
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005071 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005072 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005073
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005074 wl->hw->max_rx_aggregation_subframes = 8;
5075
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005076 return 0;
5077}
5078
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005079#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005080
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005081static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005082{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005083 struct ieee80211_hw *hw;
5084 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005085 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005086 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005087
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005088 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005089
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005090 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5091 if (!hw) {
5092 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005093 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005094 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005095 }
5096
5097 wl = hw->priv;
5098 memset(wl, 0, sizeof(*wl));
5099
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005100 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02005101 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005102
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005103 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005104
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005105 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005106 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005107 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5108
Ido Yariva6208652011-03-01 15:14:41 +02005109 skb_queue_head_init(&wl->deferred_rx_queue);
5110 skb_queue_head_init(&wl->deferred_tx_queue);
5111
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005112 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005113 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005114 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5115 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5116 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005117
Eliad Peller92ef8962011-06-07 12:50:46 +03005118 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5119 if (!wl->freezable_wq) {
5120 ret = -ENOMEM;
5121 goto err_hw;
5122 }
5123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005124 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005125 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005126 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005127 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005128 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005129 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005130 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005131 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005132 wl->ap_ps_map = 0;
5133 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005134 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005135 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005136 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005137 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005138 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005139 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005140 wl->fwlog_size = 0;
5141 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005142
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005143 /* The system link is always allocated */
5144 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5145
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005146 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005147 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005148 wl->tx_frames[i] = NULL;
5149
5150 spin_lock_init(&wl->wl_lock);
5151
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005152 wl->state = WL1271_STATE_OFF;
5153 mutex_init(&wl->mutex);
5154
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005155 /* Apply default driver configuration. */
5156 wl1271_conf_init(wl);
5157
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005158 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5159 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5160 if (!wl->aggr_buf) {
5161 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005162 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005163 }
5164
Ido Yariv990f5de2011-03-31 10:06:59 +02005165 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5166 if (!wl->dummy_packet) {
5167 ret = -ENOMEM;
5168 goto err_aggr;
5169 }
5170
Ido Yariv95dac04f2011-06-06 14:57:06 +03005171 /* Allocate one page for the FW log */
5172 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5173 if (!wl->fwlog) {
5174 ret = -ENOMEM;
5175 goto err_dummy_packet;
5176 }
5177
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005178 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005179
Ido Yariv990f5de2011-03-31 10:06:59 +02005180err_dummy_packet:
5181 dev_kfree_skb(wl->dummy_packet);
5182
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005183err_aggr:
5184 free_pages((unsigned long)wl->aggr_buf, order);
5185
Eliad Peller92ef8962011-06-07 12:50:46 +03005186err_wq:
5187 destroy_workqueue(wl->freezable_wq);
5188
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005189err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005190 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005191 ieee80211_free_hw(hw);
5192
5193err_hw_alloc:
5194
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005195 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005196}
5197
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005198static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005199{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005200 /* Unblock any fwlog readers */
5201 mutex_lock(&wl->mutex);
5202 wl->fwlog_size = -1;
5203 wake_up_interruptible_all(&wl->fwlog_waitq);
5204 mutex_unlock(&wl->mutex);
5205
Felipe Balbif79f8902011-10-06 13:05:25 +03005206 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005207
Felipe Balbif79f8902011-10-06 13:05:25 +03005208 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005209
Felipe Balbif79f8902011-10-06 13:05:25 +03005210 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005211 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005212 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005213 free_pages((unsigned long)wl->aggr_buf,
5214 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005215
5216 wl1271_debugfs_exit(wl);
5217
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005218 vfree(wl->fw);
5219 wl->fw = NULL;
5220 kfree(wl->nvs);
5221 wl->nvs = NULL;
5222
5223 kfree(wl->fw_status);
5224 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005225 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005226
5227 ieee80211_free_hw(wl->hw);
5228
5229 return 0;
5230}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005231
Felipe Balbia390e852011-10-06 10:07:44 +03005232static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5233{
5234 struct wl1271 *wl = cookie;
5235 unsigned long flags;
5236
5237 wl1271_debug(DEBUG_IRQ, "IRQ");
5238
5239 /* complete the ELP completion */
5240 spin_lock_irqsave(&wl->wl_lock, flags);
5241 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5242 if (wl->elp_compl) {
5243 complete(wl->elp_compl);
5244 wl->elp_compl = NULL;
5245 }
5246
5247 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5248 /* don't enqueue a work right now. mark it as pending */
5249 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5250 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5251 disable_irq_nosync(wl->irq);
5252 pm_wakeup_event(wl->dev, 0);
5253 spin_unlock_irqrestore(&wl->wl_lock, flags);
5254 return IRQ_HANDLED;
5255 }
5256 spin_unlock_irqrestore(&wl->wl_lock, flags);
5257
5258 return IRQ_WAKE_THREAD;
5259}
5260
Felipe Balbice2a2172011-10-05 14:12:55 +03005261static int __devinit wl12xx_probe(struct platform_device *pdev)
5262{
Felipe Balbia390e852011-10-06 10:07:44 +03005263 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5264 struct ieee80211_hw *hw;
5265 struct wl1271 *wl;
5266 unsigned long irqflags;
5267 int ret = -ENODEV;
5268
5269 hw = wl1271_alloc_hw();
5270 if (IS_ERR(hw)) {
5271 wl1271_error("can't allocate hw");
5272 ret = PTR_ERR(hw);
5273 goto out;
5274 }
5275
5276 wl = hw->priv;
5277 wl->irq = platform_get_irq(pdev, 0);
5278 wl->ref_clock = pdata->board_ref_clock;
5279 wl->tcxo_clock = pdata->board_tcxo_clock;
5280 wl->platform_quirks = pdata->platform_quirks;
5281 wl->set_power = pdata->set_power;
5282 wl->dev = &pdev->dev;
5283 wl->if_ops = pdata->ops;
5284
5285 platform_set_drvdata(pdev, wl);
5286
5287 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5288 irqflags = IRQF_TRIGGER_RISING;
5289 else
5290 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5291
5292 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5293 irqflags,
5294 pdev->name, wl);
5295 if (ret < 0) {
5296 wl1271_error("request_irq() failed: %d", ret);
5297 goto out_free_hw;
5298 }
5299
5300 ret = enable_irq_wake(wl->irq);
5301 if (!ret) {
5302 wl->irq_wake_enabled = true;
5303 device_init_wakeup(wl->dev, 1);
5304 if (pdata->pwr_in_suspend)
5305 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5306
5307 }
5308 disable_irq(wl->irq);
5309
5310 ret = wl1271_init_ieee80211(wl);
5311 if (ret)
5312 goto out_irq;
5313
5314 ret = wl1271_register_hw(wl);
5315 if (ret)
5316 goto out_irq;
5317
Felipe Balbif79f8902011-10-06 13:05:25 +03005318 /* Create sysfs file to control bt coex state */
5319 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5320 if (ret < 0) {
5321 wl1271_error("failed to create sysfs file bt_coex_state");
5322 goto out_irq;
5323 }
5324
5325 /* Create sysfs file to get HW PG version */
5326 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5327 if (ret < 0) {
5328 wl1271_error("failed to create sysfs file hw_pg_ver");
5329 goto out_bt_coex_state;
5330 }
5331
5332 /* Create sysfs file for the FW log */
5333 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5334 if (ret < 0) {
5335 wl1271_error("failed to create sysfs file fwlog");
5336 goto out_hw_pg_ver;
5337 }
5338
Felipe Balbice2a2172011-10-05 14:12:55 +03005339 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005340
Felipe Balbif79f8902011-10-06 13:05:25 +03005341out_hw_pg_ver:
5342 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5343
5344out_bt_coex_state:
5345 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5346
Felipe Balbia390e852011-10-06 10:07:44 +03005347out_irq:
5348 free_irq(wl->irq, wl);
5349
5350out_free_hw:
5351 wl1271_free_hw(wl);
5352
5353out:
5354 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005355}
5356
5357static int __devexit wl12xx_remove(struct platform_device *pdev)
5358{
Felipe Balbia390e852011-10-06 10:07:44 +03005359 struct wl1271 *wl = platform_get_drvdata(pdev);
5360
5361 if (wl->irq_wake_enabled) {
5362 device_init_wakeup(wl->dev, 0);
5363 disable_irq_wake(wl->irq);
5364 }
5365 wl1271_unregister_hw(wl);
5366 free_irq(wl->irq, wl);
5367 wl1271_free_hw(wl);
5368
Felipe Balbice2a2172011-10-05 14:12:55 +03005369 return 0;
5370}
5371
5372static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005373 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005374 { } /* Terminating Entry */
5375};
5376MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5377
5378static struct platform_driver wl12xx_driver = {
5379 .probe = wl12xx_probe,
5380 .remove = __devexit_p(wl12xx_remove),
5381 .id_table = wl12xx_id_table,
5382 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005383 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005384 .owner = THIS_MODULE,
5385 }
5386};
5387
5388static int __init wl12xx_init(void)
5389{
5390 return platform_driver_register(&wl12xx_driver);
5391}
5392module_init(wl12xx_init);
5393
5394static void __exit wl12xx_exit(void)
5395{
5396 platform_driver_unregister(&wl12xx_driver);
5397}
5398module_exit(wl12xx_exit);
5399
Guy Eilam491bbd62011-01-12 10:33:29 +01005400u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005401EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005402module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005403MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5404
Ido Yariv95dac04f2011-06-06 14:57:06 +03005405module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005406MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005407 "FW logger options: continuous, ondemand, dbgpins or disable");
5408
Eliad Peller2a5bff02011-08-25 18:10:59 +03005409module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5410MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5411
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005412MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005413MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005414MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");