blob: e4549dfb70d4922febc235a964d5dc38a0522644 [file] [log] [blame]
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001/*
2 * This file is part of wl1271
3 *
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02004 * Copyright (C) 2008-2010 Nokia Corporation
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005 *
6 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 *
22 */
23
24#include <linux/module.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030025#include <linux/firmware.h>
26#include <linux/delay.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030027#include <linux/spi/spi.h>
28#include <linux/crc32.h>
29#include <linux/etherdevice.h>
Juuso Oikarinen1fba4972009-10-08 21:56:32 +030030#include <linux/vmalloc.h>
Juuso Oikarinena1dd8182010-03-18 12:26:31 +020031#include <linux/platform_device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Ido Yariv341b7cd2011-03-31 10:07:01 +020033#include <linux/wl12xx.h>
Ido Yariv95dac04f2011-06-06 14:57:06 +030034#include <linux/sched.h>
Felipe Balbia390e852011-10-06 10:07:44 +030035#include <linux/interrupt.h>
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030036
Shahar Levi00d20102010-11-08 11:20:10 +000037#include "wl12xx.h"
Luciano Coelho0f4e3122011-10-07 11:02:42 +030038#include "debug.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030039#include "wl12xx_80211.h"
Shahar Levi00d20102010-11-08 11:20:10 +000040#include "reg.h"
41#include "io.h"
42#include "event.h"
43#include "tx.h"
44#include "rx.h"
45#include "ps.h"
46#include "init.h"
47#include "debugfs.h"
48#include "cmd.h"
49#include "boot.h"
50#include "testmode.h"
51#include "scan.h"
Luciano Coelhof5fc0f82009-08-06 16:25:28 +030052
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +020053#define WL1271_BOOT_RETRIES 3
54
Juuso Oikarinen8a080482009-10-13 12:47:44 +030055static struct conf_drv_settings default_conf = {
56 .sg = {
Eliad Peller3be41122011-08-14 13:17:19 +030057 .params = {
58 [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10,
59 [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180,
60 [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10,
61 [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180,
62 [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10,
63 [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80,
64 [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10,
65 [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80,
66 [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8,
67 [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8,
68 [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20,
69 [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20,
70 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20,
71 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35,
72 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16,
73 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35,
74 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32,
75 [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50,
76 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28,
77 [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50,
78 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10,
79 [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20,
80 [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75,
81 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15,
82 [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27,
83 [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17,
84 /* active scan params */
85 [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
86 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
87 [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
88 /* passive scan params */
89 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800,
90 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200,
91 [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
92 /* passive scan in dual antenna params */
93 [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0,
94 [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0,
95 [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0,
96 /* general params */
97 [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1,
98 [CONF_SG_ANTENNA_CONFIGURATION] = 0,
99 [CONF_SG_BEACON_MISS_PERCENT] = 60,
100 [CONF_SG_DHCP_TIME] = 5000,
101 [CONF_SG_RXT] = 1200,
102 [CONF_SG_TXT] = 1000,
103 [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
104 [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3,
105 [CONF_SG_HV3_MAX_SERVED] = 6,
106 [CONF_SG_PS_POLL_TIMEOUT] = 10,
107 [CONF_SG_UPSD_TIMEOUT] = 10,
108 [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2,
109 [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5,
110 [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30,
111 /* AP params */
112 [CONF_AP_BEACON_MISS_TX] = 3,
113 [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10,
114 [CONF_AP_BEACON_WINDOW_INTERVAL] = 2,
115 [CONF_AP_CONNECTION_PROTECTION_TIME] = 0,
116 [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25,
117 [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25,
Arik Nemtsov801f8702011-04-18 14:15:20 +0300118 },
Juuso Oikarinen1b00f542010-03-18 12:26:30 +0200119 .state = CONF_SG_PROTECTIVE,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300120 },
121 .rx = {
122 .rx_msdu_life_time = 512000,
123 .packet_detection_threshold = 0,
124 .ps_poll_timeout = 15,
125 .upsd_timeout = 15,
Arik Nemtsov5f704d12011-04-18 14:15:21 +0300126 .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200127 .rx_cca_threshold = 0,
128 .irq_blk_threshold = 0xFFFF,
129 .irq_pkt_threshold = 0,
130 .irq_timeout = 600,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300131 .queue_type = CONF_RX_QUEUE_TYPE_LOW_PRIORITY,
132 },
133 .tx = {
134 .tx_energy_detection = 0,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200135 .sta_rc_conf = {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300136 .enabled_rates = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300137 .short_retry_limit = 10,
138 .long_retry_limit = 10,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200139 .aflags = 0,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300140 },
141 .ac_conf_count = 4,
142 .ac_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200143 [CONF_TX_AC_BE] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300144 .ac = CONF_TX_AC_BE,
145 .cw_min = 15,
146 .cw_max = 63,
147 .aifsn = 3,
148 .tx_op_limit = 0,
149 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200150 [CONF_TX_AC_BK] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300151 .ac = CONF_TX_AC_BK,
152 .cw_min = 15,
153 .cw_max = 63,
154 .aifsn = 7,
155 .tx_op_limit = 0,
156 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200157 [CONF_TX_AC_VI] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300158 .ac = CONF_TX_AC_VI,
159 .cw_min = 15,
160 .cw_max = 63,
161 .aifsn = CONF_TX_AIFS_PIFS,
162 .tx_op_limit = 3008,
163 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200164 [CONF_TX_AC_VO] = {
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300165 .ac = CONF_TX_AC_VO,
166 .cw_min = 15,
167 .cw_max = 63,
168 .aifsn = CONF_TX_AIFS_PIFS,
169 .tx_op_limit = 1504,
170 },
171 },
Arik Nemtsov3618f302011-06-26 10:36:03 +0300172 .max_tx_retries = 100,
173 .ap_aging_period = 300,
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200174 .tid_conf_count = 4,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300175 .tid_conf = {
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200176 [CONF_TX_AC_BE] = {
177 .queue_id = CONF_TX_AC_BE,
178 .channel_type = CONF_CHANNEL_TYPE_EDCF,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300179 .tsid = CONF_TX_AC_BE,
180 .ps_scheme = CONF_PS_SCHEME_LEGACY,
181 .ack_policy = CONF_ACK_POLICY_LEGACY,
182 .apsd_conf = {0, 0},
183 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200184 [CONF_TX_AC_BK] = {
185 .queue_id = CONF_TX_AC_BK,
186 .channel_type = CONF_CHANNEL_TYPE_EDCF,
187 .tsid = CONF_TX_AC_BK,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300188 .ps_scheme = CONF_PS_SCHEME_LEGACY,
189 .ack_policy = CONF_ACK_POLICY_LEGACY,
190 .apsd_conf = {0, 0},
191 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200192 [CONF_TX_AC_VI] = {
193 .queue_id = CONF_TX_AC_VI,
194 .channel_type = CONF_CHANNEL_TYPE_EDCF,
195 .tsid = CONF_TX_AC_VI,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300196 .ps_scheme = CONF_PS_SCHEME_LEGACY,
197 .ack_policy = CONF_ACK_POLICY_LEGACY,
198 .apsd_conf = {0, 0},
199 },
Juuso Oikarinen9987a9d2010-09-01 11:31:12 +0200200 [CONF_TX_AC_VO] = {
201 .queue_id = CONF_TX_AC_VO,
202 .channel_type = CONF_CHANNEL_TYPE_EDCF,
203 .tsid = CONF_TX_AC_VO,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300204 .ps_scheme = CONF_PS_SCHEME_LEGACY,
205 .ack_policy = CONF_ACK_POLICY_LEGACY,
206 .apsd_conf = {0, 0},
207 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300208 },
209 .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD,
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200210 .tx_compl_timeout = 700,
Juuso Oikarinenebba60c2010-04-01 11:38:20 +0300211 .tx_compl_threshold = 4,
212 .basic_rate = CONF_HW_BIT_RATE_1MBPS,
213 .basic_rate_5 = CONF_HW_BIT_RATE_6MBPS,
Arik Nemtsov1e05a812010-10-16 17:44:51 +0200214 .tmpl_short_retry_limit = 10,
215 .tmpl_long_retry_limit = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300216 },
217 .conn = {
218 .wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300219 .listen_interval = 1,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300220 .bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
Shahar Levibc76b942011-05-11 11:14:22 +0300221 .bcn_filt_ie_count = 2,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300222 .bcn_filt_ie = {
223 [0] = {
224 .ie = WLAN_EID_CHANNEL_SWITCH,
225 .rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
Shahar Levibc76b942011-05-11 11:14:22 +0300226 },
227 [1] = {
228 .ie = WLAN_EID_HT_INFORMATION,
229 .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
230 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300231 },
Luciano Coelho3ed8f2c2009-12-11 15:40:54 +0200232 .synch_fail_thold = 10,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300233 .bss_lose_timeout = 100,
234 .beacon_rx_timeout = 10000,
235 .broadcast_timeout = 20000,
236 .rx_broadcast_in_ps = 1,
Juuso Oikarinen90494a92010-07-08 17:50:00 +0300237 .ps_poll_threshold = 10,
238 .ps_poll_recovery_period = 700,
Juuso Oikarinen11f70f92009-10-13 12:47:46 +0300239 .bet_enable = CONF_BET_MODE_ENABLE,
Ohad Ben-Cohen958b20e02011-03-14 18:53:10 +0200240 .bet_max_consecutive = 50,
Eliad Pellera879ed72011-08-23 16:37:02 +0300241 .psm_entry_retries = 8,
Shahar Levi23708412011-04-13 14:52:50 +0300242 .psm_exit_retries = 16,
Juuso Oikarinen8eab7b42010-09-24 03:10:11 +0200243 .psm_entry_nullfunc_retries = 3,
Juuso Oikarinen50c500a2010-04-01 11:38:22 +0300244 .keep_alive_interval = 55000,
245 .max_listen_interval = 20,
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300246 },
Luciano Coelho6e92b412009-12-11 15:40:50 +0200247 .itrim = {
248 .enable = false,
249 .timeout = 50000,
Juuso Oikarinen38ad2d82009-12-11 15:41:08 +0200250 },
251 .pm_config = {
252 .host_clk_settling_time = 5000,
253 .host_fast_wakeup_support = false
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300254 },
255 .roam_trigger = {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +0300256 .trigger_pacing = 1,
257 .avg_weight_rssi_beacon = 20,
258 .avg_weight_rssi_data = 10,
259 .avg_weight_snr_beacon = 20,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100260 .avg_weight_snr_data = 10,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200261 },
262 .scan = {
263 .min_dwell_time_active = 7500,
264 .max_dwell_time_active = 30000,
Juuso Oikarinenea45b2c2011-01-24 07:01:54 +0100265 .min_dwell_time_passive = 100000,
266 .max_dwell_time_passive = 100000,
Juuso Oikarinenbea39d62010-09-21 08:14:31 +0200267 .num_probe_reqs = 2,
268 },
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300269 .sched_scan = {
270 /* sched_scan requires dwell times in TU instead of TU/1000 */
Luciano Coelho221737d2011-09-02 14:28:22 +0300271 .min_dwell_time_active = 30,
272 .max_dwell_time_active = 60,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300273 .dwell_time_passive = 100,
Luciano Coelho50a66d72011-05-27 15:34:47 +0300274 .dwell_time_dfs = 150,
Luciano Coelho3a9d60e2011-05-10 14:06:31 +0300275 .num_probe_reqs = 2,
276 .rssi_threshold = -90,
277 .snr_threshold = 0,
278 },
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200279 .rf = {
280 .tx_per_channel_power_compensation_2 = {
281 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
282 },
283 .tx_per_channel_power_compensation_5 = {
284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287 },
288 },
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100289 .ht = {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300290 .rx_ba_win_size = 8,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100291 .tx_ba_win_size = 64,
292 .inactivity_timeout = 10000,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +0300293 .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP,
Levi, Shahar4b7fac72011-01-23 07:27:22 +0100294 },
Shahar Levi13b107d2011-03-06 16:32:12 +0200295 .mem_wl127x = {
Eliad Pellerfe5ef092011-02-02 09:59:36 +0200296 .num_stations = 1,
297 .ssid_profiles = 1,
298 .rx_block_num = 70,
299 .tx_min_block_num = 40,
Ido Yariv4cf557f2011-04-18 16:45:10 +0300300 .dynamic_memory = 1,
Ido Yarivb16d4b62011-03-01 15:14:44 +0200301 .min_req_tx_blocks = 100,
Eliad Pellerc8bde242011-02-02 09:59:35 +0200302 .min_req_rx_blocks = 22,
303 .tx_min = 27,
Shahar Levi13b107d2011-03-06 16:32:12 +0200304 },
305 .mem_wl128x = {
306 .num_stations = 1,
307 .ssid_profiles = 1,
308 .rx_block_num = 40,
309 .tx_min_block_num = 40,
310 .dynamic_memory = 1,
311 .min_req_tx_blocks = 45,
312 .min_req_rx_blocks = 22,
313 .tx_min = 27,
314 },
Shahar Leviff868432011-04-11 15:41:46 +0300315 .fm_coex = {
316 .enable = true,
317 .swallow_period = 5,
318 .n_divider_fref_set_1 = 0xff, /* default */
319 .n_divider_fref_set_2 = 12,
320 .m_divider_fref_set_1 = 148,
321 .m_divider_fref_set_2 = 0xffff, /* default */
322 .coex_pll_stabilization_time = 0xffffffff, /* default */
323 .ldo_stabilization_time = 0xffff, /* default */
324 .fm_disturbed_band_margin = 0xff, /* default */
325 .swallow_clk_diff = 0xff, /* default */
326 },
Eliad Pellerf84673d2011-05-15 11:10:28 +0300327 .rx_streaming = {
328 .duration = 150,
329 .queues = 0x1,
330 .interval = 20,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300331 .always = 0,
Eliad Pellerf84673d2011-05-15 11:10:28 +0300332 },
Ido Yariv95dac04f2011-06-06 14:57:06 +0300333 .fwlog = {
334 .mode = WL12XX_FWLOG_ON_DEMAND,
335 .mem_blocks = 2,
336 .severity = 0,
337 .timestamp = WL12XX_FWLOG_TIMESTAMP_DISABLED,
338 .output = WL12XX_FWLOG_OUTPUT_HOST,
339 .threshold = 0,
340 },
Luciano Coelhoafb7d3c2011-04-01 20:48:02 +0300341 .hci_io_ds = HCI_IO_DS_6MA,
Eliad Pellerfa6ad9f2011-08-14 13:17:14 +0300342 .rate = {
343 .rate_retry_score = 32000,
344 .per_add = 8192,
345 .per_th1 = 2048,
346 .per_th2 = 4096,
347 .max_per = 8100,
348 .inverse_curiosity_factor = 5,
349 .tx_fail_low_th = 4,
350 .tx_fail_high_th = 10,
351 .per_alpha_shift = 4,
352 .per_add_shift = 13,
353 .per_beta1_shift = 10,
354 .per_beta2_shift = 8,
355 .rate_check_up = 2,
356 .rate_check_down = 12,
357 .rate_retry_policy = {
358 0x00, 0x00, 0x00, 0x00, 0x00,
359 0x00, 0x00, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00,
361 },
362 },
Eliad Peller94877752011-08-28 15:11:56 +0300363 .hangover = {
364 .recover_time = 0,
365 .hangover_period = 20,
366 .dynamic_mode = 1,
367 .early_termination_mode = 1,
368 .max_period = 20,
369 .min_period = 1,
370 .increase_delta = 1,
371 .decrease_delta = 2,
372 .quiet_time = 4,
373 .increase_time = 1,
374 .window_size = 16,
375 },
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300376};
377
Ido Yariv95dac04f2011-06-06 14:57:06 +0300378static char *fwlog_param;
Eliad Peller2a5bff02011-08-25 18:10:59 +0300379static bool bug_on_recovery;
Ido Yariv95dac04f2011-06-06 14:57:06 +0300380
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300381static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +0200382 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +0300383 bool reset_tx_queues);
Eliad Pellerf0277432011-10-10 10:13:14 +0200384static void wl1271_op_stop(struct ieee80211_hw *hw);
Eliad Peller170d0e62011-10-05 11:56:06 +0200385static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +0200386
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200387static DEFINE_MUTEX(wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +0300388static LIST_HEAD(wl_list);
389
Eliad Pellerba8447f62011-10-10 10:13:00 +0200390static int wl1271_check_operstate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
391 unsigned char operstate)
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300392{
393 int ret;
Eliad Peller0603d892011-10-05 11:55:51 +0200394
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300395 if (operstate != IF_OPER_UP)
396 return 0;
397
Eliad Peller8181aec2011-10-10 10:13:04 +0200398 if (test_and_set_bit(WLVIF_FLAG_STA_STATE_SENT, &wlvif->flags))
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300399 return 0;
400
Eliad Peller154da672011-10-05 11:55:53 +0200401 ret = wl12xx_cmd_set_peer_state(wl, wlvif->sta.hlid);
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300402 if (ret < 0)
403 return ret;
404
Eliad Peller0603d892011-10-05 11:55:51 +0200405 wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +0300406
Eliad Pelleref4b29e2011-06-06 13:03:12 +0300407 wl1271_info("Association completed.");
408 return 0;
409}
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300410static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
411 void *arg)
412{
413 struct net_device *dev = arg;
414 struct wireless_dev *wdev;
415 struct wiphy *wiphy;
416 struct ieee80211_hw *hw;
417 struct wl1271 *wl;
418 struct wl1271 *wl_temp;
Eliad Pellerba8447f62011-10-10 10:13:00 +0200419 struct wl12xx_vif *wlvif;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300420 int ret = 0;
421
422 /* Check that this notification is for us. */
423 if (what != NETDEV_CHANGE)
424 return NOTIFY_DONE;
425
426 wdev = dev->ieee80211_ptr;
427 if (wdev == NULL)
428 return NOTIFY_DONE;
429
430 wiphy = wdev->wiphy;
431 if (wiphy == NULL)
432 return NOTIFY_DONE;
433
434 hw = wiphy_priv(wiphy);
435 if (hw == NULL)
436 return NOTIFY_DONE;
437
438 wl_temp = hw->priv;
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200439 mutex_lock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300440 list_for_each_entry(wl, &wl_list, list) {
441 if (wl == wl_temp)
442 break;
443 }
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +0200444 mutex_unlock(&wl_list_mutex);
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300445 if (wl != wl_temp)
446 return NOTIFY_DONE;
447
448 mutex_lock(&wl->mutex);
449
450 if (wl->state == WL1271_STATE_OFF)
451 goto out;
452
Eliad Peller6ab70912011-12-18 20:25:45 +0200453 if (dev->operstate != IF_OPER_UP)
454 goto out;
455 /*
456 * The correct behavior should be just getting the appropriate wlvif
457 * from the given dev, but currently we don't have a mac80211
458 * interface for it.
459 */
Eliad Pellerba8447f62011-10-10 10:13:00 +0200460 wl12xx_for_each_wlvif_sta(wl, wlvif) {
Eliad Peller6ab70912011-12-18 20:25:45 +0200461 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
462
Eliad Pellerba8447f62011-10-10 10:13:00 +0200463 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
464 continue;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300465
Eliad Pellerba8447f62011-10-10 10:13:00 +0200466 ret = wl1271_ps_elp_wakeup(wl);
467 if (ret < 0)
468 goto out;
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300469
Eliad Peller6ab70912011-12-18 20:25:45 +0200470 wl1271_check_operstate(wl, wlvif,
471 ieee80211_get_operstate(vif));
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300472
Eliad Pellerba8447f62011-10-10 10:13:00 +0200473 wl1271_ps_elp_sleep(wl);
474 }
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +0300475out:
476 mutex_unlock(&wl->mutex);
477
478 return NOTIFY_OK;
479}
480
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100481static int wl1271_reg_notify(struct wiphy *wiphy,
Luciano Coelho573c67c2010-11-26 13:44:59 +0200482 struct regulatory_request *request)
483{
Juuso Oikarinenb7417d92010-11-10 11:27:19 +0100484 struct ieee80211_supported_band *band;
485 struct ieee80211_channel *ch;
486 int i;
487
488 band = wiphy->bands[IEEE80211_BAND_5GHZ];
489 for (i = 0; i < band->n_channels; i++) {
490 ch = &band->channels[i];
491 if (ch->flags & IEEE80211_CHAN_DISABLED)
492 continue;
493
494 if (ch->flags & IEEE80211_CHAN_RADAR)
495 ch->flags |= IEEE80211_CHAN_NO_IBSS |
496 IEEE80211_CHAN_PASSIVE_SCAN;
497
498 }
499
500 return 0;
501}
502
Eliad Peller9eb599e2011-10-10 10:12:59 +0200503static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
504 bool enable)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300505{
506 int ret = 0;
507
508 /* we should hold wl->mutex */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200509 ret = wl1271_acx_ps_rx_streaming(wl, wlvif, enable);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300510 if (ret < 0)
511 goto out;
512
513 if (enable)
Eliad Peller0744bdb2011-10-10 10:13:05 +0200514 set_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300515 else
Eliad Peller0744bdb2011-10-10 10:13:05 +0200516 clear_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300517out:
518 return ret;
519}
520
521/*
522 * this function is being called when the rx_streaming interval
523 * has beed changed or rx_streaming should be disabled
524 */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200525int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Peller77ddaa12011-05-15 11:10:29 +0300526{
527 int ret = 0;
528 int period = wl->conf.rx_streaming.interval;
529
530 /* don't reconfigure if rx_streaming is disabled */
Eliad Peller0744bdb2011-10-10 10:13:05 +0200531 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300532 goto out;
533
534 /* reconfigure/disable according to new streaming_period */
535 if (period &&
Eliad Pellerba8447f62011-10-10 10:13:00 +0200536 test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
Eliad Peller77ddaa12011-05-15 11:10:29 +0300537 (wl->conf.rx_streaming.always ||
538 test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
Eliad Peller9eb599e2011-10-10 10:12:59 +0200539 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300540 else {
Eliad Peller9eb599e2011-10-10 10:12:59 +0200541 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300542 /* don't cancel_work_sync since we might deadlock */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200543 del_timer_sync(&wlvif->rx_streaming_timer);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300544 }
545out:
546 return ret;
547}
548
549static void wl1271_rx_streaming_enable_work(struct work_struct *work)
550{
551 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200552 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
553 rx_streaming_enable_work);
554 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300555
556 mutex_lock(&wl->mutex);
557
Eliad Peller0744bdb2011-10-10 10:13:05 +0200558 if (test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags) ||
Eliad Pellerba8447f62011-10-10 10:13:00 +0200559 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller77ddaa12011-05-15 11:10:29 +0300560 (!wl->conf.rx_streaming.always &&
561 !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)))
562 goto out;
563
564 if (!wl->conf.rx_streaming.interval)
565 goto out;
566
567 ret = wl1271_ps_elp_wakeup(wl);
568 if (ret < 0)
569 goto out;
570
Eliad Peller9eb599e2011-10-10 10:12:59 +0200571 ret = wl1271_set_rx_streaming(wl, wlvif, true);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300572 if (ret < 0)
573 goto out_sleep;
574
575 /* stop it after some time of inactivity */
Eliad Peller9eb599e2011-10-10 10:12:59 +0200576 mod_timer(&wlvif->rx_streaming_timer,
Eliad Peller77ddaa12011-05-15 11:10:29 +0300577 jiffies + msecs_to_jiffies(wl->conf.rx_streaming.duration));
578
579out_sleep:
580 wl1271_ps_elp_sleep(wl);
581out:
582 mutex_unlock(&wl->mutex);
583}
584
585static void wl1271_rx_streaming_disable_work(struct work_struct *work)
586{
587 int ret;
Eliad Peller9eb599e2011-10-10 10:12:59 +0200588 struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
589 rx_streaming_disable_work);
590 struct wl1271 *wl = wlvif->wl;
Eliad Peller77ddaa12011-05-15 11:10:29 +0300591
592 mutex_lock(&wl->mutex);
593
Eliad Peller0744bdb2011-10-10 10:13:05 +0200594 if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
Eliad Peller77ddaa12011-05-15 11:10:29 +0300595 goto out;
596
597 ret = wl1271_ps_elp_wakeup(wl);
598 if (ret < 0)
599 goto out;
600
Eliad Peller9eb599e2011-10-10 10:12:59 +0200601 ret = wl1271_set_rx_streaming(wl, wlvif, false);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300602 if (ret)
603 goto out_sleep;
604
605out_sleep:
606 wl1271_ps_elp_sleep(wl);
607out:
608 mutex_unlock(&wl->mutex);
609}
610
611static void wl1271_rx_streaming_timer(unsigned long data)
612{
Eliad Peller9eb599e2011-10-10 10:12:59 +0200613 struct wl12xx_vif *wlvif = (struct wl12xx_vif *)data;
614 struct wl1271 *wl = wlvif->wl;
615 ieee80211_queue_work(wl->hw, &wlvif->rx_streaming_disable_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +0300616}
617
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300618static void wl1271_conf_init(struct wl1271 *wl)
619{
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300620
621 /*
622 * This function applies the default configuration to the driver. This
623 * function is invoked upon driver load (spi probe.)
624 *
625 * The configuration is stored in a run-time structure in order to
626 * facilitate for run-time adjustment of any of the parameters. Making
627 * changes to the configuration structure will apply the new values on
628 * the next interface up (wl1271_op_start.)
629 */
630
631 /* apply driver default configuration */
Juuso Oikarinen8a080482009-10-13 12:47:44 +0300632 memcpy(&wl->conf, &default_conf, sizeof(default_conf));
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300633
Ido Yariv95dac04f2011-06-06 14:57:06 +0300634 /* Adjust settings according to optional module parameters */
635 if (fwlog_param) {
636 if (!strcmp(fwlog_param, "continuous")) {
637 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
638 } else if (!strcmp(fwlog_param, "ondemand")) {
639 wl->conf.fwlog.mode = WL12XX_FWLOG_ON_DEMAND;
640 } else if (!strcmp(fwlog_param, "dbgpins")) {
641 wl->conf.fwlog.mode = WL12XX_FWLOG_CONTINUOUS;
642 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_DBG_PINS;
643 } else if (!strcmp(fwlog_param, "disable")) {
644 wl->conf.fwlog.mem_blocks = 0;
645 wl->conf.fwlog.output = WL12XX_FWLOG_OUTPUT_NONE;
646 } else {
647 wl1271_error("Unknown fwlog parameter %s", fwlog_param);
648 }
649 }
650}
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +0300651
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300652static int wl1271_plt_init(struct wl1271 *wl)
653{
Eliad Peller188e7f52011-12-06 12:15:06 +0200654 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300655
Shahar Levi49d750ca2011-03-06 16:32:09 +0200656 if (wl->chip.id == CHIP_ID_1283_PG20)
657 ret = wl128x_cmd_general_parms(wl);
658 else
659 ret = wl1271_cmd_general_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200660 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200661 return ret;
662
Shahar Levi49d750ca2011-03-06 16:32:09 +0200663 if (wl->chip.id == CHIP_ID_1283_PG20)
664 ret = wl128x_cmd_radio_parms(wl);
665 else
666 ret = wl1271_cmd_radio_parms(wl);
Luciano Coelho4a904062009-11-23 23:22:18 +0200667 if (ret < 0)
Luciano Coelhocc7defa2009-11-23 23:22:16 +0200668 return ret;
669
Shahar Levi49d750ca2011-03-06 16:32:09 +0200670 if (wl->chip.id != CHIP_ID_1283_PG20) {
671 ret = wl1271_cmd_ext_radio_parms(wl);
672 if (ret < 0)
673 return ret;
674 }
Juuso Oikarinen644a4862010-10-05 13:11:56 +0200675 if (ret < 0)
676 return ret;
677
Shahar Levi48a61472011-03-06 16:32:08 +0200678 /* Chip-specific initializations */
679 ret = wl1271_chip_specific_init(wl);
680 if (ret < 0)
681 return ret;
682
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300683 ret = wl1271_acx_init_mem_config(wl);
684 if (ret < 0)
685 return ret;
686
Eliad Peller7f0979882011-08-14 13:17:06 +0300687 ret = wl12xx_acx_mem_cfg(wl);
Gery Kahn1ec610e2011-02-01 03:03:08 -0600688 if (ret < 0)
689 goto out_free_memmap;
690
Luciano Coelho12419cc2010-02-18 13:25:44 +0200691 /* Enable data path */
Luciano Coelho94210892009-12-11 15:40:55 +0200692 ret = wl1271_cmd_data_path(wl, 1);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300693 if (ret < 0)
Luciano Coelho12419cc2010-02-18 13:25:44 +0200694 goto out_free_memmap;
695
696 /* Configure for CAM power saving (ie. always active) */
697 ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
698 if (ret < 0)
699 goto out_free_memmap;
700
701 /* configure PM */
702 ret = wl1271_acx_pm_config(wl);
703 if (ret < 0)
704 goto out_free_memmap;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300705
706 return 0;
Luciano Coelho12419cc2010-02-18 13:25:44 +0200707
708 out_free_memmap:
709 kfree(wl->target_mem_map);
710 wl->target_mem_map = NULL;
711
712 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300713}
714
Eliad Peller6e8cd332011-10-10 10:13:13 +0200715static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
716 struct wl12xx_vif *wlvif,
717 u8 hlid, u8 tx_pkts)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200718{
Arik Nemtsovda032092011-08-25 12:43:15 +0300719 bool fw_ps, single_sta;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200720
Arik Nemtsovb622d992011-02-23 00:22:31 +0200721 fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Arik Nemtsovda032092011-08-25 12:43:15 +0300722 single_sta = (wl->active_sta_count == 1);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200723
724 /*
725 * Wake up from high level PS if the STA is asleep with too little
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300726 * packets in FW or if the STA is awake.
Arik Nemtsovb622d992011-02-23 00:22:31 +0200727 */
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300728 if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200729 wl12xx_ps_link_end(wl, wlvif, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200730
Arik Nemtsovda032092011-08-25 12:43:15 +0300731 /*
732 * Start high-level PS if the STA is asleep with enough blocks in FW.
733 * Make an exception if this is the only connected station. In this
734 * case FW-memory congestion is not a problem.
735 */
736 else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
Eliad Peller6e8cd332011-10-10 10:13:13 +0200737 wl12xx_ps_link_start(wl, wlvif, hlid, true);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200738}
739
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300740static void wl12xx_irq_update_links_status(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200741 struct wl12xx_vif *wlvif,
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300742 struct wl12xx_fw_status *status)
Arik Nemtsovb622d992011-02-23 00:22:31 +0200743{
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200744 struct wl1271_link *lnk;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200745 u32 cur_fw_ps_map;
Arik Nemtsov9b17f1b2011-08-14 13:17:35 +0300746 u8 hlid, cnt;
747
748 /* TODO: also use link_fast_bitmap here */
Arik Nemtsovb622d992011-02-23 00:22:31 +0200749
750 cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap);
751 if (wl->ap_fw_ps_map != cur_fw_ps_map) {
752 wl1271_debug(DEBUG_PSM,
753 "link ps prev 0x%x cur 0x%x changed 0x%x",
754 wl->ap_fw_ps_map, cur_fw_ps_map,
755 wl->ap_fw_ps_map ^ cur_fw_ps_map);
756
757 wl->ap_fw_ps_map = cur_fw_ps_map;
758 }
759
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200760 for_each_set_bit(hlid, wlvif->ap.sta_hlid_map, WL12XX_MAX_LINKS) {
761 lnk = &wl->links[hlid];
762 cnt = status->tx_lnk_free_pkts[hlid] - lnk->prev_freed_pkts;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200763
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200764 lnk->prev_freed_pkts = status->tx_lnk_free_pkts[hlid];
765 lnk->allocated_pkts -= cnt;
Arik Nemtsovb622d992011-02-23 00:22:31 +0200766
Eliad Peller6e8cd332011-10-10 10:13:13 +0200767 wl12xx_irq_ps_regulate_link(wl, wlvif, hlid,
768 lnk->allocated_pkts);
Arik Nemtsovb622d992011-02-23 00:22:31 +0200769 }
770}
771
Eliad Peller4d56ad92011-08-14 13:17:05 +0300772static void wl12xx_fw_status(struct wl1271 *wl,
773 struct wl12xx_fw_status *status)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300774{
Eliad Peller6e8cd332011-10-10 10:13:13 +0200775 struct wl12xx_vif *wlvif;
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200776 struct timespec ts;
Shahar Levi13b107d2011-03-06 16:32:12 +0200777 u32 old_tx_blk_count = wl->tx_blocks_available;
Eliad Peller4d56ad92011-08-14 13:17:05 +0300778 int avail, freed_blocks;
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300779 int i;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300780
Eliad Peller4d56ad92011-08-14 13:17:05 +0300781 wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
Shahar Levi13b107d2011-03-06 16:32:12 +0200782
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300783 wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
784 "drv_rx_counter = %d, tx_results_counter = %d)",
785 status->intr,
786 status->fw_rx_counter,
787 status->drv_rx_counter,
788 status->tx_results_counter);
789
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300790 for (i = 0; i < NUM_TX_QUEUES; i++) {
791 /* prevent wrap-around in freed-packets counter */
Arik Nemtsov742246f2011-08-14 13:17:33 +0300792 wl->tx_allocated_pkts[i] -=
Arik Nemtsovbf54e302011-08-14 13:17:32 +0300793 (status->tx_released_pkts[i] -
794 wl->tx_pkts_freed[i]) & 0xff;
795
796 wl->tx_pkts_freed[i] = status->tx_released_pkts[i];
797 }
798
Arik Nemtsovbdf91cf2011-08-14 13:17:34 +0300799 /* prevent wrap-around in total blocks counter */
800 if (likely(wl->tx_blocks_freed <=
801 le32_to_cpu(status->total_released_blks)))
802 freed_blocks = le32_to_cpu(status->total_released_blks) -
803 wl->tx_blocks_freed;
804 else
805 freed_blocks = 0x100000000LL - wl->tx_blocks_freed +
806 le32_to_cpu(status->total_released_blks);
807
Eliad Peller4d56ad92011-08-14 13:17:05 +0300808 wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks);
Shahar Levi13b107d2011-03-06 16:32:12 +0200809
Arik Nemtsov7bb5d6c2011-08-14 13:17:00 +0300810 wl->tx_allocated_blocks -= freed_blocks;
811
Eliad Peller4d56ad92011-08-14 13:17:05 +0300812 avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks;
Ido Yarivd2f4d472011-03-31 10:07:00 +0200813
Eliad Peller4d56ad92011-08-14 13:17:05 +0300814 /*
815 * The FW might change the total number of TX memblocks before
816 * we get a notification about blocks being released. Thus, the
817 * available blocks calculation might yield a temporary result
818 * which is lower than the actual available blocks. Keeping in
819 * mind that only blocks that were allocated can be moved from
820 * TX to RX, tx_blocks_available should never decrease here.
821 */
822 wl->tx_blocks_available = max((int)wl->tx_blocks_available,
823 avail);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300824
Ido Yariva5225502010-10-12 14:49:10 +0200825 /* if more blocks are available now, tx work can be scheduled */
Shahar Levi13b107d2011-03-06 16:32:12 +0200826 if (wl->tx_blocks_available > old_tx_blk_count)
Ido Yariva5225502010-10-12 14:49:10 +0200827 clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300828
Eliad Peller4d56ad92011-08-14 13:17:05 +0300829 /* for AP update num of allocated TX blocks per link and ps status */
Eliad Peller6e8cd332011-10-10 10:13:13 +0200830 wl12xx_for_each_wlvif_ap(wl, wlvif) {
Eliad Pellerc7ffb902011-10-05 11:56:05 +0200831 wl12xx_irq_update_links_status(wl, wlvif, status);
Eliad Peller6e8cd332011-10-10 10:13:13 +0200832 }
Eliad Peller4d56ad92011-08-14 13:17:05 +0300833
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300834 /* update the host-chipset time offset */
Juuso Oikarinenac5e1e32010-02-22 08:38:38 +0200835 getnstimeofday(&ts);
836 wl->time_offset = (timespec_to_ns(&ts) >> 10) -
837 (s64)le32_to_cpu(status->fw_localtime);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300838}
839
Ido Yariva6208652011-03-01 15:14:41 +0200840static void wl1271_flush_deferred_work(struct wl1271 *wl)
841{
842 struct sk_buff *skb;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200843
Ido Yariva6208652011-03-01 15:14:41 +0200844 /* Pass all received frames to the network stack */
845 while ((skb = skb_dequeue(&wl->deferred_rx_queue)))
846 ieee80211_rx_ni(wl->hw, skb);
847
848 /* Return sent skbs to the network stack */
849 while ((skb = skb_dequeue(&wl->deferred_tx_queue)))
Eliad Pellerc27d3ac2011-06-07 10:40:39 +0300850 ieee80211_tx_status_ni(wl->hw, skb);
Ido Yariva6208652011-03-01 15:14:41 +0200851}
852
853static void wl1271_netstack_work(struct work_struct *work)
854{
855 struct wl1271 *wl =
856 container_of(work, struct wl1271, netstack_work);
857
858 do {
859 wl1271_flush_deferred_work(wl);
860 } while (skb_queue_len(&wl->deferred_rx_queue));
861}
862
863#define WL1271_IRQ_MAX_LOOPS 256
864
Felipe Balbi4b32a2c2011-10-06 10:46:20 +0300865static irqreturn_t wl1271_irq(int irq, void *cookie)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300866{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300867 int ret;
Juuso Oikarinenc15f63b2009-10-12 15:08:50 +0300868 u32 intr;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200869 int loopcount = WL1271_IRQ_MAX_LOOPS;
Ido Yariva6208652011-03-01 15:14:41 +0200870 struct wl1271 *wl = (struct wl1271 *)cookie;
871 bool done = false;
872 unsigned int defer_count;
Ido Yarivb07d4032011-03-01 15:14:43 +0200873 unsigned long flags;
874
875 /* TX might be handled here, avoid redundant work */
876 set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
877 cancel_work_sync(&wl->tx_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300878
Ido Yariv341b7cd2011-03-31 10:07:01 +0200879 /*
880 * In case edge triggered interrupt must be used, we cannot iterate
881 * more than once without introducing race conditions with the hardirq.
882 */
883 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
884 loopcount = 1;
885
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300886 mutex_lock(&wl->mutex);
887
888 wl1271_debug(DEBUG_IRQ, "IRQ work");
889
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200890 if (unlikely(wl->state == WL1271_STATE_OFF))
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300891 goto out;
892
Ido Yariva6208652011-03-01 15:14:41 +0200893 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300894 if (ret < 0)
895 goto out;
896
Ido Yariva6208652011-03-01 15:14:41 +0200897 while (!done && loopcount--) {
898 /*
899 * In order to avoid a race with the hardirq, clear the flag
900 * before acknowledging the chip. Since the mutex is held,
901 * wl1271_ps_elp_wakeup cannot be called concurrently.
902 */
903 clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
904 smp_mb__after_clear_bit();
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200905
Eliad Peller4d56ad92011-08-14 13:17:05 +0300906 wl12xx_fw_status(wl, wl->fw_status);
907 intr = le32_to_cpu(wl->fw_status->intr);
Ido Yariva6208652011-03-01 15:14:41 +0200908 intr &= WL1271_INTR_MASK;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200909 if (!intr) {
Ido Yariva6208652011-03-01 15:14:41 +0200910 done = true;
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200911 continue;
912 }
913
Eliad Pellerccc83b02010-10-27 14:09:57 +0200914 if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
915 wl1271_error("watchdog interrupt received! "
916 "starting recovery.");
Ido Yarivbaacb9ae2011-06-06 14:57:05 +0300917 wl12xx_queue_recovery_work(wl);
Eliad Pellerccc83b02010-10-27 14:09:57 +0200918
919 /* restarting the chip. ignore any other interrupt. */
920 goto out;
921 }
922
Ido Yariva6208652011-03-01 15:14:41 +0200923 if (likely(intr & WL1271_ACX_INTR_DATA)) {
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200924 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
925
Eliad Peller4d56ad92011-08-14 13:17:05 +0300926 wl12xx_rx(wl, wl->fw_status);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200927
Ido Yariva5225502010-10-12 14:49:10 +0200928 /* Check if any tx blocks were freed */
Ido Yarivb07d4032011-03-01 15:14:43 +0200929 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200930 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300931 wl1271_tx_total_queue_count(wl) > 0) {
Ido Yarivb07d4032011-03-01 15:14:43 +0200932 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200933 /*
934 * In order to avoid starvation of the TX path,
935 * call the work function directly.
936 */
Eliad Pellera32d0cd2011-10-10 10:12:55 +0200937 wl1271_tx_work_locked(wl);
Ido Yarivb07d4032011-03-01 15:14:43 +0200938 } else {
939 spin_unlock_irqrestore(&wl->wl_lock, flags);
Ido Yariva5225502010-10-12 14:49:10 +0200940 }
941
Ido Yariv8aad2462011-03-01 15:14:38 +0200942 /* check for tx results */
Eliad Peller4d56ad92011-08-14 13:17:05 +0300943 if (wl->fw_status->tx_results_counter !=
Ido Yariv8aad2462011-03-01 15:14:38 +0200944 (wl->tx_results_count & 0xff))
945 wl1271_tx_complete(wl);
Ido Yariva6208652011-03-01 15:14:41 +0200946
947 /* Make sure the deferred queues don't get too long */
948 defer_count = skb_queue_len(&wl->deferred_tx_queue) +
949 skb_queue_len(&wl->deferred_rx_queue);
950 if (defer_count > WL1271_DEFERRED_QUEUE_LIMIT)
951 wl1271_flush_deferred_work(wl);
Juuso Oikarinen1e73eb62010-02-22 08:38:37 +0200952 }
953
954 if (intr & WL1271_ACX_INTR_EVENT_A) {
955 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
956 wl1271_event_handle(wl, 0);
957 }
958
959 if (intr & WL1271_ACX_INTR_EVENT_B) {
960 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
961 wl1271_event_handle(wl, 1);
962 }
963
964 if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
965 wl1271_debug(DEBUG_IRQ,
966 "WL1271_ACX_INTR_INIT_COMPLETE");
967
968 if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
969 wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300970 }
971
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300972 wl1271_ps_elp_sleep(wl);
973
974out:
Ido Yarivb07d4032011-03-01 15:14:43 +0200975 spin_lock_irqsave(&wl->wl_lock, flags);
976 /* In case TX was not handled here, queue TX work */
977 clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
978 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
Arik Nemtsovf1a46382011-07-07 14:25:23 +0300979 wl1271_tx_total_queue_count(wl) > 0)
Ido Yarivb07d4032011-03-01 15:14:43 +0200980 ieee80211_queue_work(wl->hw, &wl->tx_work);
981 spin_unlock_irqrestore(&wl->wl_lock, flags);
982
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300983 mutex_unlock(&wl->mutex);
Ido Yariva6208652011-03-01 15:14:41 +0200984
985 return IRQ_HANDLED;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300986}
987
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300988static int wl1271_fetch_firmware(struct wl1271 *wl)
989{
990 const struct firmware *fw;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200991 const char *fw_name;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +0300992 int ret;
993
Arik Nemtsovc302b2c2011-08-17 10:45:48 +0300994 if (wl->chip.id == CHIP_ID_1283_PG20)
995 fw_name = WL128X_FW_NAME;
996 else
997 fw_name = WL127X_FW_NAME;
Arik Nemtsov166d5042010-10-16 21:44:57 +0200998
999 wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name);
1000
Felipe Balbia390e852011-10-06 10:07:44 +03001001 ret = request_firmware(&fw, fw_name, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001002
1003 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001004 wl1271_error("could not get firmware %s: %d", fw_name, ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001005 return ret;
1006 }
1007
1008 if (fw->size % 4) {
1009 wl1271_error("firmware size is not multiple of 32 bits: %zu",
1010 fw->size);
1011 ret = -EILSEQ;
1012 goto out;
1013 }
1014
Arik Nemtsov166d5042010-10-16 21:44:57 +02001015 vfree(wl->fw);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001016 wl->fw_len = fw->size;
Juuso Oikarinen1fba4972009-10-08 21:56:32 +03001017 wl->fw = vmalloc(wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001018
1019 if (!wl->fw) {
1020 wl1271_error("could not allocate memory for the firmware");
1021 ret = -ENOMEM;
1022 goto out;
1023 }
1024
1025 memcpy(wl->fw, fw->data, wl->fw_len);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001026 ret = 0;
1027
1028out:
1029 release_firmware(fw);
1030
1031 return ret;
1032}
1033
1034static int wl1271_fetch_nvs(struct wl1271 *wl)
1035{
1036 const struct firmware *fw;
1037 int ret;
1038
Felipe Balbia390e852011-10-06 10:07:44 +03001039 ret = request_firmware(&fw, WL12XX_NVS_NAME, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001040
1041 if (ret < 0) {
Pontus Fuchs35898932011-11-30 15:35:09 +01001042 wl1271_error("could not get nvs file %s: %d", WL12XX_NVS_NAME,
1043 ret);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001044 return ret;
1045 }
1046
Shahar Levibc765bf2011-03-06 16:32:10 +02001047 wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001048
1049 if (!wl->nvs) {
1050 wl1271_error("could not allocate memory for the nvs file");
1051 ret = -ENOMEM;
1052 goto out;
1053 }
1054
Juuso Oikarinen02fabb02010-08-19 04:41:15 +02001055 wl->nvs_len = fw->size;
1056
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001057out:
1058 release_firmware(fw);
1059
1060 return ret;
1061}
1062
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001063void wl12xx_queue_recovery_work(struct wl1271 *wl)
1064{
1065 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
1066 ieee80211_queue_work(wl->hw, &wl->recovery_work);
1067}
1068
Ido Yariv95dac04f2011-06-06 14:57:06 +03001069size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
1070{
1071 size_t len = 0;
1072
1073 /* The FW log is a length-value list, find where the log end */
1074 while (len < maxlen) {
1075 if (memblock[len] == 0)
1076 break;
1077 if (len + memblock[len] + 1 > maxlen)
1078 break;
1079 len += memblock[len] + 1;
1080 }
1081
1082 /* Make sure we have enough room */
1083 len = min(len, (size_t)(PAGE_SIZE - wl->fwlog_size));
1084
1085 /* Fill the FW log file, consumed by the sysfs fwlog entry */
1086 memcpy(wl->fwlog + wl->fwlog_size, memblock, len);
1087 wl->fwlog_size += len;
1088
1089 return len;
1090}
1091
1092static void wl12xx_read_fwlog_panic(struct wl1271 *wl)
1093{
1094 u32 addr;
1095 u32 first_addr;
1096 u8 *block;
1097
1098 if ((wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) ||
1099 (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) ||
1100 (wl->conf.fwlog.mem_blocks == 0))
1101 return;
1102
1103 wl1271_info("Reading FW panic log");
1104
1105 block = kmalloc(WL12XX_HW_BLOCK_SIZE, GFP_KERNEL);
1106 if (!block)
1107 return;
1108
1109 /*
1110 * Make sure the chip is awake and the logger isn't active.
1111 * This might fail if the firmware hanged.
1112 */
1113 if (!wl1271_ps_elp_wakeup(wl))
1114 wl12xx_cmd_stop_fwlog(wl);
1115
1116 /* Read the first memory block address */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001117 wl12xx_fw_status(wl, wl->fw_status);
1118 first_addr = le32_to_cpu(wl->fw_status->log_start_addr);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001119 if (!first_addr)
1120 goto out;
1121
1122 /* Traverse the memory blocks linked list */
1123 addr = first_addr;
1124 do {
1125 memset(block, 0, WL12XX_HW_BLOCK_SIZE);
1126 wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE,
1127 false);
1128
1129 /*
1130 * Memory blocks are linked to one another. The first 4 bytes
1131 * of each memory block hold the hardware address of the next
1132 * one. The last memory block points to the first one.
1133 */
Eliad Peller4d56ad92011-08-14 13:17:05 +03001134 addr = le32_to_cpup((__le32 *)block);
Ido Yariv95dac04f2011-06-06 14:57:06 +03001135 if (!wl12xx_copy_fwlog(wl, block + sizeof(addr),
1136 WL12XX_HW_BLOCK_SIZE - sizeof(addr)))
1137 break;
1138 } while (addr && (addr != first_addr));
1139
1140 wake_up_interruptible(&wl->fwlog_waitq);
1141
1142out:
1143 kfree(block);
1144}
1145
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001146static void wl1271_recovery_work(struct work_struct *work)
1147{
1148 struct wl1271 *wl =
1149 container_of(work, struct wl1271, recovery_work);
Eliad Peller48e93e42011-10-10 10:12:58 +02001150 struct wl12xx_vif *wlvif;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001151 struct ieee80211_vif *vif;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001152
1153 mutex_lock(&wl->mutex);
1154
1155 if (wl->state != WL1271_STATE_ON)
Eliad Pellerf0277432011-10-10 10:13:14 +02001156 goto out_unlock;
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001157
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001158 /* Avoid a recursive recovery */
1159 set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1160
Ido Yariv95dac04f2011-06-06 14:57:06 +03001161 wl12xx_read_fwlog_panic(wl);
1162
Arik Nemtsov52dcaf52011-04-18 14:15:24 +03001163 wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
1164 wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001165
Eliad Peller2a5bff02011-08-25 18:10:59 +03001166 BUG_ON(bug_on_recovery);
1167
Oz Krakowskib992c682011-06-26 10:36:02 +03001168 /*
1169 * Advance security sequence number to overcome potential progress
1170 * in the firmware during recovery. This doens't hurt if the network is
1171 * not encrypted.
1172 */
Eliad Peller48e93e42011-10-10 10:12:58 +02001173 wl12xx_for_each_wlvif(wl, wlvif) {
Eliad Pellerba8447f62011-10-10 10:13:00 +02001174 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
Eliad Peller53d40d02011-10-10 10:13:02 +02001175 test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Peller48e93e42011-10-10 10:12:58 +02001176 wlvif->tx_security_seq +=
1177 WL1271_TX_SQN_POST_RECOVERY_PADDING;
1178 }
Oz Krakowskib992c682011-06-26 10:36:02 +03001179
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001180 /* Prevent spurious TX during FW restart */
1181 ieee80211_stop_queues(wl->hw);
1182
Luciano Coelho33c2c062011-05-10 14:46:02 +03001183 if (wl->sched_scanning) {
1184 ieee80211_sched_scan_stopped(wl->hw);
1185 wl->sched_scanning = false;
1186 }
1187
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001188 /* reboot the chipset */
Eliad Peller6e8cd332011-10-10 10:13:13 +02001189 while (!list_empty(&wl->wlvif_list)) {
1190 wlvif = list_first_entry(&wl->wlvif_list,
1191 struct wl12xx_vif, list);
1192 vif = wl12xx_wlvif_to_vif(wlvif);
1193 __wl1271_op_remove_interface(wl, vif, false);
1194 }
Eliad Pellerf0277432011-10-10 10:13:14 +02001195 mutex_unlock(&wl->mutex);
1196 wl1271_op_stop(wl->hw);
Ido Yarivbaacb9ae2011-06-06 14:57:05 +03001197
1198 clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
1199
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001200 ieee80211_restart_hw(wl->hw);
1201
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03001202 /*
1203 * Its safe to enable TX now - the queues are stopped after a request
1204 * to restart the HW.
1205 */
1206 ieee80211_wake_queues(wl->hw);
Eliad Pellerf0277432011-10-10 10:13:14 +02001207 return;
1208out_unlock:
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001209 mutex_unlock(&wl->mutex);
1210}
1211
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001212static void wl1271_fw_wakeup(struct wl1271 *wl)
1213{
1214 u32 elp_reg;
1215
1216 elp_reg = ELPCTRL_WAKE_UP;
Juuso Oikarinen74621412009-10-12 15:08:54 +03001217 wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001218}
1219
1220static int wl1271_setup(struct wl1271 *wl)
1221{
1222 wl->fw_status = kmalloc(sizeof(*wl->fw_status), GFP_KERNEL);
1223 if (!wl->fw_status)
1224 return -ENOMEM;
1225
1226 wl->tx_res_if = kmalloc(sizeof(*wl->tx_res_if), GFP_KERNEL);
1227 if (!wl->tx_res_if) {
1228 kfree(wl->fw_status);
1229 return -ENOMEM;
1230 }
1231
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001232 return 0;
1233}
1234
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001235static int wl12xx_set_power_on(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001236{
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001237 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001238
Juuso Oikarinen01ac17e2009-12-11 15:41:02 +02001239 msleep(WL1271_PRE_POWER_ON_SLEEP);
Ohad Ben-Cohen2cc78ff2010-09-16 01:22:04 +02001240 ret = wl1271_power_on(wl);
1241 if (ret < 0)
1242 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001243 msleep(WL1271_POWER_ON_SLEEP);
Teemu Paasikivi9b280722010-02-18 13:25:56 +02001244 wl1271_io_reset(wl);
1245 wl1271_io_init(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001246
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001247 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001248
1249 /* ELP module wake up */
1250 wl1271_fw_wakeup(wl);
1251
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001252out:
1253 return ret;
1254}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001255
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02001256static int wl1271_chip_wakeup(struct wl1271 *wl)
1257{
1258 int ret = 0;
1259
1260 ret = wl12xx_set_power_on(wl);
1261 if (ret < 0)
1262 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001263
Luciano Coelhoe62c9ce2011-11-03 08:44:42 +02001264 /*
1265 * For wl127x based devices we could use the default block
1266 * size (512 bytes), but due to a bug in the sdio driver, we
1267 * need to set it explicitly after the chip is powered on. To
1268 * simplify the code and since the performance impact is
1269 * negligible, we use the same block size for all different
1270 * chip types.
1271 */
1272 if (!wl1271_set_block_size(wl))
1273 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001274
1275 switch (wl->chip.id) {
1276 case CHIP_ID_1271_PG10:
1277 wl1271_warning("chip id 0x%x (1271 PG10) support is obsolete",
1278 wl->chip.id);
1279
1280 ret = wl1271_setup(wl);
1281 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001282 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001283 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001284 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001285
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001286 case CHIP_ID_1271_PG20:
1287 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
1288 wl->chip.id);
1289
1290 ret = wl1271_setup(wl);
1291 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001292 goto out;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001293 wl->quirks |= WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001294 break;
Luciano Coelhoce39def2011-11-03 08:44:41 +02001295
Shahar Levi0830cee2011-03-06 16:32:20 +02001296 case CHIP_ID_1283_PG20:
1297 wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
1298 wl->chip.id);
1299
1300 ret = wl1271_setup(wl);
1301 if (ret < 0)
1302 goto out;
1303 break;
1304 case CHIP_ID_1283_PG10:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001305 default:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001306 wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001307 ret = -ENODEV;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001308 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001309 }
1310
Arik Nemtsovc302b2c2011-08-17 10:45:48 +03001311 if (wl->fw == NULL) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001312 ret = wl1271_fetch_firmware(wl);
1313 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001314 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001315 }
1316
1317 /* No NVS from netlink, try to get it from the filesystem */
1318 if (wl->nvs == NULL) {
1319 ret = wl1271_fetch_nvs(wl);
1320 if (ret < 0)
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001321 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001322 }
1323
1324out:
1325 return ret;
1326}
1327
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001328int wl1271_plt_start(struct wl1271 *wl)
1329{
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001330 int retries = WL1271_BOOT_RETRIES;
Gery Kahn6f07b722011-07-18 14:21:49 +03001331 struct wiphy *wiphy = wl->hw->wiphy;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001332 int ret;
1333
1334 mutex_lock(&wl->mutex);
1335
1336 wl1271_notice("power up");
1337
1338 if (wl->state != WL1271_STATE_OFF) {
1339 wl1271_error("cannot go into PLT state because not "
1340 "in off state: %d", wl->state);
1341 ret = -EBUSY;
1342 goto out;
1343 }
1344
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001345 while (retries) {
1346 retries--;
1347 ret = wl1271_chip_wakeup(wl);
1348 if (ret < 0)
1349 goto power_off;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001350
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001351 ret = wl1271_boot(wl);
1352 if (ret < 0)
1353 goto power_off;
1354
1355 ret = wl1271_plt_init(wl);
1356 if (ret < 0)
1357 goto irq_disable;
1358
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001359 wl->state = WL1271_STATE_PLT;
1360 wl1271_notice("firmware booted in PLT mode (%s)",
Levi, Shahar4b7fac72011-01-23 07:27:22 +01001361 wl->chip.fw_ver_str);
Luciano Coelhoe7ddf542011-03-10 15:24:57 +02001362
Gery Kahn6f07b722011-07-18 14:21:49 +03001363 /* update hw/fw version info in wiphy struct */
1364 wiphy->hw_version = wl->chip.id;
1365 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
1366 sizeof(wiphy->fw_version));
1367
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001368 goto out;
1369
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001370irq_disable:
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001371 mutex_unlock(&wl->mutex);
1372 /* Unlocking the mutex in the middle of handling is
1373 inherently unsafe. In this case we deem it safe to do,
1374 because we need to let any possibly pending IRQ out of
1375 the system (and while we are WL1271_STATE_OFF the IRQ
1376 work function will not do anything.) Also, any other
1377 possible concurrent operations will fail due to the
1378 current state, hence the wl1271 struct should be safe. */
Ido Yariva6208652011-03-01 15:14:41 +02001379 wl1271_disable_interrupts(wl);
1380 wl1271_flush_deferred_work(wl);
1381 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001382 mutex_lock(&wl->mutex);
1383power_off:
1384 wl1271_power_off(wl);
1385 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001386
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02001387 wl1271_error("firmware boot in PLT mode failed despite %d retries",
1388 WL1271_BOOT_RETRIES);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001389out:
1390 mutex_unlock(&wl->mutex);
1391
1392 return ret;
1393}
1394
Ido Yarivf3df1332012-01-11 09:42:39 +02001395int wl1271_plt_stop(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001396{
1397 int ret = 0;
1398
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001399 wl1271_notice("power down");
1400
Ido Yariv46b0cc92012-01-11 09:42:41 +02001401 /*
1402 * Interrupts must be disabled before setting the state to OFF.
1403 * Otherwise, the interrupt handler might be called and exit without
1404 * reading the interrupt status.
1405 */
1406 wl1271_disable_interrupts(wl);
Ido Yarivf3df1332012-01-11 09:42:39 +02001407 mutex_lock(&wl->mutex);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001408 if (wl->state != WL1271_STATE_PLT) {
Ido Yarivf3df1332012-01-11 09:42:39 +02001409 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001410
1411 /*
1412 * This will not necessarily enable interrupts as interrupts
1413 * may have been disabled when op_stop was called. It will,
1414 * however, balance the above call to disable_interrupts().
1415 */
1416 wl1271_enable_interrupts(wl);
1417
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001418 wl1271_error("cannot power down because not in PLT "
1419 "state: %d", wl->state);
1420 ret = -EBUSY;
1421 goto out;
1422 }
1423
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001424 mutex_unlock(&wl->mutex);
Ido Yarivf3df1332012-01-11 09:42:39 +02001425
Ido Yariva6208652011-03-01 15:14:41 +02001426 wl1271_flush_deferred_work(wl);
1427 cancel_work_sync(&wl->netstack_work);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02001428 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001429 cancel_delayed_work_sync(&wl->elp_work);
Ido Yariva4549692012-01-11 09:42:40 +02001430
1431 mutex_lock(&wl->mutex);
1432 wl1271_power_off(wl);
Luciano Coelhof6fbecc2012-01-11 09:42:42 +02001433 wl->flags = 0;
1434 wl->state = WL1271_STATE_OFF;
1435 wl->rx_counter = 0;
Ido Yariva4549692012-01-11 09:42:40 +02001436 mutex_unlock(&wl->mutex);
1437
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01001438out:
1439 return ret;
1440}
Juuso Oikarinen8c7f4f32010-09-21 06:23:29 +02001441
Johannes Berg7bb45682011-02-24 14:42:06 +01001442static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001443{
1444 struct wl1271 *wl = hw->priv;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001445 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1446 struct ieee80211_vif *vif = info->control.vif;
Eliad Peller0f168012011-10-11 13:52:25 +02001447 struct wl12xx_vif *wlvif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001448 unsigned long flags;
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001449 int q, mapping;
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001450 u8 hlid;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001451
Eliad Peller0f168012011-10-11 13:52:25 +02001452 if (vif)
1453 wlvif = wl12xx_vif_to_data(vif);
1454
Arik Nemtsov708bb3c2011-06-24 13:03:37 +03001455 mapping = skb_get_queue_mapping(skb);
1456 q = wl1271_tx_get_queue(mapping);
Ido Yarivb07d4032011-03-01 15:14:43 +02001457
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001458 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb);
Ido Yarivb07d4032011-03-01 15:14:43 +02001459
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001460 spin_lock_irqsave(&wl->wl_lock, flags);
Ido Yarivb07d4032011-03-01 15:14:43 +02001461
Juuso Oikarinen830fb672009-12-11 15:41:06 +02001462 /* queue the packet */
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001463 if (hlid == WL12XX_INVALID_LINK_ID ||
Eliad Peller0f168012011-10-11 13:52:25 +02001464 (wlvif && !test_bit(hlid, wlvif->links_map))) {
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001465 wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q);
Eliad Peller5de8eef2011-12-13 15:26:38 +02001466 ieee80211_free_txskb(hw, skb);
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001467 goto out;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02001468 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001469
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02001470 wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q);
1471 skb_queue_tail(&wl->links[hlid].tx_queue[q], skb);
1472
Arik Nemtsov04b4d69c2011-08-14 13:17:39 +03001473 wl->tx_queue_count[q]++;
1474
1475 /*
1476 * The workqueue is slow to process the tx_queue and we need stop
1477 * the queue here, otherwise the queue will get too long.
1478 */
1479 if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
1480 wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q);
1481 ieee80211_stop_queue(wl->hw, mapping);
1482 set_bit(q, &wl->stopped_queues_map);
1483 }
1484
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001485 /*
1486 * The chip specific setup must run before the first TX packet -
1487 * before that, the tx_work will not be initialized!
1488 */
1489
Ido Yarivb07d4032011-03-01 15:14:43 +02001490 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) &&
1491 !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags))
Ido Yariva5225502010-10-12 14:49:10 +02001492 ieee80211_queue_work(wl->hw, &wl->tx_work);
Ido Yarivb07d4032011-03-01 15:14:43 +02001493
Arik Nemtsov04216da2011-08-14 13:17:38 +03001494out:
Ido Yarivb07d4032011-03-01 15:14:43 +02001495 spin_unlock_irqrestore(&wl->wl_lock, flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001496}
1497
Shahar Leviae47c452011-03-06 16:32:14 +02001498int wl1271_tx_dummy_packet(struct wl1271 *wl)
1499{
Ido Yariv990f5de2011-03-31 10:06:59 +02001500 unsigned long flags;
Arik Nemtsov14623782011-08-28 15:11:57 +03001501 int q;
1502
1503 /* no need to queue a new dummy packet if one is already pending */
1504 if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
1505 return 0;
1506
1507 q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
Shahar Leviae47c452011-03-06 16:32:14 +02001508
Ido Yariv990f5de2011-03-31 10:06:59 +02001509 spin_lock_irqsave(&wl->wl_lock, flags);
1510 set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
Arik Nemtsovf1a46382011-07-07 14:25:23 +03001511 wl->tx_queue_count[q]++;
Ido Yariv990f5de2011-03-31 10:06:59 +02001512 spin_unlock_irqrestore(&wl->wl_lock, flags);
1513
1514 /* The FW is low on RX memory blocks, so send the dummy packet asap */
1515 if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
Eliad Pellera32d0cd2011-10-10 10:12:55 +02001516 wl1271_tx_work_locked(wl);
Ido Yariv990f5de2011-03-31 10:06:59 +02001517
1518 /*
1519 * If the FW TX is busy, TX work will be scheduled by the threaded
1520 * interrupt handler function
1521 */
1522 return 0;
1523}
1524
1525/*
1526 * The size of the dummy packet should be at least 1400 bytes. However, in
1527 * order to minimize the number of bus transactions, aligning it to 512 bytes
1528 * boundaries could be beneficial, performance wise
1529 */
1530#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
1531
Luciano Coelhocf27d862011-04-01 21:08:23 +03001532static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
Ido Yariv990f5de2011-03-31 10:06:59 +02001533{
1534 struct sk_buff *skb;
1535 struct ieee80211_hdr_3addr *hdr;
1536 unsigned int dummy_packet_size;
1537
1538 dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
1539 sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
1540
1541 skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
Shahar Leviae47c452011-03-06 16:32:14 +02001542 if (!skb) {
Ido Yariv990f5de2011-03-31 10:06:59 +02001543 wl1271_warning("Failed to allocate a dummy packet skb");
1544 return NULL;
Shahar Leviae47c452011-03-06 16:32:14 +02001545 }
1546
1547 skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
1548
1549 hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
1550 memset(hdr, 0, sizeof(*hdr));
1551 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
Ido Yariv990f5de2011-03-31 10:06:59 +02001552 IEEE80211_STYPE_NULLFUNC |
1553 IEEE80211_FCTL_TODS);
Shahar Leviae47c452011-03-06 16:32:14 +02001554
Ido Yariv990f5de2011-03-31 10:06:59 +02001555 memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
Shahar Leviae47c452011-03-06 16:32:14 +02001556
Luciano Coelho18b92ff2011-03-21 16:35:21 +02001557 /* Dummy packets require the TID to be management */
1558 skb->priority = WL1271_TID_MGMT;
Ido Yariv990f5de2011-03-31 10:06:59 +02001559
1560 /* Initialize all fields that might be used */
Hauke Mehrtens86c438f2011-04-26 23:27:44 +02001561 skb_set_queue_mapping(skb, 0);
Ido Yariv990f5de2011-03-31 10:06:59 +02001562 memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
Shahar Leviae47c452011-03-06 16:32:14 +02001563
Ido Yariv990f5de2011-03-31 10:06:59 +02001564 return skb;
Shahar Leviae47c452011-03-06 16:32:14 +02001565}
1566
Ido Yariv990f5de2011-03-31 10:06:59 +02001567
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03001568static struct notifier_block wl1271_dev_notifier = {
1569 .notifier_call = wl1271_dev_notify,
1570};
1571
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001572#ifdef CONFIG_PM
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001573static int wl1271_configure_suspend_sta(struct wl1271 *wl,
1574 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001575{
Eliad Pellere85d1622011-06-27 13:06:43 +03001576 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001577
Eliad Peller94390642011-05-13 11:57:13 +03001578 mutex_lock(&wl->mutex);
1579
Eliad Pellerba8447f62011-10-10 10:13:00 +02001580 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001581 goto out_unlock;
1582
Eliad Peller94390642011-05-13 11:57:13 +03001583 ret = wl1271_ps_elp_wakeup(wl);
1584 if (ret < 0)
1585 goto out_unlock;
1586
1587 /* enter psm if needed*/
Eliad Pellerc29bb002011-10-10 10:13:03 +02001588 if (!test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller94390642011-05-13 11:57:13 +03001589 DECLARE_COMPLETION_ONSTACK(compl);
1590
Eliad Peller6ec45dc2011-10-05 11:56:01 +02001591 wlvif->ps_compl = &compl;
Eliad Peller0603d892011-10-05 11:55:51 +02001592 ret = wl1271_ps_set_mode(wl, wlvif, STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001593 wlvif->basic_rate, true);
Eliad Peller94390642011-05-13 11:57:13 +03001594 if (ret < 0)
1595 goto out_sleep;
1596
1597 /* we must unlock here so we will be able to get events */
1598 wl1271_ps_elp_sleep(wl);
1599 mutex_unlock(&wl->mutex);
1600
1601 ret = wait_for_completion_timeout(
1602 &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
Pontus Fuchsef187062011-12-14 14:32:23 +01001603
1604 mutex_lock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001605 if (ret <= 0) {
1606 wl1271_warning("couldn't enter ps mode!");
1607 ret = -EBUSY;
Pontus Fuchsef187062011-12-14 14:32:23 +01001608 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001609 }
1610
Eliad Peller94390642011-05-13 11:57:13 +03001611 ret = wl1271_ps_elp_wakeup(wl);
1612 if (ret < 0)
Pontus Fuchsef187062011-12-14 14:32:23 +01001613 goto out_cleanup;
Eliad Peller94390642011-05-13 11:57:13 +03001614 }
1615out_sleep:
1616 wl1271_ps_elp_sleep(wl);
Pontus Fuchsef187062011-12-14 14:32:23 +01001617out_cleanup:
1618 wlvif->ps_compl = NULL;
Eliad Peller94390642011-05-13 11:57:13 +03001619out_unlock:
1620 mutex_unlock(&wl->mutex);
Eliad Peller94390642011-05-13 11:57:13 +03001621 return ret;
1622
1623}
1624
Eliad Peller0603d892011-10-05 11:55:51 +02001625static int wl1271_configure_suspend_ap(struct wl1271 *wl,
1626 struct wl12xx_vif *wlvif)
Eliad Peller94390642011-05-13 11:57:13 +03001627{
Eliad Pellere85d1622011-06-27 13:06:43 +03001628 int ret = 0;
Eliad Peller94390642011-05-13 11:57:13 +03001629
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001630 mutex_lock(&wl->mutex);
1631
Eliad Peller53d40d02011-10-10 10:13:02 +02001632 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
Eliad Pellere85d1622011-06-27 13:06:43 +03001633 goto out_unlock;
1634
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001635 ret = wl1271_ps_elp_wakeup(wl);
1636 if (ret < 0)
1637 goto out_unlock;
1638
Eliad Peller0603d892011-10-05 11:55:51 +02001639 ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001640
1641 wl1271_ps_elp_sleep(wl);
1642out_unlock:
1643 mutex_unlock(&wl->mutex);
1644 return ret;
1645
1646}
1647
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001648static int wl1271_configure_suspend(struct wl1271 *wl,
1649 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001650{
Eliad Peller536129c82011-10-05 11:55:45 +02001651 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001652 return wl1271_configure_suspend_sta(wl, wlvif);
Eliad Peller536129c82011-10-05 11:55:45 +02001653 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
Eliad Peller0603d892011-10-05 11:55:51 +02001654 return wl1271_configure_suspend_ap(wl, wlvif);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001655 return 0;
1656}
1657
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001658static void wl1271_configure_resume(struct wl1271 *wl,
1659 struct wl12xx_vif *wlvif)
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001660{
1661 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02001662 bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
1663 bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001664
1665 if (!is_sta && !is_ap)
Eliad Peller94390642011-05-13 11:57:13 +03001666 return;
1667
1668 mutex_lock(&wl->mutex);
1669 ret = wl1271_ps_elp_wakeup(wl);
1670 if (ret < 0)
1671 goto out;
1672
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001673 if (is_sta) {
1674 /* exit psm if it wasn't configured */
Eliad Pellerc29bb002011-10-10 10:13:03 +02001675 if (!test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02001676 wl1271_ps_set_mode(wl, wlvif, STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001677 wlvif->basic_rate, true);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001678 } else if (is_ap) {
Eliad Peller0603d892011-10-05 11:55:51 +02001679 wl1271_acx_beacon_filter_opt(wl, wlvif, false);
Eliad Peller8a7cf3f2011-06-06 12:21:54 +03001680 }
Eliad Peller94390642011-05-13 11:57:13 +03001681
1682 wl1271_ps_elp_sleep(wl);
1683out:
1684 mutex_unlock(&wl->mutex);
1685}
1686
Eliad Peller402e48612011-05-13 11:57:09 +03001687static int wl1271_op_suspend(struct ieee80211_hw *hw,
1688 struct cfg80211_wowlan *wow)
1689{
1690 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001691 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001692 int ret;
1693
Eliad Peller402e48612011-05-13 11:57:09 +03001694 wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
Eliad Peller4a859df2011-06-06 12:21:52 +03001695 WARN_ON(!wow || !wow->any);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001696
Eliad Peller4a859df2011-06-06 12:21:52 +03001697 wl->wow_enabled = true;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001698 wl12xx_for_each_wlvif(wl, wlvif) {
1699 ret = wl1271_configure_suspend(wl, wlvif);
1700 if (ret < 0) {
1701 wl1271_warning("couldn't prepare device to suspend");
1702 return ret;
1703 }
Eliad Pellerf44e5862011-05-13 11:57:11 +03001704 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001705 /* flush any remaining work */
1706 wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
Eliad Peller4a859df2011-06-06 12:21:52 +03001707
1708 /*
1709 * disable and re-enable interrupts in order to flush
1710 * the threaded_irq
1711 */
1712 wl1271_disable_interrupts(wl);
1713
1714 /*
1715 * set suspended flag to avoid triggering a new threaded_irq
1716 * work. no need for spinlock as interrupts are disabled.
1717 */
1718 set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1719
1720 wl1271_enable_interrupts(wl);
1721 flush_work(&wl->tx_work);
Eliad Peller6e8cd332011-10-10 10:13:13 +02001722 wl12xx_for_each_wlvif(wl, wlvif) {
1723 flush_delayed_work(&wlvif->pspoll_work);
1724 }
Eliad Peller4a859df2011-06-06 12:21:52 +03001725 flush_delayed_work(&wl->elp_work);
1726
Eliad Peller402e48612011-05-13 11:57:09 +03001727 return 0;
1728}
1729
1730static int wl1271_op_resume(struct ieee80211_hw *hw)
1731{
1732 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02001733 struct wl12xx_vif *wlvif;
Eliad Peller4a859df2011-06-06 12:21:52 +03001734 unsigned long flags;
1735 bool run_irq_work = false;
1736
Eliad Peller402e48612011-05-13 11:57:09 +03001737 wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
1738 wl->wow_enabled);
Eliad Peller4a859df2011-06-06 12:21:52 +03001739 WARN_ON(!wl->wow_enabled);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001740
1741 /*
1742 * re-enable irq_work enqueuing, and call irq_work directly if
1743 * there is a pending work.
1744 */
Eliad Peller4a859df2011-06-06 12:21:52 +03001745 spin_lock_irqsave(&wl->wl_lock, flags);
1746 clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
1747 if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
1748 run_irq_work = true;
1749 spin_unlock_irqrestore(&wl->wl_lock, flags);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001750
Eliad Peller4a859df2011-06-06 12:21:52 +03001751 if (run_irq_work) {
1752 wl1271_debug(DEBUG_MAC80211,
1753 "run postponed irq_work directly");
1754 wl1271_irq(0, wl);
1755 wl1271_enable_interrupts(wl);
Eliad Pellerf44e5862011-05-13 11:57:11 +03001756 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02001757 wl12xx_for_each_wlvif(wl, wlvif) {
1758 wl1271_configure_resume(wl, wlvif);
1759 }
Eliad Pellerff91afc2011-06-06 12:21:53 +03001760 wl->wow_enabled = false;
Eliad Pellerf44e5862011-05-13 11:57:11 +03001761
Eliad Peller402e48612011-05-13 11:57:09 +03001762 return 0;
1763}
Luciano Coelhof634a4e2011-05-18 16:51:26 -04001764#endif
Eliad Peller402e48612011-05-13 11:57:09 +03001765
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03001766static int wl1271_op_start(struct ieee80211_hw *hw)
1767{
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001768 wl1271_debug(DEBUG_MAC80211, "mac80211 start");
1769
1770 /*
1771 * We have to delay the booting of the hardware because
1772 * we need to know the local MAC address before downloading and
1773 * initializing the firmware. The MAC address cannot be changed
1774 * after boot, and without the proper MAC address, the firmware
1775 * will not function properly.
1776 *
1777 * The MAC address is first known when the corresponding interface
1778 * is added. That is where we will initialize the hardware.
1779 */
1780
Eliad Pellercdaac622012-01-31 11:57:16 +02001781 wl1271_error("wl12xx is in an ustable state (fw api update is "
1782 "taking place). skip this commit when bisecting");
1783 return -EBUSY;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001784}
1785
1786static void wl1271_op_stop(struct ieee80211_hw *hw)
1787{
Eliad Pellerbaf62772011-10-10 10:12:52 +02001788 struct wl1271 *wl = hw->priv;
1789 int i;
1790
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001791 wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
Eliad Pellerbaf62772011-10-10 10:12:52 +02001792
Ido Yariv46b0cc92012-01-11 09:42:41 +02001793 /*
1794 * Interrupts must be disabled before setting the state to OFF.
1795 * Otherwise, the interrupt handler might be called and exit without
1796 * reading the interrupt status.
1797 */
1798 wl1271_disable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001799 mutex_lock(&wl->mutex);
1800 if (wl->state == WL1271_STATE_OFF) {
1801 mutex_unlock(&wl->mutex);
Ido Yariv46b0cc92012-01-11 09:42:41 +02001802
1803 /*
1804 * This will not necessarily enable interrupts as interrupts
1805 * may have been disabled when op_stop was called. It will,
1806 * however, balance the above call to disable_interrupts().
1807 */
1808 wl1271_enable_interrupts(wl);
Eliad Peller10c8cd02011-10-10 10:13:06 +02001809 return;
1810 }
Ido Yariv46b0cc92012-01-11 09:42:41 +02001811
Eliad Pellerbaf62772011-10-10 10:12:52 +02001812 /*
1813 * this must be before the cancel_work calls below, so that the work
1814 * functions don't perform further work.
1815 */
1816 wl->state = WL1271_STATE_OFF;
Eliad Peller10c8cd02011-10-10 10:13:06 +02001817 mutex_unlock(&wl->mutex);
1818
1819 mutex_lock(&wl_list_mutex);
1820 list_del(&wl->list);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001821 mutex_unlock(&wl_list_mutex);
1822
Eliad Pellerbaf62772011-10-10 10:12:52 +02001823 wl1271_flush_deferred_work(wl);
1824 cancel_delayed_work_sync(&wl->scan_complete_work);
1825 cancel_work_sync(&wl->netstack_work);
1826 cancel_work_sync(&wl->tx_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02001827 cancel_delayed_work_sync(&wl->elp_work);
1828
1829 /* let's notify MAC80211 about the remaining pending TX frames */
1830 wl12xx_tx_reset(wl, true);
1831 mutex_lock(&wl->mutex);
1832
1833 wl1271_power_off(wl);
1834
1835 wl->band = IEEE80211_BAND_2GHZ;
1836
1837 wl->rx_counter = 0;
1838 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
1839 wl->tx_blocks_available = 0;
1840 wl->tx_allocated_blocks = 0;
1841 wl->tx_results_count = 0;
1842 wl->tx_packets_count = 0;
1843 wl->time_offset = 0;
Eliad Pellerbaf62772011-10-10 10:12:52 +02001844 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
1845 wl->ap_fw_ps_map = 0;
1846 wl->ap_ps_map = 0;
1847 wl->sched_scanning = false;
1848 memset(wl->roles_map, 0, sizeof(wl->roles_map));
1849 memset(wl->links_map, 0, sizeof(wl->links_map));
1850 memset(wl->roc_map, 0, sizeof(wl->roc_map));
1851 wl->active_sta_count = 0;
1852
1853 /* The system link is always allocated */
1854 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
1855
1856 /*
1857 * this is performed after the cancel_work calls and the associated
1858 * mutex_lock, so that wl1271_op_add_interface does not accidentally
1859 * get executed before all these vars have been reset.
1860 */
1861 wl->flags = 0;
1862
1863 wl->tx_blocks_freed = 0;
1864
1865 for (i = 0; i < NUM_TX_QUEUES; i++) {
1866 wl->tx_pkts_freed[i] = 0;
1867 wl->tx_allocated_pkts[i] = 0;
1868 }
1869
1870 wl1271_debugfs_reset(wl);
1871
1872 kfree(wl->fw_status);
1873 wl->fw_status = NULL;
1874 kfree(wl->tx_res_if);
1875 wl->tx_res_if = NULL;
1876 kfree(wl->target_mem_map);
1877 wl->target_mem_map = NULL;
1878
1879 mutex_unlock(&wl->mutex);
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02001880}
1881
Eliad Pellere5a359f2011-10-10 10:13:15 +02001882static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
1883{
1884 u8 policy = find_first_zero_bit(wl->rate_policies_map,
1885 WL12XX_MAX_RATE_POLICIES);
1886 if (policy >= WL12XX_MAX_RATE_POLICIES)
1887 return -EBUSY;
1888
1889 __set_bit(policy, wl->rate_policies_map);
1890 *idx = policy;
1891 return 0;
1892}
1893
1894static void wl12xx_free_rate_policy(struct wl1271 *wl, u8 *idx)
1895{
1896 if (WARN_ON(*idx >= WL12XX_MAX_RATE_POLICIES))
1897 return;
1898
1899 __clear_bit(*idx, wl->rate_policies_map);
1900 *idx = WL12XX_MAX_RATE_POLICIES;
1901}
1902
Eliad Peller536129c82011-10-05 11:55:45 +02001903static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001904{
Eliad Peller536129c82011-10-05 11:55:45 +02001905 switch (wlvif->bss_type) {
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001906 case BSS_TYPE_AP_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001907 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001908 return WL1271_ROLE_P2P_GO;
1909 else
1910 return WL1271_ROLE_AP;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001911
1912 case BSS_TYPE_STA_BSS:
Eliad Pellerfb0e7072011-10-05 11:55:47 +02001913 if (wlvif->p2p)
Eliad Peller045c7452011-08-28 15:23:01 +03001914 return WL1271_ROLE_P2P_CL;
1915 else
1916 return WL1271_ROLE_STA;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001917
Eliad Peller227e81e2011-08-14 13:17:26 +03001918 case BSS_TYPE_IBSS:
1919 return WL1271_ROLE_IBSS;
1920
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001921 default:
Eliad Peller536129c82011-10-05 11:55:45 +02001922 wl1271_error("invalid bss_type: %d", wlvif->bss_type);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03001923 }
1924 return WL12XX_INVALID_ROLE_TYPE;
1925}
1926
Eliad Peller83587502011-10-10 10:12:53 +02001927static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
Eliad Peller87fbcb02011-10-05 11:55:41 +02001928{
Eliad Pellere936bbe2011-10-05 11:55:56 +02001929 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02001930 int i;
Eliad Pellere936bbe2011-10-05 11:55:56 +02001931
Eliad Peller48e93e42011-10-10 10:12:58 +02001932 /* clear everything but the persistent data */
1933 memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent));
Eliad Pellere936bbe2011-10-05 11:55:56 +02001934
1935 switch (ieee80211_vif_type_p2p(vif)) {
1936 case NL80211_IFTYPE_P2P_CLIENT:
1937 wlvif->p2p = 1;
1938 /* fall-through */
1939 case NL80211_IFTYPE_STATION:
1940 wlvif->bss_type = BSS_TYPE_STA_BSS;
1941 break;
1942 case NL80211_IFTYPE_ADHOC:
1943 wlvif->bss_type = BSS_TYPE_IBSS;
1944 break;
1945 case NL80211_IFTYPE_P2P_GO:
1946 wlvif->p2p = 1;
1947 /* fall-through */
1948 case NL80211_IFTYPE_AP:
1949 wlvif->bss_type = BSS_TYPE_AP_BSS;
1950 break;
1951 default:
1952 wlvif->bss_type = MAX_BSS_TYPE;
1953 return -EOPNOTSUPP;
1954 }
1955
Eliad Peller0603d892011-10-05 11:55:51 +02001956 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02001957 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02001958 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001959
Eliad Pellere936bbe2011-10-05 11:55:56 +02001960 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
1961 wlvif->bss_type == BSS_TYPE_IBSS) {
1962 /* init sta/ibss data */
1963 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001964 wl12xx_allocate_rate_policy(wl, &wlvif->sta.basic_rate_idx);
1965 wl12xx_allocate_rate_policy(wl, &wlvif->sta.ap_rate_idx);
1966 wl12xx_allocate_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001967 } else {
1968 /* init ap data */
1969 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
1970 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02001971 wl12xx_allocate_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
1972 wl12xx_allocate_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
1973 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
1974 wl12xx_allocate_rate_policy(wl,
1975 &wlvif->ap.ucast_rate_idx[i]);
Eliad Pellere936bbe2011-10-05 11:55:56 +02001976 }
Eliad Pellera8ab39a2011-10-05 11:55:54 +02001977
Eliad Peller83587502011-10-10 10:12:53 +02001978 wlvif->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
1979 wlvif->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
Eliad Peller87fbcb02011-10-05 11:55:41 +02001980 wlvif->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Pellerd2d66c52011-10-05 11:55:43 +02001981 wlvif->basic_rate = CONF_TX_RATE_MASK_BASIC;
Eliad Peller30d0c8f2011-10-05 11:55:42 +02001982 wlvif->rate_set = CONF_TX_RATE_MASK_BASIC;
Eliad Peller6a899792011-10-05 11:55:58 +02001983 wlvif->beacon_int = WL1271_DEFAULT_BEACON_INT;
1984
Eliad Peller1b92f152011-10-10 10:13:09 +02001985 /*
1986 * mac80211 configures some values globally, while we treat them
1987 * per-interface. thus, on init, we have to copy them from wl
1988 */
1989 wlvif->band = wl->band;
Eliad Peller61f845f2011-10-10 10:13:10 +02001990 wlvif->channel = wl->channel;
Eliad Peller6bd65022011-10-10 10:13:11 +02001991 wlvif->power_level = wl->power_level;
Eliad Peller1b92f152011-10-10 10:13:09 +02001992
Eliad Peller9eb599e2011-10-10 10:12:59 +02001993 INIT_WORK(&wlvif->rx_streaming_enable_work,
1994 wl1271_rx_streaming_enable_work);
1995 INIT_WORK(&wlvif->rx_streaming_disable_work,
1996 wl1271_rx_streaming_disable_work);
Eliad Peller252efa42011-10-05 11:56:00 +02001997 INIT_DELAYED_WORK(&wlvif->pspoll_work, wl1271_pspoll_work);
Eliad Peller876272142011-10-10 10:12:54 +02001998 INIT_LIST_HEAD(&wlvif->list);
Eliad Peller252efa42011-10-05 11:56:00 +02001999
Eliad Peller9eb599e2011-10-10 10:12:59 +02002000 setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
2001 (unsigned long) wlvif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002002 return 0;
Eliad Peller87fbcb02011-10-05 11:55:41 +02002003}
2004
Eliad Peller1d095472011-10-10 10:12:49 +02002005static bool wl12xx_init_fw(struct wl1271 *wl)
2006{
2007 int retries = WL1271_BOOT_RETRIES;
2008 bool booted = false;
2009 struct wiphy *wiphy = wl->hw->wiphy;
2010 int ret;
2011
2012 while (retries) {
2013 retries--;
2014 ret = wl1271_chip_wakeup(wl);
2015 if (ret < 0)
2016 goto power_off;
2017
2018 ret = wl1271_boot(wl);
2019 if (ret < 0)
2020 goto power_off;
2021
2022 ret = wl1271_hw_init(wl);
2023 if (ret < 0)
2024 goto irq_disable;
2025
2026 booted = true;
2027 break;
2028
2029irq_disable:
2030 mutex_unlock(&wl->mutex);
2031 /* Unlocking the mutex in the middle of handling is
2032 inherently unsafe. In this case we deem it safe to do,
2033 because we need to let any possibly pending IRQ out of
2034 the system (and while we are WL1271_STATE_OFF the IRQ
2035 work function will not do anything.) Also, any other
2036 possible concurrent operations will fail due to the
2037 current state, hence the wl1271 struct should be safe. */
2038 wl1271_disable_interrupts(wl);
2039 wl1271_flush_deferred_work(wl);
2040 cancel_work_sync(&wl->netstack_work);
2041 mutex_lock(&wl->mutex);
2042power_off:
2043 wl1271_power_off(wl);
2044 }
2045
2046 if (!booted) {
2047 wl1271_error("firmware boot failed despite %d retries",
2048 WL1271_BOOT_RETRIES);
2049 goto out;
2050 }
2051
2052 wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
2053
2054 /* update hw/fw version info in wiphy struct */
2055 wiphy->hw_version = wl->chip.id;
2056 strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
2057 sizeof(wiphy->fw_version));
2058
2059 /*
2060 * Now we know if 11a is supported (info from the NVS), so disable
2061 * 11a channels if not supported
2062 */
2063 if (!wl->enable_11a)
2064 wiphy->bands[IEEE80211_BAND_5GHZ]->n_channels = 0;
2065
2066 wl1271_debug(DEBUG_MAC80211, "11a is %ssupported",
2067 wl->enable_11a ? "" : "not ");
2068
2069 wl->state = WL1271_STATE_ON;
2070out:
2071 return booted;
2072}
2073
Eliad Peller92e712d2011-12-18 20:25:43 +02002074static bool wl12xx_dev_role_started(struct wl12xx_vif *wlvif)
2075{
2076 return wlvif->dev_hlid != WL12XX_INVALID_LINK_ID;
2077}
2078
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002079static int wl1271_op_add_interface(struct ieee80211_hw *hw,
2080 struct ieee80211_vif *vif)
2081{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002082 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002083 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002084 int ret = 0;
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002085 u8 role_type;
Eliad Peller71125ab2010-10-28 21:46:43 +02002086 bool booted = false;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002087
Johannes Bergea086352012-01-19 09:29:58 +01002088 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
2089 IEEE80211_VIF_SUPPORTS_CQM_RSSI;
Johannes Bergc1288b12012-01-19 09:29:57 +01002090
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002091 wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
Eliad Peller045c7452011-08-28 15:23:01 +03002092 ieee80211_vif_type_p2p(vif), vif->addr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002093
2094 mutex_lock(&wl->mutex);
Eliad Pellerf750c822011-10-10 10:13:16 +02002095 ret = wl1271_ps_elp_wakeup(wl);
2096 if (ret < 0)
2097 goto out_unlock;
2098
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002099 if (wl->vif) {
Eliad Peller71125ab2010-10-28 21:46:43 +02002100 wl1271_debug(DEBUG_MAC80211,
2101 "multiple vifs are not supported yet");
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002102 ret = -EBUSY;
2103 goto out;
2104 }
2105
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002106 /*
2107 * in some very corner case HW recovery scenarios its possible to
2108 * get here before __wl1271_op_remove_interface is complete, so
2109 * opt out if that is the case.
2110 */
Eliad Peller10c8cd02011-10-10 10:13:06 +02002111 if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) ||
2112 test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)) {
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002113 ret = -EBUSY;
2114 goto out;
2115 }
2116
Eliad Peller83587502011-10-10 10:12:53 +02002117 ret = wl12xx_init_vif_data(wl, vif);
Eliad Pellere936bbe2011-10-05 11:55:56 +02002118 if (ret < 0)
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002119 goto out;
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002120
Eliad Peller252efa42011-10-05 11:56:00 +02002121 wlvif->wl = wl;
Eliad Peller536129c82011-10-05 11:55:45 +02002122 role_type = wl12xx_get_role_type(wl, wlvif);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002123 if (role_type == WL12XX_INVALID_ROLE_TYPE) {
2124 ret = -EINVAL;
2125 goto out;
2126 }
Eliad Peller1d095472011-10-10 10:12:49 +02002127
Eliad Peller784f6942011-10-05 11:55:39 +02002128 /*
Eliad Peller1d095472011-10-10 10:12:49 +02002129 * TODO: after the nvs issue will be solved, move this block
2130 * to start(), and make sure here the driver is ON.
Eliad Peller784f6942011-10-05 11:55:39 +02002131 */
Eliad Peller1d095472011-10-10 10:12:49 +02002132 if (wl->state == WL1271_STATE_OFF) {
2133 /*
2134 * we still need this in order to configure the fw
2135 * while uploading the nvs
2136 */
Luciano Coelho5e037e72011-12-23 09:32:17 +02002137 memcpy(wl->addresses[0].addr, vif->addr, ETH_ALEN);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002138
Eliad Peller1d095472011-10-10 10:12:49 +02002139 booted = wl12xx_init_fw(wl);
2140 if (!booted) {
2141 ret = -EINVAL;
2142 goto out;
Eliad Peller04e80792011-08-14 13:17:09 +03002143 }
Eliad Peller1d095472011-10-10 10:12:49 +02002144 }
Eliad Peller04e80792011-08-14 13:17:09 +03002145
Eliad Peller1d095472011-10-10 10:12:49 +02002146 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2147 wlvif->bss_type == BSS_TYPE_IBSS) {
2148 /*
2149 * The device role is a special role used for
2150 * rx and tx frames prior to association (as
2151 * the STA role can get packets only from
2152 * its associated bssid)
2153 */
Eliad Peller784f6942011-10-05 11:55:39 +02002154 ret = wl12xx_cmd_role_enable(wl, vif->addr,
Eliad Peller1d095472011-10-10 10:12:49 +02002155 WL1271_ROLE_DEVICE,
2156 &wlvif->dev_role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002157 if (ret < 0)
Eliad Peller1d095472011-10-10 10:12:49 +02002158 goto out;
Juuso Oikarinen9ccd9212009-12-11 15:41:01 +02002159 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002160
Eliad Peller1d095472011-10-10 10:12:49 +02002161 ret = wl12xx_cmd_role_enable(wl, vif->addr,
2162 role_type, &wlvif->role_id);
2163 if (ret < 0)
Eliad Peller71125ab2010-10-28 21:46:43 +02002164 goto out;
Eliad Peller1d095472011-10-10 10:12:49 +02002165
2166 ret = wl1271_init_vif_specific(wl, vif);
2167 if (ret < 0)
2168 goto out;
Eliad Peller71125ab2010-10-28 21:46:43 +02002169
2170 wl->vif = vif;
Eliad Peller876272142011-10-10 10:12:54 +02002171 list_add(&wlvif->list, &wl->wlvif_list);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002172 set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags);
Eliad Pellera4e41302011-10-11 11:49:15 +02002173
2174 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2175 wl->ap_count++;
2176 else
2177 wl->sta_count++;
Juuso Oikarineneb5b28d2009-10-13 12:47:45 +03002178out:
Eliad Pellerf750c822011-10-10 10:13:16 +02002179 wl1271_ps_elp_sleep(wl);
2180out_unlock:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002181 mutex_unlock(&wl->mutex);
2182
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002183 mutex_lock(&wl_list_mutex);
Juuso Oikarineneb887df2010-07-08 17:49:58 +03002184 if (!ret)
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002185 list_add(&wl->list, &wl_list);
Juuso Oikarinenf9f774c2011-03-21 10:43:36 +02002186 mutex_unlock(&wl_list_mutex);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03002187
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002188 return ret;
2189}
2190
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002191static void __wl1271_op_remove_interface(struct wl1271 *wl,
Eliad Peller536129c82011-10-05 11:55:45 +02002192 struct ieee80211_vif *vif,
Arik Nemtsov7dece1c2011-04-18 14:15:28 +03002193 bool reset_tx_queues)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002194{
Eliad Peller536129c82011-10-05 11:55:45 +02002195 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellere5a359f2011-10-10 10:13:15 +02002196 int i, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002197
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002198 wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002199
Eliad Peller10c8cd02011-10-10 10:13:06 +02002200 if (!test_and_clear_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2201 return;
2202
Eliad Peller2f8e81a2011-11-01 15:12:50 +02002203 wl->vif = NULL;
2204
Juuso Oikarinen13026de2011-03-29 16:43:50 +03002205 /* because of hardware recovery, we may get here twice */
2206 if (wl->state != WL1271_STATE_ON)
2207 return;
2208
Juuso Oikarinen1b72aec2010-03-18 12:26:39 +02002209 wl1271_info("down");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002210
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002211 /* enable dyn ps just in case (if left on due to fw crash etc) */
Eliad Peller536129c82011-10-05 11:55:45 +02002212 if (wlvif->bss_type == BSS_TYPE_STA_BSS)
Eliad Pellerbaf62772011-10-10 10:12:52 +02002213 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03002214
Eliad Pellerbaf62772011-10-10 10:12:52 +02002215 if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
2216 wl->scan_vif == vif) {
Luciano Coelho08688d62010-07-08 17:50:07 +03002217 wl->scan.state = WL1271_SCAN_STATE_IDLE;
Luciano Coelho4a31c112011-03-21 23:16:14 +02002218 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02002219 wl->scan_vif = NULL;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02002220 wl->scan.req = NULL;
Juuso Oikarinen76a029f2010-07-29 04:54:45 +03002221 ieee80211_scan_completed(wl->hw, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002222 }
2223
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002224 if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
2225 /* disable active roles */
2226 ret = wl1271_ps_elp_wakeup(wl);
2227 if (ret < 0)
2228 goto deinit;
2229
Eliad Pellerb890f4c2011-12-18 20:25:44 +02002230 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2231 wlvif->bss_type == BSS_TYPE_IBSS) {
2232 if (wl12xx_dev_role_started(wlvif))
2233 wl12xx_stop_dev(wl, wlvif);
2234
Eliad Peller7edebf52011-10-05 11:55:52 +02002235 ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id);
Eliad Peller04e80792011-08-14 13:17:09 +03002236 if (ret < 0)
2237 goto deinit;
2238 }
2239
Eliad Peller0603d892011-10-05 11:55:51 +02002240 ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id);
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002241 if (ret < 0)
2242 goto deinit;
2243
2244 wl1271_ps_elp_sleep(wl);
2245 }
2246deinit:
Arik Nemtsove51ae9b2011-08-14 13:17:21 +03002247 /* clear all hlids (except system_hlid) */
Eliad Pellerafaf8bd2011-10-05 11:55:57 +02002248 wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
Eliad Pellere5a359f2011-10-10 10:13:15 +02002249
2250 if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
2251 wlvif->bss_type == BSS_TYPE_IBSS) {
2252 wlvif->sta.hlid = WL12XX_INVALID_LINK_ID;
2253 wl12xx_free_rate_policy(wl, &wlvif->sta.basic_rate_idx);
2254 wl12xx_free_rate_policy(wl, &wlvif->sta.ap_rate_idx);
2255 wl12xx_free_rate_policy(wl, &wlvif->sta.p2p_rate_idx);
2256 } else {
2257 wlvif->ap.bcast_hlid = WL12XX_INVALID_LINK_ID;
2258 wlvif->ap.global_hlid = WL12XX_INVALID_LINK_ID;
2259 wl12xx_free_rate_policy(wl, &wlvif->ap.mgmt_rate_idx);
2260 wl12xx_free_rate_policy(wl, &wlvif->ap.bcast_rate_idx);
2261 for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++)
2262 wl12xx_free_rate_policy(wl,
2263 &wlvif->ap.ucast_rate_idx[i]);
2264 }
Eliad Pellerb78b47e2011-08-14 13:17:08 +03002265
Eliad Pellerd6a3cc22011-10-10 10:12:51 +02002266 wl12xx_tx_reset_wlvif(wl, wlvif);
Eliad Peller170d0e62011-10-05 11:56:06 +02002267 wl1271_free_ap_keys(wl, wlvif);
Eliad Pellere4120df2011-10-10 10:13:17 +02002268 if (wl->last_wlvif == wlvif)
2269 wl->last_wlvif = NULL;
Eliad Peller876272142011-10-10 10:12:54 +02002270 list_del(&wlvif->list);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02002271 memset(wlvif->ap.sta_hlid_map, 0, sizeof(wlvif->ap.sta_hlid_map));
Eliad Peller0603d892011-10-05 11:55:51 +02002272 wlvif->role_id = WL12XX_INVALID_ROLE_ID;
Eliad Peller7edebf52011-10-05 11:55:52 +02002273 wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID;
Luciano Coelhod6e19d132009-10-12 15:08:43 +03002274
Eliad Pellera4e41302011-10-11 11:49:15 +02002275 if (wlvif->bss_type == BSS_TYPE_AP_BSS)
2276 wl->ap_count--;
2277 else
2278 wl->sta_count--;
2279
Eliad Pellerbaf62772011-10-10 10:12:52 +02002280 mutex_unlock(&wl->mutex);
Eliad Peller9eb599e2011-10-10 10:12:59 +02002281 del_timer_sync(&wlvif->rx_streaming_timer);
2282 cancel_work_sync(&wlvif->rx_streaming_enable_work);
2283 cancel_work_sync(&wlvif->rx_streaming_disable_work);
Eliad Pellerbaf62772011-10-10 10:12:52 +02002284 cancel_delayed_work_sync(&wlvif->pspoll_work);
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03002285
Eliad Pellerbaf62772011-10-10 10:12:52 +02002286 mutex_lock(&wl->mutex);
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002287}
Juuso Oikarinenbd9dc492010-04-09 11:07:26 +03002288
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002289static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
2290 struct ieee80211_vif *vif)
2291{
2292 struct wl1271 *wl = hw->priv;
Eliad Peller10c8cd02011-10-10 10:13:06 +02002293 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002294 struct wl12xx_vif *iter;
Juuso Oikarinen52a2a372010-09-21 06:23:30 +02002295
2296 mutex_lock(&wl->mutex);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002297
2298 if (wl->state == WL1271_STATE_OFF ||
2299 !test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
2300 goto out;
2301
Juuso Oikarinen67353292010-11-18 15:19:02 +02002302 /*
2303 * wl->vif can be null here if someone shuts down the interface
2304 * just when hardware recovery has been started.
2305 */
Eliad Peller6e8cd332011-10-10 10:13:13 +02002306 wl12xx_for_each_wlvif(wl, iter) {
2307 if (iter != wlvif)
2308 continue;
2309
Eliad Peller536129c82011-10-05 11:55:45 +02002310 __wl1271_op_remove_interface(wl, vif, true);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002311 break;
Juuso Oikarinen67353292010-11-18 15:19:02 +02002312 }
Eliad Peller6e8cd332011-10-10 10:13:13 +02002313 WARN_ON(iter != wlvif);
Eliad Peller10c8cd02011-10-10 10:13:06 +02002314out:
Juuso Oikarinen67353292010-11-18 15:19:02 +02002315 mutex_unlock(&wl->mutex);
Juuso Oikarinen52b0e7a2010-09-21 06:23:31 +02002316 cancel_work_sync(&wl->recovery_work);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002317}
2318
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02002319static int wl12xx_op_change_interface(struct ieee80211_hw *hw,
2320 struct ieee80211_vif *vif,
2321 enum nl80211_iftype new_type, bool p2p)
2322{
2323 wl1271_op_remove_interface(hw, vif);
2324
2325 vif->type = ieee80211_iftype_p2p(new_type, p2p);
2326 vif->p2p = p2p;
2327 return wl1271_op_add_interface(hw, vif);
2328}
2329
Eliad Peller87fbcb02011-10-05 11:55:41 +02002330static int wl1271_join(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2331 bool set_assoc)
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002332{
2333 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002334 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002335
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002336 /*
2337 * One of the side effects of the JOIN command is that is clears
2338 * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
2339 * to a WPA/WPA2 access point will therefore kill the data-path.
Ohad Ben-Cohen8bf69aa2011-03-30 19:18:31 +02002340 * Currently the only valid scenario for JOIN during association
2341 * is on roaming, in which case we will also be given new keys.
2342 * Keep the below message for now, unless it starts bothering
2343 * users who really like to roam a lot :)
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002344 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002345 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002346 wl1271_info("JOIN while associated.");
2347
2348 if (set_assoc)
Eliad Pellerba8447f62011-10-10 10:13:00 +02002349 set_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags);
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002350
Eliad Peller227e81e2011-08-14 13:17:26 +03002351 if (is_ibss)
Eliad Peller87fbcb02011-10-05 11:55:41 +02002352 ret = wl12xx_cmd_role_start_ibss(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03002353 else
Eliad Peller87fbcb02011-10-05 11:55:41 +02002354 ret = wl12xx_cmd_role_start_sta(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002355 if (ret < 0)
2356 goto out;
2357
Eliad Pellerba8447f62011-10-10 10:13:00 +02002358 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002359 goto out;
2360
2361 /*
2362 * The join command disable the keep-alive mode, shut down its process,
2363 * and also clear the template config, so we need to reset it all after
2364 * the join. The acx_aid starts the keep-alive process, and the order
2365 * of the commands below is relevant.
2366 */
Eliad Peller0603d892011-10-05 11:55:51 +02002367 ret = wl1271_acx_keep_alive_mode(wl, wlvif, true);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002368 if (ret < 0)
2369 goto out;
2370
Eliad Peller0603d892011-10-05 11:55:51 +02002371 ret = wl1271_acx_aid(wl, wlvif, wlvif->aid);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002372 if (ret < 0)
2373 goto out;
2374
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002375 ret = wl12xx_cmd_build_klv_null_data(wl, wlvif);
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002376 if (ret < 0)
2377 goto out;
2378
Eliad Peller0603d892011-10-05 11:55:51 +02002379 ret = wl1271_acx_keep_alive_config(wl, wlvif,
2380 CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen82429d32010-04-28 09:50:01 +03002381 ACX_KEEP_ALIVE_TPL_VALID);
2382 if (ret < 0)
2383 goto out;
2384
2385out:
2386 return ret;
2387}
2388
Eliad Peller0603d892011-10-05 11:55:51 +02002389static int wl1271_unjoin(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002390{
2391 int ret;
2392
Eliad Peller52630c52011-10-10 10:13:08 +02002393 if (test_and_clear_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02002394 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
2395
Shahar Levi6d158ff2011-09-08 13:01:33 +03002396 wl12xx_cmd_stop_channel_switch(wl);
Eliad Peller6e8cd332011-10-10 10:13:13 +02002397 ieee80211_chswitch_done(vif, false);
Shahar Levi6d158ff2011-09-08 13:01:33 +03002398 }
2399
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002400 /* to stop listening to a channel, we disconnect */
Eliad Peller0603d892011-10-05 11:55:51 +02002401 ret = wl12xx_cmd_role_stop_sta(wl, wlvif);
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002402 if (ret < 0)
2403 goto out;
2404
Oz Krakowskib992c682011-06-26 10:36:02 +03002405 /* reset TX security counters on a clean disconnect */
Eliad Peller48e93e42011-10-10 10:12:58 +02002406 wlvif->tx_security_last_seq_lsb = 0;
2407 wlvif->tx_security_seq = 0;
Oz Krakowskib992c682011-06-26 10:36:02 +03002408
Luciano Coelhoc7f43e42009-12-11 15:40:44 +02002409out:
2410 return ret;
2411}
2412
Eliad Peller87fbcb02011-10-05 11:55:41 +02002413static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002414{
Eliad Peller1b92f152011-10-10 10:13:09 +02002415 wlvif->basic_rate_set = wlvif->bitrate_masks[wlvif->band];
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002416 wlvif->rate_set = wlvif->basic_rate_set;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002417}
2418
Eliad Peller87fbcb02011-10-05 11:55:41 +02002419static int wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2420 bool idle)
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002421{
2422 int ret;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002423 bool cur_idle = !test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
2424
2425 if (idle == cur_idle)
2426 return 0;
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002427
2428 if (idle) {
Eliad Peller251c1772011-08-14 13:17:17 +03002429 /* no need to croc if we weren't busy (e.g. during boot) */
Eliad Peller92e712d2011-12-18 20:25:43 +02002430 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002431 ret = wl12xx_stop_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002432 if (ret < 0)
2433 goto out;
2434 }
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002435 wlvif->rate_set =
2436 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2437 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002438 if (ret < 0)
2439 goto out;
2440 ret = wl1271_acx_keep_alive_config(
Eliad Peller0603d892011-10-05 11:55:51 +02002441 wl, wlvif, CMD_TEMPL_KLV_IDX_NULL_DATA,
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002442 ACX_KEEP_ALIVE_TPL_INVALID);
2443 if (ret < 0)
2444 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002445 clear_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002446 } else {
Luciano Coelho33c2c062011-05-10 14:46:02 +03002447 /* The current firmware only supports sched_scan in idle */
2448 if (wl->sched_scanning) {
2449 wl1271_scan_sched_scan_stop(wl);
2450 ieee80211_sched_scan_stopped(wl->hw);
2451 }
2452
Eliad Peller679a6732011-10-11 11:55:44 +02002453 ret = wl12xx_start_dev(wl, wlvif);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002454 if (ret < 0)
2455 goto out;
Eliad Pellera0c7b782011-12-18 20:25:41 +02002456 set_bit(WLVIF_FLAG_IN_USE, &wlvif->flags);
Juuso Oikarinen0d58cbf2010-05-24 11:18:16 +03002457 }
2458
2459out:
2460 return ret;
2461}
2462
Eliad Peller9f259c42011-10-10 10:13:12 +02002463static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2464 struct ieee80211_conf *conf, u32 changed)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002465{
Eliad Peller9f259c42011-10-10 10:13:12 +02002466 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
2467 int channel, ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002468
2469 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2470
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002471 /* if the channel changes while joined, join again */
Juuso Oikarinen69e54342010-05-07 11:39:00 +03002472 if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
Eliad Peller1b92f152011-10-10 10:13:09 +02002473 ((wlvif->band != conf->channel->band) ||
Eliad Peller61f845f2011-10-10 10:13:10 +02002474 (wlvif->channel != channel))) {
Eliad Pellerc6930b02011-09-15 13:00:01 +03002475 /* send all pending packets */
Eliad Pellera32d0cd2011-10-10 10:12:55 +02002476 wl1271_tx_work_locked(wl);
Eliad Peller61f845f2011-10-10 10:13:10 +02002477 wlvif->band = conf->channel->band;
2478 wlvif->channel = channel;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002479
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002480 if (!is_ap) {
2481 /*
2482 * FIXME: the mac80211 should really provide a fixed
2483 * rate to use here. for now, just use the smallest
2484 * possible rate for the band as a fixed rate for
2485 * association frames and other control messages.
2486 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002487 if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
Eliad Peller87fbcb02011-10-05 11:55:41 +02002488 wl1271_set_band_rate(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002489
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002490 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02002491 wl1271_tx_min_rate_get(wl,
2492 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02002493 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002494 if (ret < 0)
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002495 wl1271_warning("rate policy for channel "
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002496 "failed %d", ret);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002497
Eliad Pellerba8447f62011-10-10 10:13:00 +02002498 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED,
2499 &wlvif->flags)) {
Eliad Peller92e712d2011-12-18 20:25:43 +02002500 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller251c1772011-08-14 13:17:17 +03002501 /* roaming */
Eliad Peller7edebf52011-10-05 11:55:52 +02002502 ret = wl12xx_croc(wl,
2503 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03002504 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002505 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002506 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02002507 ret = wl1271_join(wl, wlvif, false);
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002508 if (ret < 0)
2509 wl1271_warning("cmd join on channel "
2510 "failed %d", ret);
Eliad Peller251c1772011-08-14 13:17:17 +03002511 } else {
2512 /*
2513 * change the ROC channel. do it only if we are
2514 * not idle. otherwise, CROC will be called
2515 * anyway.
2516 */
Eliad Peller92e712d2011-12-18 20:25:43 +02002517 if (wl12xx_dev_role_started(wlvif) &&
Eliad Peller251c1772011-08-14 13:17:17 +03002518 !(conf->flags & IEEE80211_CONF_IDLE)) {
Eliad Peller679a6732011-10-11 11:55:44 +02002519 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002520 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002521 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002522
Eliad Peller679a6732011-10-11 11:55:44 +02002523 ret = wl12xx_start_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03002524 if (ret < 0)
Eliad Peller679a6732011-10-11 11:55:44 +02002525 return ret;
Eliad Peller251c1772011-08-14 13:17:17 +03002526 }
Arik Nemtsovbee0ffe2010-10-16 19:17:02 +02002527 }
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03002528 }
2529 }
2530
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002531 /*
2532 * if mac80211 changes the PSM mode, make sure the mode is not
2533 * incorrectly changed after the pspoll failure active window.
2534 */
2535 if (changed & IEEE80211_CONF_CHANGE_PS)
Eliad Peller836d6602011-10-10 10:13:07 +02002536 clear_bit(WLVIF_FLAG_PSPOLL_FAILURE, &wlvif->flags);
Juuso Oikarinen90494a92010-07-08 17:50:00 +03002537
Juuso Oikarinen71449f82009-12-11 15:41:07 +02002538 if (conf->flags & IEEE80211_CONF_PS &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002539 !test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
2540 set_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002541
2542 /*
2543 * We enter PSM only if we're already associated.
2544 * If we're not, we'll enter it when joining an SSID,
2545 * through the bss_info_changed() hook.
2546 */
Eliad Pellerba8447f62011-10-10 10:13:00 +02002547 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002548 wl1271_debug(DEBUG_PSM, "psm enabled");
Eliad Peller0603d892011-10-05 11:55:51 +02002549 ret = wl1271_ps_set_mode(wl, wlvif,
2550 STATION_POWER_SAVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002551 wlvif->basic_rate, true);
Juuso Oikarinenaf5e0842009-12-11 15:41:00 +02002552 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002553 } else if (!(conf->flags & IEEE80211_CONF_PS) &&
Eliad Pellerc29bb002011-10-10 10:13:03 +02002554 test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags)) {
Juuso Oikarinen18f8d462010-02-22 08:38:34 +02002555 wl1271_debug(DEBUG_PSM, "psm disabled");
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002556
Eliad Pellerc29bb002011-10-10 10:13:03 +02002557 clear_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002558
Eliad Pellerc29bb002011-10-10 10:13:03 +02002559 if (test_bit(WLVIF_FLAG_PSM, &wlvif->flags))
Eliad Peller0603d892011-10-05 11:55:51 +02002560 ret = wl1271_ps_set_mode(wl, wlvif,
2561 STATION_ACTIVE_MODE,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02002562 wlvif->basic_rate, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002563 }
2564
Eliad Peller6bd65022011-10-10 10:13:11 +02002565 if (conf->power_level != wlvif->power_level) {
Eliad Peller0603d892011-10-05 11:55:51 +02002566 ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002567 if (ret < 0)
Eliad Peller9f259c42011-10-10 10:13:12 +02002568 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002569
Eliad Peller6bd65022011-10-10 10:13:11 +02002570 wlvif->power_level = conf->power_level;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002571 }
2572
Eliad Peller9f259c42011-10-10 10:13:12 +02002573 return 0;
2574}
2575
2576static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
2577{
2578 struct wl1271 *wl = hw->priv;
2579 struct wl12xx_vif *wlvif;
2580 struct ieee80211_conf *conf = &hw->conf;
2581 int channel, ret = 0;
2582
2583 channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
2584
2585 wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s"
2586 " changed 0x%x",
2587 channel,
2588 conf->flags & IEEE80211_CONF_PS ? "on" : "off",
2589 conf->power_level,
2590 conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use",
2591 changed);
2592
2593 /*
2594 * mac80211 will go to idle nearly immediately after transmitting some
2595 * frames, such as the deauth. To make sure those frames reach the air,
2596 * wait here until the TX queue is fully flushed.
2597 */
2598 if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
2599 (conf->flags & IEEE80211_CONF_IDLE))
2600 wl1271_tx_flush(wl);
2601
2602 mutex_lock(&wl->mutex);
2603
2604 /* we support configuring the channel and band even while off */
2605 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
2606 wl->band = conf->channel->band;
2607 wl->channel = channel;
2608 }
2609
2610 if (changed & IEEE80211_CONF_CHANGE_POWER)
2611 wl->power_level = conf->power_level;
2612
2613 if (unlikely(wl->state == WL1271_STATE_OFF))
2614 goto out;
2615
2616 ret = wl1271_ps_elp_wakeup(wl);
2617 if (ret < 0)
2618 goto out;
2619
2620 /* configure each interface */
2621 wl12xx_for_each_wlvif(wl, wlvif) {
2622 ret = wl12xx_config_vif(wl, wlvif, conf, changed);
2623 if (ret < 0)
2624 goto out_sleep;
2625 }
2626
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002627out_sleep:
2628 wl1271_ps_elp_sleep(wl);
2629
2630out:
2631 mutex_unlock(&wl->mutex);
2632
2633 return ret;
2634}
2635
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002636struct wl1271_filter_params {
2637 bool enabled;
2638 int mc_list_length;
2639 u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
2640};
2641
Jiri Pirko22bedad32010-04-01 21:22:57 +00002642static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
2643 struct netdev_hw_addr_list *mc_list)
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002644{
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002645 struct wl1271_filter_params *fp;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002646 struct netdev_hw_addr *ha;
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002647 struct wl1271 *wl = hw->priv;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002648
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002649 if (unlikely(wl->state == WL1271_STATE_OFF))
2650 return 0;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002651
Juuso Oikarinen74441132009-10-13 12:47:53 +03002652 fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002653 if (!fp) {
2654 wl1271_error("Out of memory setting filters.");
2655 return 0;
2656 }
2657
2658 /* update multicast filtering parameters */
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002659 fp->mc_list_length = 0;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002660 if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
2661 fp->enabled = false;
2662 } else {
2663 fp->enabled = true;
2664 netdev_hw_addr_list_for_each(ha, mc_list) {
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002665 memcpy(fp->mc_list[fp->mc_list_length],
Jiri Pirko22bedad32010-04-01 21:22:57 +00002666 ha->addr, ETH_ALEN);
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002667 fp->mc_list_length++;
Jiri Pirko22bedad32010-04-01 21:22:57 +00002668 }
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002669 }
2670
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002671 return (u64)(unsigned long)fp;
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002672}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002673
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002674#define WL1271_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
2675 FIF_ALLMULTI | \
2676 FIF_FCSFAIL | \
2677 FIF_BCN_PRBRESP_PROMISC | \
2678 FIF_CONTROL | \
2679 FIF_OTHER_BSS)
2680
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002681static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
2682 unsigned int changed,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03002683 unsigned int *total, u64 multicast)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002684{
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002685 struct wl1271_filter_params *fp = (void *)(unsigned long)multicast;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002686 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02002687 struct wl12xx_vif *wlvif;
Eliad Peller536129c82011-10-05 11:55:45 +02002688
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002689 int ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002690
Arik Nemtsov7d057862010-10-16 19:25:35 +02002691 wl1271_debug(DEBUG_MAC80211, "mac80211 configure filter changed %x"
2692 " total %x", changed, *total);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002693
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002694 mutex_lock(&wl->mutex);
2695
Saravanan Dhanabal2c10bb92010-04-09 11:07:27 +03002696 *total &= WL1271_SUPPORTED_FILTERS;
2697 changed &= WL1271_SUPPORTED_FILTERS;
2698
2699 if (unlikely(wl->state == WL1271_STATE_OFF))
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002700 goto out;
2701
Ido Yariva6208652011-03-01 15:14:41 +02002702 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002703 if (ret < 0)
2704 goto out;
2705
Eliad Peller6e8cd332011-10-10 10:13:13 +02002706 wl12xx_for_each_wlvif(wl, wlvif) {
2707 if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
2708 if (*total & FIF_ALLMULTI)
2709 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2710 false,
2711 NULL, 0);
2712 else if (fp)
2713 ret = wl1271_acx_group_address_tbl(wl, wlvif,
2714 fp->enabled,
2715 fp->mc_list,
2716 fp->mc_list_length);
2717 if (ret < 0)
2718 goto out_sleep;
2719 }
Arik Nemtsov7d057862010-10-16 19:25:35 +02002720 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002721
Eliad Peller08c1d1c2011-08-14 13:17:04 +03002722 /*
2723 * the fw doesn't provide an api to configure the filters. instead,
2724 * the filters configuration is based on the active roles / ROC
2725 * state.
2726 */
Juuso Oikarinenb54853f2009-10-13 12:47:59 +03002727
2728out_sleep:
2729 wl1271_ps_elp_sleep(wl);
2730
2731out:
2732 mutex_unlock(&wl->mutex);
Juuso Oikarinen14b228a2010-03-18 12:26:43 +02002733 kfree(fp);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002734}
2735
Eliad Peller170d0e62011-10-05 11:56:06 +02002736static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2737 u8 id, u8 key_type, u8 key_size,
2738 const u8 *key, u8 hlid, u32 tx_seq_32,
2739 u16 tx_seq_16)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002740{
2741 struct wl1271_ap_key *ap_key;
2742 int i;
2743
2744 wl1271_debug(DEBUG_CRYPT, "record ap key id %d", (int)id);
2745
2746 if (key_size > MAX_KEY_SIZE)
2747 return -EINVAL;
2748
2749 /*
2750 * Find next free entry in ap_keys. Also check we are not replacing
2751 * an existing key.
2752 */
2753 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002754 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002755 break;
2756
Eliad Peller170d0e62011-10-05 11:56:06 +02002757 if (wlvif->ap.recorded_keys[i]->id == id) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002758 wl1271_warning("trying to record key replacement");
2759 return -EINVAL;
2760 }
2761 }
2762
2763 if (i == MAX_NUM_KEYS)
2764 return -EBUSY;
2765
2766 ap_key = kzalloc(sizeof(*ap_key), GFP_KERNEL);
2767 if (!ap_key)
2768 return -ENOMEM;
2769
2770 ap_key->id = id;
2771 ap_key->key_type = key_type;
2772 ap_key->key_size = key_size;
2773 memcpy(ap_key->key, key, key_size);
2774 ap_key->hlid = hlid;
2775 ap_key->tx_seq_32 = tx_seq_32;
2776 ap_key->tx_seq_16 = tx_seq_16;
2777
Eliad Peller170d0e62011-10-05 11:56:06 +02002778 wlvif->ap.recorded_keys[i] = ap_key;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002779 return 0;
2780}
2781
Eliad Peller170d0e62011-10-05 11:56:06 +02002782static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002783{
2784 int i;
2785
2786 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller170d0e62011-10-05 11:56:06 +02002787 kfree(wlvif->ap.recorded_keys[i]);
2788 wlvif->ap.recorded_keys[i] = NULL;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002789 }
2790}
2791
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002792static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002793{
2794 int i, ret = 0;
2795 struct wl1271_ap_key *key;
2796 bool wep_key_added = false;
2797
2798 for (i = 0; i < MAX_NUM_KEYS; i++) {
Eliad Peller7f97b482011-08-14 13:17:30 +03002799 u8 hlid;
Eliad Peller170d0e62011-10-05 11:56:06 +02002800 if (wlvif->ap.recorded_keys[i] == NULL)
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002801 break;
2802
Eliad Peller170d0e62011-10-05 11:56:06 +02002803 key = wlvif->ap.recorded_keys[i];
Eliad Peller7f97b482011-08-14 13:17:30 +03002804 hlid = key->hlid;
2805 if (hlid == WL12XX_INVALID_LINK_ID)
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002806 hlid = wlvif->ap.bcast_hlid;
Eliad Peller7f97b482011-08-14 13:17:30 +03002807
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002808 ret = wl1271_cmd_set_ap_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002809 key->id, key->key_type,
2810 key->key_size, key->key,
Eliad Peller7f97b482011-08-14 13:17:30 +03002811 hlid, key->tx_seq_32,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002812 key->tx_seq_16);
2813 if (ret < 0)
2814 goto out;
2815
2816 if (key->key_type == KEY_WEP)
2817 wep_key_added = true;
2818 }
2819
2820 if (wep_key_added) {
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002821 ret = wl12xx_cmd_set_default_wep_key(wl, wlvif->default_key,
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002822 wlvif->ap.bcast_hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002823 if (ret < 0)
2824 goto out;
2825 }
2826
2827out:
Eliad Peller170d0e62011-10-05 11:56:06 +02002828 wl1271_free_ap_keys(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002829 return ret;
2830}
2831
Eliad Peller536129c82011-10-05 11:55:45 +02002832static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif,
2833 u16 action, u8 id, u8 key_type,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002834 u8 key_size, const u8 *key, u32 tx_seq_32,
2835 u16 tx_seq_16, struct ieee80211_sta *sta)
2836{
2837 int ret;
Eliad Peller536129c82011-10-05 11:55:45 +02002838 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002839
2840 if (is_ap) {
2841 struct wl1271_station *wl_sta;
2842 u8 hlid;
2843
2844 if (sta) {
2845 wl_sta = (struct wl1271_station *)sta->drv_priv;
2846 hlid = wl_sta->hlid;
2847 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002848 hlid = wlvif->ap.bcast_hlid;
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002849 }
2850
Eliad Peller53d40d02011-10-10 10:13:02 +02002851 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002852 /*
2853 * We do not support removing keys after AP shutdown.
2854 * Pretend we do to make mac80211 happy.
2855 */
2856 if (action != KEY_ADD_OR_REPLACE)
2857 return 0;
2858
Eliad Peller170d0e62011-10-05 11:56:06 +02002859 ret = wl1271_record_ap_key(wl, wlvif, id,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002860 key_type, key_size,
2861 key, hlid, tx_seq_32,
2862 tx_seq_16);
2863 } else {
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002864 ret = wl1271_cmd_set_ap_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002865 id, key_type, key_size,
2866 key, hlid, tx_seq_32,
2867 tx_seq_16);
2868 }
2869
2870 if (ret < 0)
2871 return ret;
2872 } else {
2873 const u8 *addr;
2874 static const u8 bcast_addr[ETH_ALEN] = {
2875 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
2876 };
2877
Guy Eilame9eb8cb2011-08-16 19:49:12 +03002878 /*
2879 * A STA set to GEM cipher requires 2 tx spare blocks.
2880 * Return to default value when GEM cipher key is removed
2881 */
2882 if (key_type == KEY_GEM) {
2883 if (action == KEY_ADD_OR_REPLACE)
2884 wl->tx_spare_blocks = 2;
2885 else if (action == KEY_REMOVE)
2886 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
2887 }
2888
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002889 addr = sta ? sta->addr : bcast_addr;
2890
2891 if (is_zero_ether_addr(addr)) {
2892 /* We dont support TX only encryption */
2893 return -EOPNOTSUPP;
2894 }
2895
2896 /* The wl1271 does not allow to remove unicast keys - they
2897 will be cleared automatically on next CMD_JOIN. Ignore the
2898 request silently, as we dont want the mac80211 to emit
2899 an error message. */
2900 if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr))
2901 return 0;
2902
Eliad Peller010d3d32011-08-14 13:17:31 +03002903 /* don't remove key if hlid was already deleted */
2904 if (action == KEY_REMOVE &&
Eliad Peller154da672011-10-05 11:55:53 +02002905 wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)
Eliad Peller010d3d32011-08-14 13:17:31 +03002906 return 0;
2907
Eliad Pellera8ab39a2011-10-05 11:55:54 +02002908 ret = wl1271_cmd_set_sta_key(wl, wlvif, action,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002909 id, key_type, key_size,
2910 key, addr, tx_seq_32,
2911 tx_seq_16);
2912 if (ret < 0)
2913 return ret;
2914
2915 /* the default WEP key needs to be configured at least once */
2916 if (key_type == KEY_WEP) {
Eliad Pellerc690ec82011-08-14 13:17:07 +03002917 ret = wl12xx_cmd_set_default_wep_key(wl,
Eliad Pellerf75c753f2011-10-05 11:55:59 +02002918 wlvif->default_key,
2919 wlvif->sta.hlid);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002920 if (ret < 0)
2921 return ret;
2922 }
2923 }
2924
2925 return 0;
2926}
2927
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002928static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
2929 struct ieee80211_vif *vif,
2930 struct ieee80211_sta *sta,
2931 struct ieee80211_key_conf *key_conf)
2932{
2933 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02002934 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002935 int ret;
Juuso Oikarinenac4e4ce2009-10-08 21:56:19 +03002936 u32 tx_seq_32 = 0;
2937 u16 tx_seq_16 = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002938 u8 key_type;
2939
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002940 wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
2941
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002942 wl1271_debug(DEBUG_CRYPT, "CMD: 0x%x sta: %p", cmd, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002943 wl1271_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
Johannes Berg97359d12010-08-10 09:46:38 +02002944 key_conf->cipher, key_conf->keyidx,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002945 key_conf->keylen, key_conf->flags);
2946 wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
2947
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002948 mutex_lock(&wl->mutex);
2949
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02002950 if (unlikely(wl->state == WL1271_STATE_OFF)) {
2951 ret = -EAGAIN;
2952 goto out_unlock;
2953 }
2954
Ido Yariva6208652011-03-01 15:14:41 +02002955 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002956 if (ret < 0)
2957 goto out_unlock;
2958
Johannes Berg97359d12010-08-10 09:46:38 +02002959 switch (key_conf->cipher) {
2960 case WLAN_CIPHER_SUITE_WEP40:
2961 case WLAN_CIPHER_SUITE_WEP104:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002962 key_type = KEY_WEP;
2963
2964 key_conf->hw_key_idx = key_conf->keyidx;
2965 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002966 case WLAN_CIPHER_SUITE_TKIP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002967 key_type = KEY_TKIP;
2968
2969 key_conf->hw_key_idx = key_conf->keyidx;
Eliad Peller48e93e42011-10-10 10:12:58 +02002970 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2971 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002972 break;
Johannes Berg97359d12010-08-10 09:46:38 +02002973 case WLAN_CIPHER_SUITE_CCMP:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002974 key_type = KEY_AES;
2975
Arik Nemtsov12d4b972011-10-23 08:21:54 +02002976 key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
Eliad Peller48e93e42011-10-10 10:12:58 +02002977 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2978 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002979 break;
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002980 case WL1271_CIPHER_SUITE_GEM:
2981 key_type = KEY_GEM;
Eliad Peller48e93e42011-10-10 10:12:58 +02002982 tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
2983 tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
Juuso Oikarinen7a557242010-09-27 12:42:07 +02002984 break;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002985 default:
Johannes Berg97359d12010-08-10 09:46:38 +02002986 wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002987
2988 ret = -EOPNOTSUPP;
2989 goto out_sleep;
2990 }
2991
2992 switch (cmd) {
2993 case SET_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02002994 ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02002995 key_conf->keyidx, key_type,
2996 key_conf->keylen, key_conf->key,
2997 tx_seq_32, tx_seq_16, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03002998 if (ret < 0) {
2999 wl1271_error("Could not add or replace key");
3000 goto out_sleep;
3001 }
3002 break;
3003
3004 case DISABLE_KEY:
Eliad Peller536129c82011-10-05 11:55:45 +02003005 ret = wl1271_set_key(wl, wlvif, KEY_REMOVE,
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003006 key_conf->keyidx, key_type,
3007 key_conf->keylen, key_conf->key,
3008 0, 0, sta);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003009 if (ret < 0) {
3010 wl1271_error("Could not remove key");
3011 goto out_sleep;
3012 }
3013 break;
3014
3015 default:
3016 wl1271_error("Unsupported key cmd 0x%x", cmd);
3017 ret = -EOPNOTSUPP;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003018 break;
3019 }
3020
3021out_sleep:
3022 wl1271_ps_elp_sleep(wl);
3023
3024out_unlock:
3025 mutex_unlock(&wl->mutex);
3026
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003027 return ret;
3028}
3029
3030static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
Johannes Berga060bbf2010-04-27 11:59:34 +02003031 struct ieee80211_vif *vif,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003032 struct cfg80211_scan_request *req)
3033{
3034 struct wl1271 *wl = hw->priv;
Eliad Peller7edebf52011-10-05 11:55:52 +02003035 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3036
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003037 int ret;
3038 u8 *ssid = NULL;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003039 size_t len = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003040
3041 wl1271_debug(DEBUG_MAC80211, "mac80211 hw scan");
3042
3043 if (req->n_ssids) {
3044 ssid = req->ssids[0].ssid;
Teemu Paasikiviabb0b3b2009-10-13 12:47:50 +03003045 len = req->ssids[0].ssid_len;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003046 }
3047
3048 mutex_lock(&wl->mutex);
3049
Juuso Oikarinenb739a422010-10-26 13:24:38 +02003050 if (wl->state == WL1271_STATE_OFF) {
3051 /*
3052 * We cannot return -EBUSY here because cfg80211 will expect
3053 * a call to ieee80211_scan_completed if we do - in this case
3054 * there won't be any call.
3055 */
3056 ret = -EAGAIN;
3057 goto out;
3058 }
3059
Ido Yariva6208652011-03-01 15:14:41 +02003060 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003061 if (ret < 0)
3062 goto out;
3063
Eliad Peller92e712d2011-12-18 20:25:43 +02003064 if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) &&
3065 test_bit(wlvif->role_id, wl->roc_map)) {
3066 /* don't allow scanning right now */
3067 ret = -EBUSY;
3068 goto out_sleep;
Eliad Peller251c1772011-08-14 13:17:17 +03003069 }
3070
Eliad Peller92e712d2011-12-18 20:25:43 +02003071 /* cancel ROC before scanning */
3072 if (wl12xx_dev_role_started(wlvif))
3073 wl12xx_stop_dev(wl, wlvif);
3074
Eliad Peller784f6942011-10-05 11:55:39 +02003075 ret = wl1271_scan(hw->priv, vif, ssid, len, req);
Eliad Peller251c1772011-08-14 13:17:17 +03003076out_sleep:
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003077 wl1271_ps_elp_sleep(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003078out:
3079 mutex_unlock(&wl->mutex);
3080
3081 return ret;
3082}
3083
Eliad Peller73ecce32011-06-27 13:06:45 +03003084static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
3085 struct ieee80211_vif *vif)
3086{
3087 struct wl1271 *wl = hw->priv;
3088 int ret;
3089
3090 wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
3091
3092 mutex_lock(&wl->mutex);
3093
3094 if (wl->state == WL1271_STATE_OFF)
3095 goto out;
3096
3097 if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
3098 goto out;
3099
3100 ret = wl1271_ps_elp_wakeup(wl);
3101 if (ret < 0)
3102 goto out;
3103
3104 if (wl->scan.state != WL1271_SCAN_STATE_DONE) {
3105 ret = wl1271_scan_stop(wl);
3106 if (ret < 0)
3107 goto out_sleep;
3108 }
3109 wl->scan.state = WL1271_SCAN_STATE_IDLE;
3110 memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
Eliad Peller784f6942011-10-05 11:55:39 +02003111 wl->scan_vif = NULL;
Eliad Peller73ecce32011-06-27 13:06:45 +03003112 wl->scan.req = NULL;
3113 ieee80211_scan_completed(wl->hw, true);
3114
3115out_sleep:
3116 wl1271_ps_elp_sleep(wl);
3117out:
3118 mutex_unlock(&wl->mutex);
3119
3120 cancel_delayed_work_sync(&wl->scan_complete_work);
3121}
3122
Luciano Coelho33c2c062011-05-10 14:46:02 +03003123static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
3124 struct ieee80211_vif *vif,
3125 struct cfg80211_sched_scan_request *req,
3126 struct ieee80211_sched_scan_ies *ies)
3127{
3128 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003129 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003130 int ret;
3131
3132 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
3133
3134 mutex_lock(&wl->mutex);
3135
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003136 if (wl->state == WL1271_STATE_OFF) {
3137 ret = -EAGAIN;
3138 goto out;
3139 }
3140
Luciano Coelho33c2c062011-05-10 14:46:02 +03003141 ret = wl1271_ps_elp_wakeup(wl);
3142 if (ret < 0)
3143 goto out;
3144
Eliad Peller536129c82011-10-05 11:55:45 +02003145 ret = wl1271_scan_sched_scan_config(wl, wlvif, req, ies);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003146 if (ret < 0)
3147 goto out_sleep;
3148
Eliad Peller536129c82011-10-05 11:55:45 +02003149 ret = wl1271_scan_sched_scan_start(wl, wlvif);
Luciano Coelho33c2c062011-05-10 14:46:02 +03003150 if (ret < 0)
3151 goto out_sleep;
3152
3153 wl->sched_scanning = true;
3154
3155out_sleep:
3156 wl1271_ps_elp_sleep(wl);
3157out:
3158 mutex_unlock(&wl->mutex);
3159 return ret;
3160}
3161
3162static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
3163 struct ieee80211_vif *vif)
3164{
3165 struct wl1271 *wl = hw->priv;
3166 int ret;
3167
3168 wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
3169
3170 mutex_lock(&wl->mutex);
3171
Pontus Fuchs9e0dc892012-01-11 14:22:42 +01003172 if (wl->state == WL1271_STATE_OFF)
3173 goto out;
3174
Luciano Coelho33c2c062011-05-10 14:46:02 +03003175 ret = wl1271_ps_elp_wakeup(wl);
3176 if (ret < 0)
3177 goto out;
3178
3179 wl1271_scan_sched_scan_stop(wl);
3180
3181 wl1271_ps_elp_sleep(wl);
3182out:
3183 mutex_unlock(&wl->mutex);
3184}
3185
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003186static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
3187{
3188 struct wl1271 *wl = hw->priv;
3189 int ret = 0;
3190
3191 mutex_lock(&wl->mutex);
3192
3193 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3194 ret = -EAGAIN;
3195 goto out;
3196 }
3197
Ido Yariva6208652011-03-01 15:14:41 +02003198 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003199 if (ret < 0)
3200 goto out;
3201
Arik Nemtsov5f704d12011-04-18 14:15:21 +03003202 ret = wl1271_acx_frag_threshold(wl, value);
Arik Nemtsov68d069c2010-11-08 10:51:07 +01003203 if (ret < 0)
3204 wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
3205
3206 wl1271_ps_elp_sleep(wl);
3207
3208out:
3209 mutex_unlock(&wl->mutex);
3210
3211 return ret;
3212}
3213
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003214static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
3215{
3216 struct wl1271 *wl = hw->priv;
Eliad Peller6e8cd332011-10-10 10:13:13 +02003217 struct wl12xx_vif *wlvif;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003218 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003219
3220 mutex_lock(&wl->mutex);
3221
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003222 if (unlikely(wl->state == WL1271_STATE_OFF)) {
3223 ret = -EAGAIN;
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003224 goto out;
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02003225 }
Saravanan Dhanabalaecb0562010-04-09 11:07:28 +03003226
Ido Yariva6208652011-03-01 15:14:41 +02003227 ret = wl1271_ps_elp_wakeup(wl);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003228 if (ret < 0)
3229 goto out;
3230
Eliad Peller6e8cd332011-10-10 10:13:13 +02003231 wl12xx_for_each_wlvif(wl, wlvif) {
3232 ret = wl1271_acx_rts_threshold(wl, wlvif, value);
3233 if (ret < 0)
3234 wl1271_warning("set rts threshold failed: %d", ret);
3235 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003236 wl1271_ps_elp_sleep(wl);
3237
3238out:
3239 mutex_unlock(&wl->mutex);
3240
3241 return ret;
3242}
3243
Eliad Peller1fe9f162011-10-05 11:55:48 +02003244static int wl1271_ssid_set(struct ieee80211_vif *vif, struct sk_buff *skb,
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003245 int offset)
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003246{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003247 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller889cb362011-05-01 09:56:45 +03003248 u8 ssid_len;
3249 const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
3250 skb->len - offset);
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003251
Eliad Peller889cb362011-05-01 09:56:45 +03003252 if (!ptr) {
3253 wl1271_error("No SSID in IEs!");
3254 return -ENOENT;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003255 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003256
Eliad Peller889cb362011-05-01 09:56:45 +03003257 ssid_len = ptr[1];
3258 if (ssid_len > IEEE80211_MAX_SSID_LEN) {
3259 wl1271_error("SSID is too long!");
3260 return -EINVAL;
3261 }
3262
Eliad Peller1fe9f162011-10-05 11:55:48 +02003263 wlvif->ssid_len = ssid_len;
3264 memcpy(wlvif->ssid, ptr+2, ssid_len);
Eliad Peller889cb362011-05-01 09:56:45 +03003265 return 0;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003266}
3267
Eliad Pellerd48055d2011-09-15 12:07:04 +03003268static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
3269{
3270 int len;
3271 const u8 *next, *end = skb->data + skb->len;
3272 u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
3273 skb->len - ieoffset);
3274 if (!ie)
3275 return;
3276 len = ie[1] + 2;
3277 next = ie + len;
3278 memmove(ie, next, end - next);
3279 skb_trim(skb, skb->len - len);
3280}
3281
Eliad Peller26b4bf22011-09-15 12:07:05 +03003282static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
3283 unsigned int oui, u8 oui_type,
3284 int ieoffset)
3285{
3286 int len;
3287 const u8 *next, *end = skb->data + skb->len;
3288 u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
3289 skb->data + ieoffset,
3290 skb->len - ieoffset);
3291 if (!ie)
3292 return;
3293 len = ie[1] + 2;
3294 next = ie + len;
3295 memmove(ie, next, end - next);
3296 skb_trim(skb, skb->len - len);
3297}
3298
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003299static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, u32 rates,
3300 struct ieee80211_vif *vif)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003301{
Eliad Pellercdaac622012-01-31 11:57:16 +02003302 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003303 struct sk_buff *skb;
3304 int ret;
3305
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003306 skb = ieee80211_proberesp_get(wl->hw, vif);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003307 if (!skb)
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003308 return -EOPNOTSUPP;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003309
Eliad Pellercdaac622012-01-31 11:57:16 +02003310 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov560f002412011-11-08 18:46:54 +02003311 CMD_TEMPL_AP_PROBE_RESPONSE,
3312 skb->data,
3313 skb->len, 0,
3314 rates);
3315
3316 dev_kfree_skb(skb);
3317 return ret;
3318}
3319
3320static int wl1271_ap_set_probe_resp_tmpl_legacy(struct wl1271 *wl,
3321 struct ieee80211_vif *vif,
3322 u8 *probe_rsp_data,
3323 size_t probe_rsp_len,
3324 u32 rates)
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003325{
Eliad Peller1fe9f162011-10-05 11:55:48 +02003326 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3327 struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003328 u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
3329 int ssid_ie_offset, ie_offset, templ_len;
3330 const u8 *ptr;
3331
3332 /* no need to change probe response if the SSID is set correctly */
Eliad Peller1fe9f162011-10-05 11:55:48 +02003333 if (wlvif->ssid_len > 0)
Eliad Pellercdaac622012-01-31 11:57:16 +02003334 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003335 CMD_TEMPL_AP_PROBE_RESPONSE,
3336 probe_rsp_data,
3337 probe_rsp_len, 0,
3338 rates);
3339
3340 if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
3341 wl1271_error("probe_rsp template too big");
3342 return -EINVAL;
3343 }
3344
3345 /* start searching from IE offset */
3346 ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
3347
3348 ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
3349 probe_rsp_len - ie_offset);
3350 if (!ptr) {
3351 wl1271_error("No SSID in beacon!");
3352 return -EINVAL;
3353 }
3354
3355 ssid_ie_offset = ptr - probe_rsp_data;
3356 ptr += (ptr[1] + 2);
3357
3358 memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
3359
3360 /* insert SSID from bss_conf */
3361 probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
3362 probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
3363 memcpy(probe_rsp_templ + ssid_ie_offset + 2,
3364 bss_conf->ssid, bss_conf->ssid_len);
3365 templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
3366
3367 memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
3368 ptr, probe_rsp_len - (ptr - probe_rsp_data));
3369 templ_len += probe_rsp_len - (ptr - probe_rsp_data);
3370
Eliad Pellercdaac622012-01-31 11:57:16 +02003371 return wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003372 CMD_TEMPL_AP_PROBE_RESPONSE,
3373 probe_rsp_templ,
3374 templ_len, 0,
3375 rates);
3376}
3377
Arik Nemtsove78a2872010-10-16 19:07:21 +02003378static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
Eliad Peller0603d892011-10-05 11:55:51 +02003379 struct ieee80211_vif *vif,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003380 struct ieee80211_bss_conf *bss_conf,
3381 u32 changed)
3382{
Eliad Peller0603d892011-10-05 11:55:51 +02003383 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003384 int ret = 0;
3385
3386 if (changed & BSS_CHANGED_ERP_SLOT) {
3387 if (bss_conf->use_short_slot)
Eliad Peller0603d892011-10-05 11:55:51 +02003388 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003389 else
Eliad Peller0603d892011-10-05 11:55:51 +02003390 ret = wl1271_acx_slot(wl, wlvif, SLOT_TIME_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003391 if (ret < 0) {
3392 wl1271_warning("Set slot time failed %d", ret);
3393 goto out;
3394 }
3395 }
3396
3397 if (changed & BSS_CHANGED_ERP_PREAMBLE) {
3398 if (bss_conf->use_short_preamble)
Eliad Peller0603d892011-10-05 11:55:51 +02003399 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_SHORT);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003400 else
Eliad Peller0603d892011-10-05 11:55:51 +02003401 wl1271_acx_set_preamble(wl, wlvif, ACX_PREAMBLE_LONG);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003402 }
3403
3404 if (changed & BSS_CHANGED_ERP_CTS_PROT) {
3405 if (bss_conf->use_cts_prot)
Eliad Peller0603d892011-10-05 11:55:51 +02003406 ret = wl1271_acx_cts_protect(wl, wlvif,
3407 CTSPROTECT_ENABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003408 else
Eliad Peller0603d892011-10-05 11:55:51 +02003409 ret = wl1271_acx_cts_protect(wl, wlvif,
3410 CTSPROTECT_DISABLE);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003411 if (ret < 0) {
3412 wl1271_warning("Set ctsprotect failed %d", ret);
3413 goto out;
3414 }
3415 }
3416
3417out:
3418 return ret;
3419}
3420
3421static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
3422 struct ieee80211_vif *vif,
3423 struct ieee80211_bss_conf *bss_conf,
3424 u32 changed)
3425{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003426 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Peller536129c82011-10-05 11:55:45 +02003427 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003428 int ret = 0;
3429
3430 if ((changed & BSS_CHANGED_BEACON_INT)) {
3431 wl1271_debug(DEBUG_MASTER, "beacon interval updated: %d",
3432 bss_conf->beacon_int);
3433
Eliad Peller6a899792011-10-05 11:55:58 +02003434 wlvif->beacon_int = bss_conf->beacon_int;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003435 }
3436
Arik Nemtsov560f002412011-11-08 18:46:54 +02003437 if ((changed & BSS_CHANGED_AP_PROBE_RESP) && is_ap) {
3438 u32 rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsov341f2c12011-11-22 19:52:59 +02003439 if (!wl1271_ap_set_probe_resp_tmpl(wl, rate, vif)) {
3440 wl1271_debug(DEBUG_AP, "probe response updated");
3441 set_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags);
3442 }
Arik Nemtsov560f002412011-11-08 18:46:54 +02003443 }
3444
Arik Nemtsove78a2872010-10-16 19:07:21 +02003445 if ((changed & BSS_CHANGED_BEACON)) {
3446 struct ieee80211_hdr *hdr;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003447 u32 min_rate;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003448 int ieoffset = offsetof(struct ieee80211_mgmt,
3449 u.beacon.variable);
3450 struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
3451 u16 tmpl_id;
3452
Arik Nemtsov560f002412011-11-08 18:46:54 +02003453 if (!beacon) {
3454 ret = -EINVAL;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003455 goto out;
Arik Nemtsov560f002412011-11-08 18:46:54 +02003456 }
Arik Nemtsove78a2872010-10-16 19:07:21 +02003457
3458 wl1271_debug(DEBUG_MASTER, "beacon updated");
3459
Eliad Peller1fe9f162011-10-05 11:55:48 +02003460 ret = wl1271_ssid_set(vif, beacon, ieoffset);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003461 if (ret < 0) {
3462 dev_kfree_skb(beacon);
3463 goto out;
3464 }
Eliad Peller87fbcb02011-10-05 11:55:41 +02003465 min_rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003466 tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
3467 CMD_TEMPL_BEACON;
Eliad Pellercdaac622012-01-31 11:57:16 +02003468 ret = wl1271_cmd_template_set(wl, wlvif->role_id, tmpl_id,
Arik Nemtsove78a2872010-10-16 19:07:21 +02003469 beacon->data,
3470 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003471 min_rate);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003472 if (ret < 0) {
3473 dev_kfree_skb(beacon);
3474 goto out;
3475 }
3476
Arik Nemtsov560f002412011-11-08 18:46:54 +02003477 /*
3478 * In case we already have a probe-resp beacon set explicitly
3479 * by usermode, don't use the beacon data.
3480 */
3481 if (test_bit(WLVIF_FLAG_AP_PROBE_RESP_SET, &wlvif->flags))
3482 goto end_bcn;
3483
Eliad Pellerd48055d2011-09-15 12:07:04 +03003484 /* remove TIM ie from probe response */
3485 wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
3486
Eliad Peller26b4bf22011-09-15 12:07:05 +03003487 /*
3488 * remove p2p ie from probe response.
3489 * the fw reponds to probe requests that don't include
3490 * the p2p ie. probe requests with p2p ie will be passed,
3491 * and will be responded by the supplicant (the spec
3492 * forbids including the p2p ie when responding to probe
3493 * requests that didn't include it).
3494 */
3495 wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
3496 WLAN_OUI_TYPE_WFA_P2P, ieoffset);
3497
Arik Nemtsove78a2872010-10-16 19:07:21 +02003498 hdr = (struct ieee80211_hdr *) beacon->data;
3499 hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
3500 IEEE80211_STYPE_PROBE_RESP);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003501 if (is_ap)
Arik Nemtsov560f002412011-11-08 18:46:54 +02003502 ret = wl1271_ap_set_probe_resp_tmpl_legacy(wl, vif,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003503 beacon->data,
3504 beacon->len,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003505 min_rate);
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003506 else
Eliad Pellercdaac622012-01-31 11:57:16 +02003507 ret = wl1271_cmd_template_set(wl, wlvif->role_id,
Arik Nemtsov68eaaf62011-09-03 20:22:03 +03003508 CMD_TEMPL_PROBE_RESPONSE,
3509 beacon->data,
3510 beacon->len, 0,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003511 min_rate);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003512end_bcn:
Arik Nemtsove78a2872010-10-16 19:07:21 +02003513 dev_kfree_skb(beacon);
3514 if (ret < 0)
3515 goto out;
3516 }
3517
3518out:
Arik Nemtsov560f002412011-11-08 18:46:54 +02003519 if (ret != 0)
3520 wl1271_error("beacon info change failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003521 return ret;
3522}
3523
3524/* AP mode changes */
3525static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003526 struct ieee80211_vif *vif,
3527 struct ieee80211_bss_conf *bss_conf,
3528 u32 changed)
3529{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003530 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003531 int ret = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003532
Arik Nemtsove78a2872010-10-16 19:07:21 +02003533 if ((changed & BSS_CHANGED_BASIC_RATES)) {
3534 u32 rates = bss_conf->basic_rates;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003535
Eliad Peller87fbcb02011-10-05 11:55:41 +02003536 wlvif->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003537 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003538 wlvif->basic_rate = wl1271_tx_min_rate_get(wl,
Eliad Peller87fbcb02011-10-05 11:55:41 +02003539 wlvif->basic_rate_set);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003540
Eliad Peller87fbcb02011-10-05 11:55:41 +02003541 ret = wl1271_init_ap_rates(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003542 if (ret < 0) {
Arik Nemtsov70f47422011-04-18 14:15:25 +03003543 wl1271_error("AP rate policy change failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003544 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003545 }
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003546
Eliad Peller784f6942011-10-05 11:55:39 +02003547 ret = wl1271_ap_init_templates(wl, vif);
Arik Nemtsovc45a85b2011-04-18 14:15:26 +03003548 if (ret < 0)
3549 goto out;
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02003550 }
3551
Arik Nemtsove78a2872010-10-16 19:07:21 +02003552 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
3553 if (ret < 0)
3554 goto out;
3555
3556 if ((changed & BSS_CHANGED_BEACON_ENABLED)) {
3557 if (bss_conf->enable_beacon) {
Eliad Peller53d40d02011-10-10 10:13:02 +02003558 if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003559 ret = wl12xx_cmd_role_start_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003560 if (ret < 0)
3561 goto out;
3562
Eliad Pellera8ab39a2011-10-05 11:55:54 +02003563 ret = wl1271_ap_init_hwenc(wl, wlvif);
Arik Nemtsov7f179b42010-10-16 21:39:06 +02003564 if (ret < 0)
3565 goto out;
Arik Nemtsovcf420392011-08-14 13:17:37 +03003566
Eliad Peller53d40d02011-10-10 10:13:02 +02003567 set_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsovcf420392011-08-14 13:17:37 +03003568 wl1271_debug(DEBUG_AP, "started AP");
Arik Nemtsove78a2872010-10-16 19:07:21 +02003569 }
3570 } else {
Eliad Peller53d40d02011-10-10 10:13:02 +02003571 if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003572 ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003573 if (ret < 0)
3574 goto out;
3575
Eliad Peller53d40d02011-10-10 10:13:02 +02003576 clear_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags);
Arik Nemtsov560f002412011-11-08 18:46:54 +02003577 clear_bit(WLVIF_FLAG_AP_PROBE_RESP_SET,
3578 &wlvif->flags);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003579 wl1271_debug(DEBUG_AP, "stopped AP");
3580 }
3581 }
3582 }
3583
Eliad Peller0603d892011-10-05 11:55:51 +02003584 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003585 if (ret < 0)
3586 goto out;
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003587
3588 /* Handle HT information change */
3589 if ((changed & BSS_CHANGED_HT) &&
3590 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003591 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003592 bss_conf->ht_operation_mode);
3593 if (ret < 0) {
3594 wl1271_warning("Set ht information failed %d", ret);
3595 goto out;
3596 }
3597 }
3598
Arik Nemtsove78a2872010-10-16 19:07:21 +02003599out:
3600 return;
3601}
3602
3603/* STA/IBSS mode changes */
3604static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
3605 struct ieee80211_vif *vif,
3606 struct ieee80211_bss_conf *bss_conf,
3607 u32 changed)
3608{
Eliad Peller87fbcb02011-10-05 11:55:41 +02003609 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003610 bool do_join = false, set_assoc = false;
Eliad Peller536129c82011-10-05 11:55:45 +02003611 bool is_ibss = (wlvif->bss_type == BSS_TYPE_IBSS);
Eliad Peller227e81e2011-08-14 13:17:26 +03003612 bool ibss_joined = false;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003613 u32 sta_rate_set = 0;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003614 int ret;
Luciano Coelho2d6e4e762011-01-11 19:07:21 +01003615 struct ieee80211_sta *sta;
Arik Nemtsova1008852011-02-12 23:24:20 +02003616 bool sta_exists = false;
3617 struct ieee80211_sta_ht_cap sta_ht_cap;
Arik Nemtsove78a2872010-10-16 19:07:21 +02003618
3619 if (is_ibss) {
3620 ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf,
3621 changed);
3622 if (ret < 0)
3623 goto out;
3624 }
3625
Eliad Peller227e81e2011-08-14 13:17:26 +03003626 if (changed & BSS_CHANGED_IBSS) {
3627 if (bss_conf->ibss_joined) {
Eliad Pellereee514e2011-10-10 10:13:01 +02003628 set_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags);
Eliad Peller227e81e2011-08-14 13:17:26 +03003629 ibss_joined = true;
3630 } else {
Eliad Pellereee514e2011-10-10 10:13:01 +02003631 if (test_and_clear_bit(WLVIF_FLAG_IBSS_JOINED,
3632 &wlvif->flags)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003633 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003634 wl12xx_start_dev(wl, wlvif);
Eliad Peller227e81e2011-08-14 13:17:26 +03003635 }
3636 }
3637 }
3638
3639 if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003640 do_join = true;
3641
3642 /* Need to update the SSID (for filtering etc) */
Eliad Peller227e81e2011-08-14 13:17:26 +03003643 if ((changed & BSS_CHANGED_BEACON) && ibss_joined)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003644 do_join = true;
3645
Eliad Peller227e81e2011-08-14 13:17:26 +03003646 if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) {
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003647 wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
3648 bss_conf->enable_beacon ? "enabled" : "disabled");
3649
Juuso Oikarinen5da11dc2010-03-26 12:53:24 +02003650 do_join = true;
3651 }
3652
Eliad Pellerc31e4942011-10-23 08:21:55 +02003653 if (changed & BSS_CHANGED_IDLE) {
3654 ret = wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
3655 if (ret < 0)
3656 wl1271_warning("idle mode change failed %d", ret);
3657 }
3658
Arik Nemtsove78a2872010-10-16 19:07:21 +02003659 if ((changed & BSS_CHANGED_CQM)) {
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003660 bool enable = false;
3661 if (bss_conf->cqm_rssi_thold)
3662 enable = true;
Eliad Peller0603d892011-10-05 11:55:51 +02003663 ret = wl1271_acx_rssi_snr_trigger(wl, wlvif, enable,
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003664 bss_conf->cqm_rssi_thold,
3665 bss_conf->cqm_rssi_hyst);
3666 if (ret < 0)
3667 goto out;
Eliad Peller04324d92011-10-05 11:56:03 +02003668 wlvif->rssi_thold = bss_conf->cqm_rssi_thold;
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03003669 }
3670
Eliad Peller7db4ee62012-01-24 18:18:42 +02003671 if (changed & BSS_CHANGED_BSSID &&
3672 (is_ibss || bss_conf->assoc))
Eliad Pellercdf09492011-10-05 11:55:44 +02003673 if (!is_zero_ether_addr(bss_conf->bssid)) {
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003674 ret = wl12xx_cmd_build_null_data(wl, wlvif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003675 if (ret < 0)
3676 goto out;
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003677
Eliad Peller784f6942011-10-05 11:55:39 +02003678 ret = wl1271_build_qos_null_data(wl, vif);
Eliad Pellerfa287b82010-12-26 09:27:50 +01003679 if (ret < 0)
3680 goto out;
Saravanan Dhanabal141418c2010-04-28 09:50:00 +03003681
Eliad Pellerfa287b82010-12-26 09:27:50 +01003682 /* Need to update the BSSID (for filtering etc) */
3683 do_join = true;
3684 }
Juuso Oikarinen30240fc2010-02-18 13:25:38 +02003685
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003686 if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) {
3687 rcu_read_lock();
3688 sta = ieee80211_find_sta(vif, bss_conf->bssid);
3689 if (!sta)
3690 goto sta_not_found;
3691
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003692 /* save the supp_rates of the ap */
3693 sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band];
3694 if (sta->ht_cap.ht_supported)
3695 sta_rate_set |=
3696 (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET);
Arik Nemtsova1008852011-02-12 23:24:20 +02003697 sta_ht_cap = sta->ht_cap;
3698 sta_exists = true;
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003699
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003700sta_not_found:
3701 rcu_read_unlock();
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003702 }
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003703
Arik Nemtsove78a2872010-10-16 19:07:21 +02003704 if ((changed & BSS_CHANGED_ASSOC)) {
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003705 if (bss_conf->assoc) {
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003706 u32 rates;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003707 int ieoffset;
Eliad Peller6840e372011-10-05 11:55:50 +02003708 wlvif->aid = bss_conf->aid;
Juuso Oikarinen69e54342010-05-07 11:39:00 +03003709 set_assoc = true;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003710
Eliad Peller74ec8392011-10-05 11:56:02 +02003711 wlvif->ps_poll_failures = 0;
Juuso Oikarinen90494a92010-07-08 17:50:00 +03003712
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003713 /*
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003714 * use basic rates from AP, and determine lowest rate
3715 * to use with control frames.
3716 */
3717 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003718 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003719 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003720 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003721 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003722 wl1271_tx_min_rate_get(wl,
3723 wlvif->basic_rate_set);
Eliad Peller72c2d9e2011-02-02 09:59:37 +02003724 if (sta_rate_set)
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003725 wlvif->rate_set =
3726 wl1271_tx_enabled_rates_get(wl,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003727 sta_rate_set,
Eliad Peller1b92f152011-10-10 10:13:09 +02003728 wlvif->band);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003729 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003730 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003731 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003732
3733 /*
Luciano Coelhoae751ba2009-10-12 15:08:57 +03003734 * with wl1271, we don't need to update the
3735 * beacon_int and dtim_period, because the firmware
3736 * updates it by itself when the first beacon is
3737 * received after a join.
3738 */
Eliad Peller6840e372011-10-05 11:55:50 +02003739 ret = wl1271_cmd_build_ps_poll(wl, wlvif, wlvif->aid);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003740 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003741 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003742
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003743 /*
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003744 * Get a template for hardware connection maintenance
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003745 */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003746 dev_kfree_skb(wlvif->probereq);
3747 wlvif->probereq = wl1271_cmd_build_ap_probe_req(wl,
Eliad Peller83587502011-10-10 10:12:53 +02003748 wlvif,
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003749 NULL);
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003750 ieoffset = offsetof(struct ieee80211_mgmt,
3751 u.probe_req.variable);
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003752 wl1271_ssid_set(vif, wlvif->probereq, ieoffset);
Juuso Oikarinenc2b2d992010-03-26 12:53:28 +02003753
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003754 /* enable the connection monitoring feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003755 ret = wl1271_acx_conn_monit_params(wl, wlvif, true);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003756 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003757 goto out;
Juuso Oikarinend94cd292009-10-08 21:56:25 +03003758 } else {
3759 /* use defaults when not associated */
Eliad Peller30df14d2011-04-05 19:13:28 +03003760 bool was_assoc =
Eliad Pellerba8447f62011-10-10 10:13:00 +02003761 !!test_and_clear_bit(WLVIF_FLAG_STA_ASSOCIATED,
3762 &wlvif->flags);
Eliad Peller251c1772011-08-14 13:17:17 +03003763 bool was_ifup =
Eliad Peller8181aec2011-10-10 10:13:04 +02003764 !!test_and_clear_bit(WLVIF_FLAG_STA_STATE_SENT,
3765 &wlvif->flags);
Eliad Peller6840e372011-10-05 11:55:50 +02003766 wlvif->aid = 0;
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003767
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003768 /* free probe-request template */
Eliad Pellerbddb29b2011-10-05 11:55:49 +02003769 dev_kfree_skb(wlvif->probereq);
3770 wlvif->probereq = NULL;
Juuso Oikarinen2f6724b2010-11-24 08:16:57 +02003771
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003772 /* re-enable dynamic ps - just in case */
Eliad Peller6e8cd332011-10-10 10:13:13 +02003773 ieee80211_enable_dyn_ps(vif);
Juuso Oikarinen8d2ef7b2010-07-08 17:50:03 +03003774
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003775 /* revert back to minimum rates for the current band */
Eliad Peller87fbcb02011-10-05 11:55:41 +02003776 wl1271_set_band_rate(wl, wlvif);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003777 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003778 wl1271_tx_min_rate_get(wl,
3779 wlvif->basic_rate_set);
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003780 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003781 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003782 goto out;
Juuso Oikarinenebba60c2010-04-01 11:38:20 +03003783
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003784 /* disable connection monitor features */
Eliad Peller0603d892011-10-05 11:55:51 +02003785 ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003786
3787 /* Disable the keep-alive feature */
Eliad Peller0603d892011-10-05 11:55:51 +02003788 ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
Juuso Oikarinen6ccbb922010-03-26 12:53:23 +02003789 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003790 goto out;
Juuso Oikarinenb84a7d32010-11-22 12:59:08 +02003791
3792 /* restore the bssid filter and go to dummy bssid */
Eliad Peller30df14d2011-04-05 19:13:28 +03003793 if (was_assoc) {
Eliad Peller251c1772011-08-14 13:17:17 +03003794 u32 conf_flags = wl->hw->conf.flags;
3795 /*
3796 * we might have to disable roc, if there was
3797 * no IF_OPER_UP notification.
3798 */
3799 if (!was_ifup) {
Eliad Peller0603d892011-10-05 11:55:51 +02003800 ret = wl12xx_croc(wl, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003801 if (ret < 0)
3802 goto out;
3803 }
3804 /*
3805 * (we also need to disable roc in case of
3806 * roaming on the same channel. until we will
3807 * have a better flow...)
3808 */
Eliad Peller7edebf52011-10-05 11:55:52 +02003809 if (test_bit(wlvif->dev_role_id, wl->roc_map)) {
3810 ret = wl12xx_croc(wl,
3811 wlvif->dev_role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003812 if (ret < 0)
3813 goto out;
3814 }
3815
Eliad Peller0603d892011-10-05 11:55:51 +02003816 wl1271_unjoin(wl, wlvif);
Eliad Peller679a6732011-10-11 11:55:44 +02003817 if (!(conf_flags & IEEE80211_CONF_IDLE))
3818 wl12xx_start_dev(wl, wlvif);
Eliad Peller30df14d2011-04-05 19:13:28 +03003819 }
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003820 }
3821 }
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03003822
Eliad Pellerd192d262011-05-24 14:33:08 +03003823 if (changed & BSS_CHANGED_IBSS) {
3824 wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
3825 bss_conf->ibss_joined);
3826
3827 if (bss_conf->ibss_joined) {
3828 u32 rates = bss_conf->basic_rates;
Eliad Peller87fbcb02011-10-05 11:55:41 +02003829 wlvif->basic_rate_set =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03003830 wl1271_tx_enabled_rates_get(wl, rates,
Eliad Peller1b92f152011-10-10 10:13:09 +02003831 wlvif->band);
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003832 wlvif->basic_rate =
Eliad Peller87fbcb02011-10-05 11:55:41 +02003833 wl1271_tx_min_rate_get(wl,
3834 wlvif->basic_rate_set);
Eliad Pellerd192d262011-05-24 14:33:08 +03003835
Shahar Levi06b660e2011-09-05 13:54:36 +03003836 /* by default, use 11b + OFDM rates */
Eliad Peller30d0c8f2011-10-05 11:55:42 +02003837 wlvif->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
3838 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
Eliad Pellerd192d262011-05-24 14:33:08 +03003839 if (ret < 0)
3840 goto out;
3841 }
3842 }
3843
Eliad Peller0603d892011-10-05 11:55:51 +02003844 ret = wl1271_bss_erp_info_changed(wl, vif, bss_conf, changed);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003845 if (ret < 0)
3846 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003847
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003848 if (changed & BSS_CHANGED_ARP_FILTER) {
3849 __be32 addr = bss_conf->arp_addr_list[0];
Eliad Peller536129c82011-10-05 11:55:45 +02003850 WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003851
Eliad Pellerc5312772010-12-09 11:31:27 +02003852 if (bss_conf->arp_addr_cnt == 1 &&
3853 bss_conf->arp_filter_enabled) {
3854 /*
3855 * The template should have been configured only upon
3856 * association. however, it seems that the correct ip
3857 * isn't being set (when sending), so we have to
3858 * reconfigure the template upon every ip change.
3859 */
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003860 ret = wl1271_cmd_build_arp_rsp(wl, wlvif, addr);
Eliad Pellerc5312772010-12-09 11:31:27 +02003861 if (ret < 0) {
3862 wl1271_warning("build arp rsp failed: %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003863 goto out;
Eliad Pellerc5312772010-12-09 11:31:27 +02003864 }
3865
Eliad Peller0603d892011-10-05 11:55:51 +02003866 ret = wl1271_acx_arp_ip_filter(wl, wlvif,
Eliad Pellere5e2f242011-01-24 19:19:03 +01003867 ACX_ARP_FILTER_ARP_FILTERING,
Eliad Pellerc5312772010-12-09 11:31:27 +02003868 addr);
3869 } else
Eliad Peller0603d892011-10-05 11:55:51 +02003870 ret = wl1271_acx_arp_ip_filter(wl, wlvif, 0, addr);
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003871
3872 if (ret < 0)
Arik Nemtsove78a2872010-10-16 19:07:21 +02003873 goto out;
Juuso Oikarinenca52a5e2010-07-08 17:50:02 +03003874 }
3875
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003876 if (do_join) {
Eliad Peller87fbcb02011-10-05 11:55:41 +02003877 ret = wl1271_join(wl, wlvif, set_assoc);
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003878 if (ret < 0) {
3879 wl1271_warning("cmd join failed %d", ret);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003880 goto out;
Juuso Oikarinen8bf29b02010-02-18 13:25:51 +02003881 }
Eliad Peller251c1772011-08-14 13:17:17 +03003882
3883 /* ROC until connected (after EAPOL exchange) */
3884 if (!is_ibss) {
Eliad Peller1b92f152011-10-10 10:13:09 +02003885 ret = wl12xx_roc(wl, wlvif, wlvif->role_id);
Eliad Peller251c1772011-08-14 13:17:17 +03003886 if (ret < 0)
3887 goto out;
3888
Eliad Pellerba8447f62011-10-10 10:13:00 +02003889 wl1271_check_operstate(wl, wlvif,
Eliad Peller251c1772011-08-14 13:17:17 +03003890 ieee80211_get_operstate(vif));
3891 }
3892 /*
3893 * stop device role if started (we might already be in
Eliad Peller92e712d2011-12-18 20:25:43 +02003894 * STA/IBSS role).
Eliad Peller251c1772011-08-14 13:17:17 +03003895 */
Eliad Peller92e712d2011-12-18 20:25:43 +02003896 if (wl12xx_dev_role_started(wlvif)) {
Eliad Peller679a6732011-10-11 11:55:44 +02003897 ret = wl12xx_stop_dev(wl, wlvif);
Eliad Peller251c1772011-08-14 13:17:17 +03003898 if (ret < 0)
3899 goto out;
3900 }
Eliad Peller05dba352011-08-23 16:37:01 +03003901
3902 /* If we want to go in PSM but we're not there yet */
Eliad Pellerc29bb002011-10-10 10:13:03 +02003903 if (test_bit(WLVIF_FLAG_PSM_REQUESTED, &wlvif->flags) &&
3904 !test_bit(WLVIF_FLAG_PSM, &wlvif->flags)) {
Eliad Peller05dba352011-08-23 16:37:01 +03003905 enum wl1271_cmd_ps_mode mode;
3906
3907 mode = STATION_POWER_SAVE_MODE;
Eliad Peller0603d892011-10-05 11:55:51 +02003908 ret = wl1271_ps_set_mode(wl, wlvif, mode,
Eliad Pellerd2d66c52011-10-05 11:55:43 +02003909 wlvif->basic_rate,
Eliad Peller05dba352011-08-23 16:37:01 +03003910 true);
3911 if (ret < 0)
3912 goto out;
3913 }
Juuso Oikarinenc1899552010-03-26 12:53:32 +02003914 }
3915
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003916 /* Handle new association with HT. Do this after join. */
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003917 if (sta_exists) {
3918 if ((changed & BSS_CHANGED_HT) &&
3919 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003920 ret = wl1271_acx_set_ht_capabilities(wl,
3921 &sta_ht_cap,
3922 true,
Eliad Peller154da672011-10-05 11:55:53 +02003923 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003924 if (ret < 0) {
3925 wl1271_warning("Set ht cap true failed %d",
3926 ret);
3927 goto out;
3928 }
3929 }
3930 /* handle new association without HT and disassociation */
3931 else if (changed & BSS_CHANGED_ASSOC) {
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003932 ret = wl1271_acx_set_ht_capabilities(wl,
3933 &sta_ht_cap,
3934 false,
Eliad Peller154da672011-10-05 11:55:53 +02003935 wlvif->sta.hlid);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003936 if (ret < 0) {
3937 wl1271_warning("Set ht cap false failed %d",
3938 ret);
3939 goto out;
3940 }
3941 }
3942 }
3943
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03003944 /* Handle HT information change. Done after join. */
3945 if ((changed & BSS_CHANGED_HT) &&
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003946 (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
Eliad Peller0603d892011-10-05 11:55:51 +02003947 ret = wl1271_acx_set_ht_information(wl, wlvif,
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03003948 bss_conf->ht_operation_mode);
3949 if (ret < 0) {
3950 wl1271_warning("Set ht information failed %d", ret);
3951 goto out;
3952 }
3953 }
3954
Arik Nemtsove78a2872010-10-16 19:07:21 +02003955out:
3956 return;
3957}
3958
3959static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
3960 struct ieee80211_vif *vif,
3961 struct ieee80211_bss_conf *bss_conf,
3962 u32 changed)
3963{
3964 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02003965 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3966 bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003967 int ret;
3968
3969 wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed 0x%x",
3970 (int)changed);
3971
3972 mutex_lock(&wl->mutex);
3973
3974 if (unlikely(wl->state == WL1271_STATE_OFF))
3975 goto out;
3976
Eliad Peller10c8cd02011-10-10 10:13:06 +02003977 if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
3978 goto out;
3979
Ido Yariva6208652011-03-01 15:14:41 +02003980 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsove78a2872010-10-16 19:07:21 +02003981 if (ret < 0)
3982 goto out;
3983
3984 if (is_ap)
3985 wl1271_bss_info_changed_ap(wl, vif, bss_conf, changed);
3986 else
3987 wl1271_bss_info_changed_sta(wl, vif, bss_conf, changed);
3988
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03003989 wl1271_ps_elp_sleep(wl);
3990
3991out:
3992 mutex_unlock(&wl->mutex);
3993}
3994
Eliad Peller8a3a3c82011-10-02 10:15:52 +02003995static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
3996 struct ieee80211_vif *vif, u16 queue,
Kalle Valoc6999d82010-02-18 13:25:41 +02003997 const struct ieee80211_tx_queue_params *params)
3998{
3999 struct wl1271 *wl = hw->priv;
Eliad Peller0603d892011-10-05 11:55:51 +02004000 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Kalle Valo4695dc92010-03-18 12:26:38 +02004001 u8 ps_scheme;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004002 int ret = 0;
Kalle Valoc6999d82010-02-18 13:25:41 +02004003
4004 mutex_lock(&wl->mutex);
4005
4006 wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue);
4007
Kalle Valo4695dc92010-03-18 12:26:38 +02004008 if (params->uapsd)
4009 ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
4010 else
4011 ps_scheme = CONF_PS_SCHEME_LEGACY;
4012
Eliad Peller5b37ddf2011-12-18 20:25:40 +02004013 if (!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags))
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004014 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004015
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004016 ret = wl1271_ps_elp_wakeup(wl);
4017 if (ret < 0)
4018 goto out;
Arik Nemtsov488fc542010-10-16 20:33:45 +02004019
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004020 /*
4021 * the txop is confed in units of 32us by the mac80211,
4022 * we need us
4023 */
Eliad Peller0603d892011-10-05 11:55:51 +02004024 ret = wl1271_acx_ac_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004025 params->cw_min, params->cw_max,
4026 params->aifs, params->txop << 5);
4027 if (ret < 0)
4028 goto out_sleep;
4029
Eliad Peller0603d892011-10-05 11:55:51 +02004030 ret = wl1271_acx_tid_cfg(wl, wlvif, wl1271_tx_get_queue(queue),
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004031 CONF_CHANNEL_TYPE_EDCF,
4032 wl1271_tx_get_queue(queue),
4033 ps_scheme, CONF_ACK_POLICY_LEGACY,
4034 0, 0);
Kalle Valoc82c1dd2010-02-18 13:25:47 +02004035
4036out_sleep:
Eliad Pellerc1b193e2011-03-23 22:22:15 +02004037 wl1271_ps_elp_sleep(wl);
Kalle Valoc6999d82010-02-18 13:25:41 +02004038
4039out:
4040 mutex_unlock(&wl->mutex);
4041
4042 return ret;
4043}
4044
Eliad Peller37a41b42011-09-21 14:06:11 +03004045static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
4046 struct ieee80211_vif *vif)
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004047{
4048
4049 struct wl1271 *wl = hw->priv;
4050 u64 mactime = ULLONG_MAX;
4051 int ret;
4052
4053 wl1271_debug(DEBUG_MAC80211, "mac80211 get tsf");
4054
4055 mutex_lock(&wl->mutex);
4056
Juuso Oikarinenf8d98022010-10-26 13:24:39 +02004057 if (unlikely(wl->state == WL1271_STATE_OFF))
4058 goto out;
4059
Ido Yariva6208652011-03-01 15:14:41 +02004060 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004061 if (ret < 0)
4062 goto out;
4063
4064 ret = wl1271_acx_tsf_info(wl, &mactime);
4065 if (ret < 0)
4066 goto out_sleep;
4067
4068out_sleep:
4069 wl1271_ps_elp_sleep(wl);
4070
4071out:
4072 mutex_unlock(&wl->mutex);
4073 return mactime;
4074}
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004075
John W. Linvilleece550d2010-07-28 16:41:06 -04004076static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
4077 struct survey_info *survey)
4078{
4079 struct wl1271 *wl = hw->priv;
4080 struct ieee80211_conf *conf = &hw->conf;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004081
John W. Linvilleece550d2010-07-28 16:41:06 -04004082 if (idx != 0)
4083 return -ENOENT;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004084
John W. Linvilleece550d2010-07-28 16:41:06 -04004085 survey->channel = conf->channel;
4086 survey->filled = SURVEY_INFO_NOISE_DBM;
4087 survey->noise = wl->noise;
Juuso Oikarinenb739a422010-10-26 13:24:38 +02004088
John W. Linvilleece550d2010-07-28 16:41:06 -04004089 return 0;
4090}
4091
Arik Nemtsov409622e2011-02-23 00:22:29 +02004092static int wl1271_allocate_sta(struct wl1271 *wl,
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004093 struct wl12xx_vif *wlvif,
4094 struct ieee80211_sta *sta)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004095{
4096 struct wl1271_station *wl_sta;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004097 int ret;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004098
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004099
4100 if (wl->active_sta_count >= AP_MAX_STATIONS) {
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004101 wl1271_warning("could not allocate HLID - too much stations");
4102 return -EBUSY;
4103 }
4104
4105 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004106 ret = wl12xx_allocate_link(wl, wlvif, &wl_sta->hlid);
4107 if (ret < 0) {
4108 wl1271_warning("could not allocate HLID - too many links");
4109 return -EBUSY;
4110 }
4111
4112 set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004113 memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
Arik Nemtsovda032092011-08-25 12:43:15 +03004114 wl->active_sta_count++;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004115 return 0;
4116}
4117
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004118void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004119{
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004120 if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
Arik Nemtsovf1acea92011-08-25 12:43:17 +03004121 return;
4122
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004123 clear_bit(hlid, wlvif->ap.sta_hlid_map);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004124 memset(wl->links[hlid].addr, 0, ETH_ALEN);
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004125 wl->links[hlid].ba_bitmap = 0;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02004126 wl1271_tx_reset_link_queues(wl, hlid);
Arik Nemtsovb622d992011-02-23 00:22:31 +02004127 __clear_bit(hlid, &wl->ap_ps_map);
4128 __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004129 wl12xx_free_link(wl, wlvif, &hlid);
Arik Nemtsovda032092011-08-25 12:43:15 +03004130 wl->active_sta_count--;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004131}
4132
4133static int wl1271_op_sta_add(struct ieee80211_hw *hw,
4134 struct ieee80211_vif *vif,
4135 struct ieee80211_sta *sta)
4136{
4137 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004138 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004139 struct wl1271_station *wl_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004140 int ret = 0;
4141 u8 hlid;
4142
4143 mutex_lock(&wl->mutex);
4144
4145 if (unlikely(wl->state == WL1271_STATE_OFF))
4146 goto out;
4147
Eliad Peller536129c82011-10-05 11:55:45 +02004148 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004149 goto out;
4150
4151 wl1271_debug(DEBUG_MAC80211, "mac80211 add sta %d", (int)sta->aid);
4152
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004153 ret = wl1271_allocate_sta(wl, wlvif, sta);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004154 if (ret < 0)
4155 goto out;
4156
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004157 wl_sta = (struct wl1271_station *)sta->drv_priv;
4158 hlid = wl_sta->hlid;
4159
Ido Yariva6208652011-03-01 15:14:41 +02004160 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004161 if (ret < 0)
Arik Nemtsov409622e2011-02-23 00:22:29 +02004162 goto out_free_sta;
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004163
Eliad Peller1b92f152011-10-10 10:13:09 +02004164 ret = wl12xx_cmd_add_peer(wl, wlvif, sta, hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004165 if (ret < 0)
4166 goto out_sleep;
4167
Eliad Pellerb67476e2011-08-14 13:17:23 +03004168 ret = wl12xx_cmd_set_peer_state(wl, hlid);
4169 if (ret < 0)
4170 goto out_sleep;
4171
Arik Nemtsov0b932ab2011-08-14 13:17:27 +03004172 ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid);
4173 if (ret < 0)
4174 goto out_sleep;
4175
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004176out_sleep:
4177 wl1271_ps_elp_sleep(wl);
4178
Arik Nemtsov409622e2011-02-23 00:22:29 +02004179out_free_sta:
4180 if (ret < 0)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004181 wl1271_free_sta(wl, wlvif, hlid);
Arik Nemtsov409622e2011-02-23 00:22:29 +02004182
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004183out:
4184 mutex_unlock(&wl->mutex);
4185 return ret;
4186}
4187
4188static int wl1271_op_sta_remove(struct ieee80211_hw *hw,
4189 struct ieee80211_vif *vif,
4190 struct ieee80211_sta *sta)
4191{
4192 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004193 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004194 struct wl1271_station *wl_sta;
4195 int ret = 0, id;
4196
4197 mutex_lock(&wl->mutex);
4198
4199 if (unlikely(wl->state == WL1271_STATE_OFF))
4200 goto out;
4201
Eliad Peller536129c82011-10-05 11:55:45 +02004202 if (wlvif->bss_type != BSS_TYPE_AP_BSS)
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004203 goto out;
4204
4205 wl1271_debug(DEBUG_MAC80211, "mac80211 remove sta %d", (int)sta->aid);
4206
4207 wl_sta = (struct wl1271_station *)sta->drv_priv;
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004208 id = wl_sta->hlid;
4209 if (WARN_ON(!test_bit(id, wlvif->ap.sta_hlid_map)))
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004210 goto out;
4211
Ido Yariva6208652011-03-01 15:14:41 +02004212 ret = wl1271_ps_elp_wakeup(wl);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004213 if (ret < 0)
4214 goto out;
4215
Eliad Pellerc690ec82011-08-14 13:17:07 +03004216 ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004217 if (ret < 0)
4218 goto out_sleep;
4219
Eliad Pellerc7ffb902011-10-05 11:56:05 +02004220 wl1271_free_sta(wl, wlvif, wl_sta->hlid);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004221
4222out_sleep:
4223 wl1271_ps_elp_sleep(wl);
4224
4225out:
4226 mutex_unlock(&wl->mutex);
4227 return ret;
4228}
4229
Luciano Coelho4623ec72011-03-21 19:26:41 +02004230static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
4231 struct ieee80211_vif *vif,
4232 enum ieee80211_ampdu_mlme_action action,
4233 struct ieee80211_sta *sta, u16 tid, u16 *ssn,
4234 u8 buf_size)
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004235{
4236 struct wl1271 *wl = hw->priv;
Eliad Peller536129c82011-10-05 11:55:45 +02004237 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004238 int ret;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004239 u8 hlid, *ba_bitmap;
4240
4241 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
4242 tid);
4243
4244 /* sanity check - the fields in FW are only 8bits wide */
4245 if (WARN_ON(tid > 0xFF))
4246 return -ENOTSUPP;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004247
4248 mutex_lock(&wl->mutex);
4249
4250 if (unlikely(wl->state == WL1271_STATE_OFF)) {
4251 ret = -EAGAIN;
4252 goto out;
4253 }
4254
Eliad Peller536129c82011-10-05 11:55:45 +02004255 if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
Eliad Peller154da672011-10-05 11:55:53 +02004256 hlid = wlvif->sta.hlid;
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004257 ba_bitmap = &wlvif->sta.ba_rx_bitmap;
Eliad Peller536129c82011-10-05 11:55:45 +02004258 } else if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004259 struct wl1271_station *wl_sta;
4260
4261 wl_sta = (struct wl1271_station *)sta->drv_priv;
4262 hlid = wl_sta->hlid;
4263 ba_bitmap = &wl->links[hlid].ba_bitmap;
4264 } else {
4265 ret = -EINVAL;
4266 goto out;
4267 }
4268
Ido Yariva6208652011-03-01 15:14:41 +02004269 ret = wl1271_ps_elp_wakeup(wl);
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004270 if (ret < 0)
4271 goto out;
4272
Shahar Levi70559a02011-05-22 16:10:22 +03004273 wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
4274 tid, action);
4275
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004276 switch (action) {
4277 case IEEE80211_AMPDU_RX_START:
Eliad Pellerd0802ab2011-10-05 11:56:04 +02004278 if (!wlvif->ba_support || !wlvif->ba_allowed) {
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004279 ret = -ENOTSUPP;
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004280 break;
4281 }
4282
4283 if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
4284 ret = -EBUSY;
4285 wl1271_error("exceeded max RX BA sessions");
4286 break;
4287 }
4288
4289 if (*ba_bitmap & BIT(tid)) {
4290 ret = -EINVAL;
4291 wl1271_error("cannot enable RX BA session on active "
4292 "tid: %d", tid);
4293 break;
4294 }
4295
4296 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true,
4297 hlid);
4298 if (!ret) {
4299 *ba_bitmap |= BIT(tid);
4300 wl->ba_rx_session_count++;
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004301 }
4302 break;
4303
4304 case IEEE80211_AMPDU_RX_STOP:
Arik Nemtsov0f9c8252011-08-17 10:45:49 +03004305 if (!(*ba_bitmap & BIT(tid))) {
4306 ret = -EINVAL;
4307 wl1271_error("no active RX BA session on tid: %d",
4308 tid);
4309 break;
4310 }
4311
4312 ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false,
4313 hlid);
4314 if (!ret) {
4315 *ba_bitmap &= ~BIT(tid);
4316 wl->ba_rx_session_count--;
4317 }
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004318 break;
4319
4320 /*
4321 * The BA initiator session management in FW independently.
4322 * Falling break here on purpose for all TX APDU commands.
4323 */
4324 case IEEE80211_AMPDU_TX_START:
4325 case IEEE80211_AMPDU_TX_STOP:
4326 case IEEE80211_AMPDU_TX_OPERATIONAL:
4327 ret = -EINVAL;
4328 break;
4329
4330 default:
4331 wl1271_error("Incorrect ampdu action id=%x\n", action);
4332 ret = -EINVAL;
4333 }
4334
4335 wl1271_ps_elp_sleep(wl);
4336
4337out:
4338 mutex_unlock(&wl->mutex);
4339
4340 return ret;
4341}
4342
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004343static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
4344 struct ieee80211_vif *vif,
4345 const struct cfg80211_bitrate_mask *mask)
4346{
Eliad Peller83587502011-10-10 10:12:53 +02004347 struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004348 struct wl1271 *wl = hw->priv;
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004349 int i, ret = 0;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004350
4351 wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
4352 mask->control[NL80211_BAND_2GHZ].legacy,
4353 mask->control[NL80211_BAND_5GHZ].legacy);
4354
4355 mutex_lock(&wl->mutex);
4356
4357 for (i = 0; i < IEEE80211_NUM_BANDS; i++)
Eliad Peller83587502011-10-10 10:12:53 +02004358 wlvif->bitrate_masks[i] =
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004359 wl1271_tx_enabled_rates_get(wl,
4360 mask->control[i].legacy,
4361 i);
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004362
4363 if (unlikely(wl->state == WL1271_STATE_OFF))
4364 goto out;
4365
4366 if (wlvif->bss_type == BSS_TYPE_STA_BSS &&
4367 !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
4368
4369 ret = wl1271_ps_elp_wakeup(wl);
4370 if (ret < 0)
4371 goto out;
4372
4373 wl1271_set_band_rate(wl, wlvif);
4374 wlvif->basic_rate =
4375 wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4376 ret = wl1271_acx_sta_rate_policies(wl, wlvif);
4377
4378 wl1271_ps_elp_sleep(wl);
4379 }
4380out:
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004381 mutex_unlock(&wl->mutex);
4382
Eliad Pellerd6fa37c2011-10-11 11:57:39 +02004383 return ret;
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004384}
4385
Shahar Levi6d158ff2011-09-08 13:01:33 +03004386static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
4387 struct ieee80211_channel_switch *ch_switch)
4388{
4389 struct wl1271 *wl = hw->priv;
Eliad Peller52630c52011-10-10 10:13:08 +02004390 struct wl12xx_vif *wlvif;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004391 int ret;
4392
4393 wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
4394
4395 mutex_lock(&wl->mutex);
4396
4397 if (unlikely(wl->state == WL1271_STATE_OFF)) {
Eliad Peller6e8cd332011-10-10 10:13:13 +02004398 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4399 struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
4400 ieee80211_chswitch_done(vif, false);
4401 }
4402 goto out;
Shahar Levi6d158ff2011-09-08 13:01:33 +03004403 }
4404
4405 ret = wl1271_ps_elp_wakeup(wl);
4406 if (ret < 0)
4407 goto out;
4408
Eliad Peller52630c52011-10-10 10:13:08 +02004409 /* TODO: change mac80211 to pass vif as param */
4410 wl12xx_for_each_wlvif_sta(wl, wlvif) {
4411 ret = wl12xx_cmd_channel_switch(wl, ch_switch);
Shahar Levi6d158ff2011-09-08 13:01:33 +03004412
Eliad Peller52630c52011-10-10 10:13:08 +02004413 if (!ret)
4414 set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
4415 }
Shahar Levi6d158ff2011-09-08 13:01:33 +03004416
4417 wl1271_ps_elp_sleep(wl);
4418
4419out:
4420 mutex_unlock(&wl->mutex);
4421}
4422
Arik Nemtsov33437892011-04-26 23:35:39 +03004423static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
4424{
4425 struct wl1271 *wl = hw->priv;
4426 bool ret = false;
4427
4428 mutex_lock(&wl->mutex);
4429
4430 if (unlikely(wl->state == WL1271_STATE_OFF))
4431 goto out;
4432
4433 /* packets are considered pending if in the TX queue or the FW */
Arik Nemtsovf1a46382011-07-07 14:25:23 +03004434 ret = (wl1271_tx_total_queue_count(wl) > 0) || (wl->tx_frames_cnt > 0);
Arik Nemtsov33437892011-04-26 23:35:39 +03004435out:
4436 mutex_unlock(&wl->mutex);
4437
4438 return ret;
4439}
4440
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004441/* can't be const, mac80211 writes to this */
4442static struct ieee80211_rate wl1271_rates[] = {
4443 { .bitrate = 10,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004444 .hw_value = CONF_HW_BIT_RATE_1MBPS,
4445 .hw_value_short = CONF_HW_BIT_RATE_1MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004446 { .bitrate = 20,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004447 .hw_value = CONF_HW_BIT_RATE_2MBPS,
4448 .hw_value_short = CONF_HW_BIT_RATE_2MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004449 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4450 { .bitrate = 55,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004451 .hw_value = CONF_HW_BIT_RATE_5_5MBPS,
4452 .hw_value_short = CONF_HW_BIT_RATE_5_5MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004453 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4454 { .bitrate = 110,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004455 .hw_value = CONF_HW_BIT_RATE_11MBPS,
4456 .hw_value_short = CONF_HW_BIT_RATE_11MBPS,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004457 .flags = IEEE80211_RATE_SHORT_PREAMBLE },
4458 { .bitrate = 60,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004459 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4460 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004461 { .bitrate = 90,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004462 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4463 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004464 { .bitrate = 120,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004465 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4466 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004467 { .bitrate = 180,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004468 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4469 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004470 { .bitrate = 240,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004471 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4472 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004473 { .bitrate = 360,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004474 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4475 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004476 { .bitrate = 480,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004477 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4478 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004479 { .bitrate = 540,
Juuso Oikarinen2b60100b2009-10-13 12:47:39 +03004480 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4481 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004482};
4483
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004484/* can't be const, mac80211 writes to this */
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004485static struct ieee80211_channel wl1271_channels[] = {
Luciano Coelhoa2d0e3f2009-12-11 15:40:46 +02004486 { .hw_value = 1, .center_freq = 2412, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004487 { .hw_value = 2, .center_freq = 2417, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004488 { .hw_value = 3, .center_freq = 2422, .max_power = 25 },
4489 { .hw_value = 4, .center_freq = 2427, .max_power = 25 },
4490 { .hw_value = 5, .center_freq = 2432, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004491 { .hw_value = 6, .center_freq = 2437, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004492 { .hw_value = 7, .center_freq = 2442, .max_power = 25 },
4493 { .hw_value = 8, .center_freq = 2447, .max_power = 25 },
4494 { .hw_value = 9, .center_freq = 2452, .max_power = 25 },
Juuso Oikarinenfa21c7a2010-08-10 08:22:02 +02004495 { .hw_value = 10, .center_freq = 2457, .max_power = 25 },
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004496 { .hw_value = 11, .center_freq = 2462, .max_power = 25 },
4497 { .hw_value = 12, .center_freq = 2467, .max_power = 25 },
4498 { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
Arik Nemtsov6c89b7b2011-01-18 20:39:52 +01004499 { .hw_value = 14, .center_freq = 2484, .max_power = 25 },
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004500};
4501
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004502/* mapping to indexes for wl1271_rates */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004503static const u8 wl1271_rate_to_idx_2ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004504 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004505 7, /* CONF_HW_RXTX_RATE_MCS7 */
4506 6, /* CONF_HW_RXTX_RATE_MCS6 */
4507 5, /* CONF_HW_RXTX_RATE_MCS5 */
4508 4, /* CONF_HW_RXTX_RATE_MCS4 */
4509 3, /* CONF_HW_RXTX_RATE_MCS3 */
4510 2, /* CONF_HW_RXTX_RATE_MCS2 */
4511 1, /* CONF_HW_RXTX_RATE_MCS1 */
4512 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004513
4514 11, /* CONF_HW_RXTX_RATE_54 */
4515 10, /* CONF_HW_RXTX_RATE_48 */
4516 9, /* CONF_HW_RXTX_RATE_36 */
4517 8, /* CONF_HW_RXTX_RATE_24 */
4518
4519 /* TI-specific rate */
4520 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4521
4522 7, /* CONF_HW_RXTX_RATE_18 */
4523 6, /* CONF_HW_RXTX_RATE_12 */
4524 3, /* CONF_HW_RXTX_RATE_11 */
4525 5, /* CONF_HW_RXTX_RATE_9 */
4526 4, /* CONF_HW_RXTX_RATE_6 */
4527 2, /* CONF_HW_RXTX_RATE_5_5 */
4528 1, /* CONF_HW_RXTX_RATE_2 */
4529 0 /* CONF_HW_RXTX_RATE_1 */
4530};
4531
Shahar Levie8b03a22010-10-13 16:09:39 +02004532/* 11n STA capabilities */
4533#define HW_RX_HIGHEST_RATE 72
4534
Shahar Levi00d20102010-11-08 11:20:10 +00004535#define WL12XX_HT_CAP { \
Shahar Levi871d0c32011-03-13 11:24:40 +02004536 .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
4537 (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
Shahar Levie8b03a22010-10-13 16:09:39 +02004538 .ht_supported = true, \
4539 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
4540 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
4541 .mcs = { \
4542 .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
4543 .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \
4544 .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
4545 }, \
4546}
4547
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004548/* can't be const, mac80211 writes to this */
4549static struct ieee80211_supported_band wl1271_band_2ghz = {
4550 .channels = wl1271_channels,
4551 .n_channels = ARRAY_SIZE(wl1271_channels),
4552 .bitrates = wl1271_rates,
4553 .n_bitrates = ARRAY_SIZE(wl1271_rates),
Shahar Levi00d20102010-11-08 11:20:10 +00004554 .ht_cap = WL12XX_HT_CAP,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004555};
4556
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004557/* 5 GHz data rates for WL1273 */
4558static struct ieee80211_rate wl1271_rates_5ghz[] = {
4559 { .bitrate = 60,
4560 .hw_value = CONF_HW_BIT_RATE_6MBPS,
4561 .hw_value_short = CONF_HW_BIT_RATE_6MBPS, },
4562 { .bitrate = 90,
4563 .hw_value = CONF_HW_BIT_RATE_9MBPS,
4564 .hw_value_short = CONF_HW_BIT_RATE_9MBPS, },
4565 { .bitrate = 120,
4566 .hw_value = CONF_HW_BIT_RATE_12MBPS,
4567 .hw_value_short = CONF_HW_BIT_RATE_12MBPS, },
4568 { .bitrate = 180,
4569 .hw_value = CONF_HW_BIT_RATE_18MBPS,
4570 .hw_value_short = CONF_HW_BIT_RATE_18MBPS, },
4571 { .bitrate = 240,
4572 .hw_value = CONF_HW_BIT_RATE_24MBPS,
4573 .hw_value_short = CONF_HW_BIT_RATE_24MBPS, },
4574 { .bitrate = 360,
4575 .hw_value = CONF_HW_BIT_RATE_36MBPS,
4576 .hw_value_short = CONF_HW_BIT_RATE_36MBPS, },
4577 { .bitrate = 480,
4578 .hw_value = CONF_HW_BIT_RATE_48MBPS,
4579 .hw_value_short = CONF_HW_BIT_RATE_48MBPS, },
4580 { .bitrate = 540,
4581 .hw_value = CONF_HW_BIT_RATE_54MBPS,
4582 .hw_value_short = CONF_HW_BIT_RATE_54MBPS, },
4583};
4584
Juuso Oikarinenfa97f462010-11-10 11:27:20 +01004585/* 5 GHz band channels for WL1273 */
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004586static struct ieee80211_channel wl1271_channels_5ghz[] = {
Arik Nemtsov6cfa5cf2011-06-27 22:06:33 +03004587 { .hw_value = 7, .center_freq = 5035, .max_power = 25 },
4588 { .hw_value = 8, .center_freq = 5040, .max_power = 25 },
4589 { .hw_value = 9, .center_freq = 5045, .max_power = 25 },
4590 { .hw_value = 11, .center_freq = 5055, .max_power = 25 },
4591 { .hw_value = 12, .center_freq = 5060, .max_power = 25 },
4592 { .hw_value = 16, .center_freq = 5080, .max_power = 25 },
4593 { .hw_value = 34, .center_freq = 5170, .max_power = 25 },
4594 { .hw_value = 36, .center_freq = 5180, .max_power = 25 },
4595 { .hw_value = 38, .center_freq = 5190, .max_power = 25 },
4596 { .hw_value = 40, .center_freq = 5200, .max_power = 25 },
4597 { .hw_value = 42, .center_freq = 5210, .max_power = 25 },
4598 { .hw_value = 44, .center_freq = 5220, .max_power = 25 },
4599 { .hw_value = 46, .center_freq = 5230, .max_power = 25 },
4600 { .hw_value = 48, .center_freq = 5240, .max_power = 25 },
4601 { .hw_value = 52, .center_freq = 5260, .max_power = 25 },
4602 { .hw_value = 56, .center_freq = 5280, .max_power = 25 },
4603 { .hw_value = 60, .center_freq = 5300, .max_power = 25 },
4604 { .hw_value = 64, .center_freq = 5320, .max_power = 25 },
4605 { .hw_value = 100, .center_freq = 5500, .max_power = 25 },
4606 { .hw_value = 104, .center_freq = 5520, .max_power = 25 },
4607 { .hw_value = 108, .center_freq = 5540, .max_power = 25 },
4608 { .hw_value = 112, .center_freq = 5560, .max_power = 25 },
4609 { .hw_value = 116, .center_freq = 5580, .max_power = 25 },
4610 { .hw_value = 120, .center_freq = 5600, .max_power = 25 },
4611 { .hw_value = 124, .center_freq = 5620, .max_power = 25 },
4612 { .hw_value = 128, .center_freq = 5640, .max_power = 25 },
4613 { .hw_value = 132, .center_freq = 5660, .max_power = 25 },
4614 { .hw_value = 136, .center_freq = 5680, .max_power = 25 },
4615 { .hw_value = 140, .center_freq = 5700, .max_power = 25 },
4616 { .hw_value = 149, .center_freq = 5745, .max_power = 25 },
4617 { .hw_value = 153, .center_freq = 5765, .max_power = 25 },
4618 { .hw_value = 157, .center_freq = 5785, .max_power = 25 },
4619 { .hw_value = 161, .center_freq = 5805, .max_power = 25 },
4620 { .hw_value = 165, .center_freq = 5825, .max_power = 25 },
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004621};
4622
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004623/* mapping to indexes for wl1271_rates_5ghz */
Tobias Klausera0ea9492010-05-20 10:38:11 +02004624static const u8 wl1271_rate_to_idx_5ghz[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004625 /* MCS rates are used only with 11n */
Shahar Levi18357852010-10-13 16:09:41 +02004626 7, /* CONF_HW_RXTX_RATE_MCS7 */
4627 6, /* CONF_HW_RXTX_RATE_MCS6 */
4628 5, /* CONF_HW_RXTX_RATE_MCS5 */
4629 4, /* CONF_HW_RXTX_RATE_MCS4 */
4630 3, /* CONF_HW_RXTX_RATE_MCS3 */
4631 2, /* CONF_HW_RXTX_RATE_MCS2 */
4632 1, /* CONF_HW_RXTX_RATE_MCS1 */
4633 0, /* CONF_HW_RXTX_RATE_MCS0 */
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004634
4635 7, /* CONF_HW_RXTX_RATE_54 */
4636 6, /* CONF_HW_RXTX_RATE_48 */
4637 5, /* CONF_HW_RXTX_RATE_36 */
4638 4, /* CONF_HW_RXTX_RATE_24 */
4639
4640 /* TI-specific rate */
4641 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22 */
4642
4643 3, /* CONF_HW_RXTX_RATE_18 */
4644 2, /* CONF_HW_RXTX_RATE_12 */
4645 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11 */
4646 1, /* CONF_HW_RXTX_RATE_9 */
4647 0, /* CONF_HW_RXTX_RATE_6 */
4648 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5 */
4649 CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2 */
4650 CONF_HW_RXTX_RATE_UNSUPPORTED /* CONF_HW_RXTX_RATE_1 */
4651};
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004652
4653static struct ieee80211_supported_band wl1271_band_5ghz = {
4654 .channels = wl1271_channels_5ghz,
4655 .n_channels = ARRAY_SIZE(wl1271_channels_5ghz),
4656 .bitrates = wl1271_rates_5ghz,
4657 .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
Shahar Levi00d20102010-11-08 11:20:10 +00004658 .ht_cap = WL12XX_HT_CAP,
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03004659};
4660
Tobias Klausera0ea9492010-05-20 10:38:11 +02004661static const u8 *wl1271_band_rate_to_idx[] = {
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004662 [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
4663 [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
4664};
4665
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004666static const struct ieee80211_ops wl1271_ops = {
4667 .start = wl1271_op_start,
4668 .stop = wl1271_op_stop,
4669 .add_interface = wl1271_op_add_interface,
4670 .remove_interface = wl1271_op_remove_interface,
Eliad Pellerc0fad1b2011-12-19 12:00:03 +02004671 .change_interface = wl12xx_op_change_interface,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004672#ifdef CONFIG_PM
Eliad Peller402e48612011-05-13 11:57:09 +03004673 .suspend = wl1271_op_suspend,
4674 .resume = wl1271_op_resume,
Luciano Coelhof634a4e2011-05-18 16:51:26 -04004675#endif
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004676 .config = wl1271_op_config,
Juuso Oikarinenc87dec92009-10-08 21:56:31 +03004677 .prepare_multicast = wl1271_op_prepare_multicast,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004678 .configure_filter = wl1271_op_configure_filter,
4679 .tx = wl1271_op_tx,
4680 .set_key = wl1271_op_set_key,
4681 .hw_scan = wl1271_op_hw_scan,
Eliad Peller73ecce32011-06-27 13:06:45 +03004682 .cancel_hw_scan = wl1271_op_cancel_hw_scan,
Luciano Coelho33c2c062011-05-10 14:46:02 +03004683 .sched_scan_start = wl1271_op_sched_scan_start,
4684 .sched_scan_stop = wl1271_op_sched_scan_stop,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004685 .bss_info_changed = wl1271_op_bss_info_changed,
Arik Nemtsov68d069c2010-11-08 10:51:07 +01004686 .set_frag_threshold = wl1271_op_set_frag_threshold,
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004687 .set_rts_threshold = wl1271_op_set_rts_threshold,
Kalle Valoc6999d82010-02-18 13:25:41 +02004688 .conf_tx = wl1271_op_conf_tx,
Juuso Oikarinenbbbb5382010-07-08 17:49:57 +03004689 .get_tsf = wl1271_op_get_tsf,
John W. Linvilleece550d2010-07-28 16:41:06 -04004690 .get_survey = wl1271_op_get_survey,
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02004691 .sta_add = wl1271_op_sta_add,
4692 .sta_remove = wl1271_op_sta_remove,
Levi, Shaharbbba3e62011-01-23 07:27:23 +01004693 .ampdu_action = wl1271_op_ampdu_action,
Arik Nemtsov33437892011-04-26 23:35:39 +03004694 .tx_frames_pending = wl1271_tx_frames_pending,
Eliad Pelleraf7fbb22011-09-19 13:51:42 +03004695 .set_bitrate_mask = wl12xx_set_bitrate_mask,
Shahar Levi6d158ff2011-09-08 13:01:33 +03004696 .channel_switch = wl12xx_op_channel_switch,
Kalle Valoc8c90872010-02-18 13:25:53 +02004697 CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004698};
4699
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004700
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004701u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band)
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004702{
4703 u8 idx;
4704
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004705 BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004706
4707 if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
4708 wl1271_error("Illegal RX rate from HW: %d", rate);
4709 return 0;
4710 }
4711
Teemu Paasikivi6a2de932010-10-14 11:00:04 +02004712 idx = wl1271_band_rate_to_idx[band][rate];
Juuso Oikarinenf876bb92010-03-26 12:53:11 +02004713 if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
4714 wl1271_error("Unsupported RX rate from HW: %d", rate);
4715 return 0;
4716 }
4717
4718 return idx;
4719}
4720
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004721static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
4722 struct device_attribute *attr,
4723 char *buf)
4724{
4725 struct wl1271 *wl = dev_get_drvdata(dev);
4726 ssize_t len;
4727
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004728 len = PAGE_SIZE;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004729
4730 mutex_lock(&wl->mutex);
4731 len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
4732 wl->sg_enabled);
4733 mutex_unlock(&wl->mutex);
4734
4735 return len;
4736
4737}
4738
4739static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
4740 struct device_attribute *attr,
4741 const char *buf, size_t count)
4742{
4743 struct wl1271 *wl = dev_get_drvdata(dev);
4744 unsigned long res;
4745 int ret;
4746
Luciano Coelho6277ed62011-04-01 17:49:54 +03004747 ret = kstrtoul(buf, 10, &res);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004748 if (ret < 0) {
4749 wl1271_warning("incorrect value written to bt_coex_mode");
4750 return count;
4751 }
4752
4753 mutex_lock(&wl->mutex);
4754
4755 res = !!res;
4756
4757 if (res == wl->sg_enabled)
4758 goto out;
4759
4760 wl->sg_enabled = res;
4761
4762 if (wl->state == WL1271_STATE_OFF)
4763 goto out;
4764
Ido Yariva6208652011-03-01 15:14:41 +02004765 ret = wl1271_ps_elp_wakeup(wl);
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02004766 if (ret < 0)
4767 goto out;
4768
4769 wl1271_acx_sg_enable(wl, wl->sg_enabled);
4770 wl1271_ps_elp_sleep(wl);
4771
4772 out:
4773 mutex_unlock(&wl->mutex);
4774 return count;
4775}
4776
4777static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
4778 wl1271_sysfs_show_bt_coex_state,
4779 wl1271_sysfs_store_bt_coex_state);
4780
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004781static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
4782 struct device_attribute *attr,
4783 char *buf)
4784{
4785 struct wl1271 *wl = dev_get_drvdata(dev);
4786 ssize_t len;
4787
Juuso Oikarinen2f63b012010-08-10 06:38:35 +02004788 len = PAGE_SIZE;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004789
4790 mutex_lock(&wl->mutex);
4791 if (wl->hw_pg_ver >= 0)
4792 len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
4793 else
4794 len = snprintf(buf, len, "n/a\n");
4795 mutex_unlock(&wl->mutex);
4796
4797 return len;
4798}
4799
Gery Kahn6f07b722011-07-18 14:21:49 +03004800static DEVICE_ATTR(hw_pg_ver, S_IRUGO,
Juuso Oikarinend717fd62010-05-07 11:38:58 +03004801 wl1271_sysfs_show_hw_pg_ver, NULL);
4802
Ido Yariv95dac04f2011-06-06 14:57:06 +03004803static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj,
4804 struct bin_attribute *bin_attr,
4805 char *buffer, loff_t pos, size_t count)
4806{
4807 struct device *dev = container_of(kobj, struct device, kobj);
4808 struct wl1271 *wl = dev_get_drvdata(dev);
4809 ssize_t len;
4810 int ret;
4811
4812 ret = mutex_lock_interruptible(&wl->mutex);
4813 if (ret < 0)
4814 return -ERESTARTSYS;
4815
4816 /* Let only one thread read the log at a time, blocking others */
4817 while (wl->fwlog_size == 0) {
4818 DEFINE_WAIT(wait);
4819
4820 prepare_to_wait_exclusive(&wl->fwlog_waitq,
4821 &wait,
4822 TASK_INTERRUPTIBLE);
4823
4824 if (wl->fwlog_size != 0) {
4825 finish_wait(&wl->fwlog_waitq, &wait);
4826 break;
4827 }
4828
4829 mutex_unlock(&wl->mutex);
4830
4831 schedule();
4832 finish_wait(&wl->fwlog_waitq, &wait);
4833
4834 if (signal_pending(current))
4835 return -ERESTARTSYS;
4836
4837 ret = mutex_lock_interruptible(&wl->mutex);
4838 if (ret < 0)
4839 return -ERESTARTSYS;
4840 }
4841
4842 /* Check if the fwlog is still valid */
4843 if (wl->fwlog_size < 0) {
4844 mutex_unlock(&wl->mutex);
4845 return 0;
4846 }
4847
4848 /* Seeking is not supported - old logs are not kept. Disregard pos. */
4849 len = min(count, (size_t)wl->fwlog_size);
4850 wl->fwlog_size -= len;
4851 memcpy(buffer, wl->fwlog, len);
4852
4853 /* Make room for new messages */
4854 memmove(wl->fwlog, wl->fwlog + len, wl->fwlog_size);
4855
4856 mutex_unlock(&wl->mutex);
4857
4858 return len;
4859}
4860
4861static struct bin_attribute fwlog_attr = {
4862 .attr = {.name = "fwlog", .mode = S_IRUSR},
4863 .read = wl1271_sysfs_read_fwlog,
4864};
4865
Luciano Coelho5e037e72011-12-23 09:32:17 +02004866static bool wl12xx_mac_in_fuse(struct wl1271 *wl)
4867{
4868 bool supported = false;
4869 u8 major, minor;
4870
4871 if (wl->chip.id == CHIP_ID_1283_PG20) {
4872 major = WL128X_PG_GET_MAJOR(wl->hw_pg_ver);
4873 minor = WL128X_PG_GET_MINOR(wl->hw_pg_ver);
4874
4875 /* in wl128x we have the MAC address if the PG is >= (2, 1) */
4876 if (major > 2 || (major == 2 && minor >= 1))
4877 supported = true;
4878 } else {
4879 major = WL127X_PG_GET_MAJOR(wl->hw_pg_ver);
4880 minor = WL127X_PG_GET_MINOR(wl->hw_pg_ver);
4881
4882 /* in wl127x we have the MAC address if the PG is >= (3, 1) */
4883 if (major == 3 && minor >= 1)
4884 supported = true;
4885 }
4886
4887 wl1271_debug(DEBUG_PROBE,
4888 "PG Ver major = %d minor = %d, MAC %s present",
4889 major, minor, supported ? "is" : "is not");
4890
4891 return supported;
4892}
4893
4894static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
4895 u32 oui, u32 nic, int n)
4896{
4897 int i;
4898
4899 wl1271_debug(DEBUG_PROBE, "base address: oui %06x nic %06x, n %d",
4900 oui, nic, n);
4901
4902 if (nic + n - 1 > 0xffffff)
4903 wl1271_warning("NIC part of the MAC address wraps around!");
4904
4905 for (i = 0; i < n; i++) {
4906 wl->addresses[i].addr[0] = (u8)(oui >> 16);
4907 wl->addresses[i].addr[1] = (u8)(oui >> 8);
4908 wl->addresses[i].addr[2] = (u8) oui;
4909 wl->addresses[i].addr[3] = (u8)(nic >> 16);
4910 wl->addresses[i].addr[4] = (u8)(nic >> 8);
4911 wl->addresses[i].addr[5] = (u8) nic;
4912 nic++;
4913 }
4914
4915 wl->hw->wiphy->n_addresses = n;
4916 wl->hw->wiphy->addresses = wl->addresses;
4917}
4918
4919static void wl12xx_get_fuse_mac(struct wl1271 *wl)
4920{
4921 u32 mac1, mac2;
4922
4923 wl1271_set_partition(wl, &wl12xx_part_table[PART_DRPW]);
4924
4925 mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1);
4926 mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2);
4927
4928 /* these are the two parts of the BD_ADDR */
4929 wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) +
4930 ((mac1 & 0xff000000) >> 24);
4931 wl->fuse_nic_addr = mac1 & 0xffffff;
4932
4933 wl1271_set_partition(wl, &wl12xx_part_table[PART_DOWN]);
4934}
4935
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004936static int wl12xx_get_hw_info(struct wl1271 *wl)
4937{
4938 int ret;
4939 u32 die_info;
4940
4941 ret = wl12xx_set_power_on(wl);
4942 if (ret < 0)
4943 goto out;
4944
4945 wl->chip.id = wl1271_read32(wl, CHIP_ID_B);
4946
4947 if (wl->chip.id == CHIP_ID_1283_PG20)
4948 die_info = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1);
4949 else
4950 die_info = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1);
4951
4952 wl->hw_pg_ver = (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET;
4953
Luciano Coelho5e037e72011-12-23 09:32:17 +02004954 if (!wl12xx_mac_in_fuse(wl)) {
4955 wl->fuse_oui_addr = 0;
4956 wl->fuse_nic_addr = 0;
4957 } else {
4958 wl12xx_get_fuse_mac(wl);
4959 }
4960
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004961 wl1271_power_off(wl);
4962out:
4963 return ret;
4964}
4965
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03004966static int wl1271_register_hw(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004967{
4968 int ret;
Luciano Coelho5e037e72011-12-23 09:32:17 +02004969 u32 oui_addr = 0, nic_addr = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03004970
4971 if (wl->mac80211_registered)
4972 return 0;
4973
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02004974 ret = wl12xx_get_hw_info(wl);
4975 if (ret < 0) {
4976 wl1271_error("couldn't get hw info");
4977 goto out;
4978 }
4979
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004980 ret = wl1271_fetch_nvs(wl);
4981 if (ret == 0) {
Shahar Levibc765bf2011-03-06 16:32:10 +02004982 /* NOTE: The wl->nvs->nvs element must be first, in
4983 * order to simplify the casting, we assume it is at
4984 * the beginning of the wl->nvs structure.
4985 */
4986 u8 *nvs_ptr = (u8 *)wl->nvs;
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004987
Luciano Coelho5e037e72011-12-23 09:32:17 +02004988 oui_addr =
4989 (nvs_ptr[11] << 16) + (nvs_ptr[10] << 8) + nvs_ptr[6];
4990 nic_addr =
4991 (nvs_ptr[5] << 16) + (nvs_ptr[4] << 8) + nvs_ptr[3];
Arik Nemtsov31d26ec2010-10-16 21:49:52 +02004992 }
4993
Luciano Coelho5e037e72011-12-23 09:32:17 +02004994 /* if the MAC address is zeroed in the NVS derive from fuse */
4995 if (oui_addr == 0 && nic_addr == 0) {
4996 oui_addr = wl->fuse_oui_addr;
4997 /* fuse has the BD_ADDR, the WLAN addresses are the next two */
4998 nic_addr = wl->fuse_nic_addr + 1;
4999 }
5000
5001 wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr, 2);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005002
5003 ret = ieee80211_register_hw(wl->hw);
5004 if (ret < 0) {
5005 wl1271_error("unable to register mac80211 hw: %d", ret);
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005006 goto out;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005007 }
5008
5009 wl->mac80211_registered = true;
5010
Eliad Pellerd60080a2010-11-24 12:53:16 +02005011 wl1271_debugfs_init(wl);
5012
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005013 register_netdevice_notifier(&wl1271_dev_notifier);
5014
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005015 wl1271_notice("loaded");
5016
Luciano Coelho30c5dbd2012-01-18 14:53:22 +02005017out:
5018 return ret;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005019}
5020
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005021static void wl1271_unregister_hw(struct wl1271 *wl)
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005022{
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005023 if (wl->state == WL1271_STATE_PLT)
Ido Yarivf3df1332012-01-11 09:42:39 +02005024 wl1271_plt_stop(wl);
Juuso Oikarinen4ae3fa82011-01-14 12:48:46 +01005025
Juuso Oikarinenc2c192a2010-07-27 03:30:09 +03005026 unregister_netdevice_notifier(&wl1271_dev_notifier);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005027 ieee80211_unregister_hw(wl->hw);
5028 wl->mac80211_registered = false;
5029
5030}
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005031
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005032static int wl1271_init_ieee80211(struct wl1271 *wl)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005033{
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005034 static const u32 cipher_suites[] = {
5035 WLAN_CIPHER_SUITE_WEP40,
5036 WLAN_CIPHER_SUITE_WEP104,
5037 WLAN_CIPHER_SUITE_TKIP,
5038 WLAN_CIPHER_SUITE_CCMP,
5039 WL1271_CIPHER_SUITE_GEM,
5040 };
5041
Juuso Oikarinen1e2b7972009-10-08 21:56:20 +03005042 /* The tx descriptor buffer and the TKIP space. */
5043 wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
5044 sizeof(struct wl1271_tx_hw_descr);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005045
5046 /* unit us */
5047 /* FIXME: find a proper value */
5048 wl->hw->channel_change_time = 10000;
Juuso Oikarinen50c500a2010-04-01 11:38:22 +03005049 wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005050
5051 wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
Juuso Oikarinen0a343322010-02-22 08:38:41 +02005052 IEEE80211_HW_SUPPORTS_PS |
Kalle Valo4695dc92010-03-18 12:26:38 +02005053 IEEE80211_HW_SUPPORTS_UAPSD |
Juuso Oikarinena9af0922010-03-26 12:53:30 +02005054 IEEE80211_HW_HAS_RATE_CONTROL |
Juuso Oikarinen00236aed2010-04-09 11:07:30 +03005055 IEEE80211_HW_CONNECTION_MONITOR |
Luciano Coelho25eaea302011-05-02 12:37:33 +03005056 IEEE80211_HW_REPORTS_TX_ACK_STATUS |
Shahar Levifcd23b62011-05-11 12:12:56 +03005057 IEEE80211_HW_SPECTRUM_MGMT |
Arik Nemtsov93f8c8e2011-08-30 09:34:01 +03005058 IEEE80211_HW_AP_LINK_PS |
5059 IEEE80211_HW_AMPDU_AGGREGATION |
5060 IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005061
Juuso Oikarinen7a557242010-09-27 12:42:07 +02005062 wl->hw->wiphy->cipher_suites = cipher_suites;
5063 wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
5064
Juuso Oikarinene0d8bbf2009-12-11 15:41:04 +02005065 wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Eliad Peller045c7452011-08-28 15:23:01 +03005066 BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
5067 BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005068 wl->hw->wiphy->max_scan_ssids = 1;
Luciano Coelho221737d2011-09-02 14:28:22 +03005069 wl->hw->wiphy->max_sched_scan_ssids = 16;
5070 wl->hw->wiphy->max_match_sets = 16;
Guy Eilamea559b42010-12-09 16:54:59 +02005071 /*
5072 * Maximum length of elements in scanning probe request templates
5073 * should be the maximum length possible for a template, without
5074 * the IEEE80211 header of the template
5075 */
Eliad Peller154037d2011-08-14 13:17:12 +03005076 wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
Guy Eilamea559b42010-12-09 16:54:59 +02005077 sizeof(struct ieee80211_header);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005078
Luciano Coelhoc9e79a42011-09-27 16:22:35 +03005079 wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
5080 sizeof(struct ieee80211_header);
5081
Eliad Peller1ec23f72011-08-25 14:26:54 +03005082 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
5083
Luciano Coelho4a31c112011-03-21 23:16:14 +02005084 /* make sure all our channels fit in the scanned_ch bitmask */
5085 BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
5086 ARRAY_SIZE(wl1271_channels_5ghz) >
5087 WL1271_MAX_CHANNELS);
Luciano Coelhoa8aaaf52011-01-11 18:25:18 +01005088 /*
5089 * We keep local copies of the band structs because we need to
5090 * modify them on a per-device basis.
5091 */
5092 memcpy(&wl->bands[IEEE80211_BAND_2GHZ], &wl1271_band_2ghz,
5093 sizeof(wl1271_band_2ghz));
5094 memcpy(&wl->bands[IEEE80211_BAND_5GHZ], &wl1271_band_5ghz,
5095 sizeof(wl1271_band_5ghz));
5096
5097 wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
5098 &wl->bands[IEEE80211_BAND_2GHZ];
5099 wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
5100 &wl->bands[IEEE80211_BAND_5GHZ];
Teemu Paasikivi1ebec3d2009-10-13 12:47:48 +03005101
Kalle Valo12bd8942010-03-18 12:26:33 +02005102 wl->hw->queues = 4;
Juuso Oikarinen31627dc2010-03-26 12:53:12 +02005103 wl->hw->max_rates = 1;
Kalle Valo12bd8942010-03-18 12:26:33 +02005104
Juuso Oikarinenb7417d92010-11-10 11:27:19 +01005105 wl->hw->wiphy->reg_notifier = wl1271_reg_notify;
5106
Arik Nemtsov9c1b1902011-11-08 18:46:55 +02005107 /* the FW answers probe-requests in AP-mode */
5108 wl->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
5109 wl->hw->wiphy->probe_resp_offload =
5110 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
5111 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
5112 NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
5113
Felipe Balbia390e852011-10-06 10:07:44 +03005114 SET_IEEE80211_DEV(wl->hw, wl->dev);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005115
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005116 wl->hw->sta_data_size = sizeof(struct wl1271_station);
Eliad Peller87fbcb02011-10-05 11:55:41 +02005117 wl->hw->vif_data_size = sizeof(struct wl12xx_vif);
Arik Nemtsovf84f7d72010-10-16 20:21:23 +02005118
Luciano Coelho4c9cfa72011-01-12 14:27:03 +01005119 wl->hw->max_rx_aggregation_subframes = 8;
5120
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005121 return 0;
5122}
5123
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005124#define WL1271_DEFAULT_CHANNEL 0
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005125
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005126static struct ieee80211_hw *wl1271_alloc_hw(void)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005127{
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005128 struct ieee80211_hw *hw;
5129 struct wl1271 *wl;
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005130 int i, j, ret;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005131 unsigned int order;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005132
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005133 BUILD_BUG_ON(AP_MAX_STATIONS > WL12XX_MAX_LINKS);
Arik Nemtsovf80c2d12011-09-22 09:52:05 +03005134
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005135 hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
5136 if (!hw) {
5137 wl1271_error("could not alloc ieee80211_hw");
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005138 ret = -ENOMEM;
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005139 goto err_hw_alloc;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005140 }
5141
5142 wl = hw->priv;
5143 memset(wl, 0, sizeof(*wl));
5144
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005145 INIT_LIST_HEAD(&wl->list);
Eliad Peller876272142011-10-10 10:12:54 +02005146 INIT_LIST_HEAD(&wl->wlvif_list);
Juuso Oikarinen01c09162009-10-13 12:47:55 +03005147
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005148 wl->hw = hw;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005149
Juuso Oikarinen6742f552010-12-13 09:52:37 +02005150 for (i = 0; i < NUM_TX_QUEUES; i++)
Eliad Pellerc7ffb902011-10-05 11:56:05 +02005151 for (j = 0; j < WL12XX_MAX_LINKS; j++)
Arik Nemtsova8c0ddb2011-02-23 00:22:26 +02005152 skb_queue_head_init(&wl->links[j].tx_queue[i]);
5153
Ido Yariva6208652011-03-01 15:14:41 +02005154 skb_queue_head_init(&wl->deferred_rx_queue);
5155 skb_queue_head_init(&wl->deferred_tx_queue);
5156
Juuso Oikarinen37b70a82009-10-08 21:56:21 +03005157 INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
Ido Yariva6208652011-03-01 15:14:41 +02005158 INIT_WORK(&wl->netstack_work, wl1271_netstack_work);
Juuso Oikarinen117b38d2010-09-30 10:43:28 +02005159 INIT_WORK(&wl->tx_work, wl1271_tx_work);
5160 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
5161 INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
Eliad Peller77ddaa12011-05-15 11:10:29 +03005162
Eliad Peller92ef8962011-06-07 12:50:46 +03005163 wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
5164 if (!wl->freezable_wq) {
5165 ret = -ENOMEM;
5166 goto err_hw;
5167 }
5168
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005169 wl->channel = WL1271_DEFAULT_CHANNEL;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005170 wl->rx_counter = 0;
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005171 wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
Juuso Oikarinen8a5a37a2009-10-08 21:56:24 +03005172 wl->band = IEEE80211_BAND_2GHZ;
Juuso Oikarinenb771eee2009-10-08 21:56:34 +03005173 wl->vif = NULL;
Juuso Oikarinen830fb672009-12-11 15:41:06 +02005174 wl->flags = 0;
Juuso Oikarinen7fc3a862010-03-18 12:26:32 +02005175 wl->sg_enabled = true;
Juuso Oikarinend717fd62010-05-07 11:38:58 +03005176 wl->hw_pg_ver = -1;
Arik Nemtsovb622d992011-02-23 00:22:31 +02005177 wl->ap_ps_map = 0;
5178 wl->ap_fw_ps_map = 0;
Ido Yariv606ea9f2011-03-01 15:14:39 +02005179 wl->quirks = 0;
Ido Yariv341b7cd2011-03-31 10:07:01 +02005180 wl->platform_quirks = 0;
Luciano Coelho33c2c062011-05-10 14:46:02 +03005181 wl->sched_scanning = false;
Guy Eilame9eb8cb2011-08-16 19:49:12 +03005182 wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005183 wl->system_hlid = WL12XX_SYSTEM_HLID;
Arik Nemtsovda032092011-08-25 12:43:15 +03005184 wl->active_sta_count = 0;
Ido Yariv95dac04f2011-06-06 14:57:06 +03005185 wl->fwlog_size = 0;
5186 init_waitqueue_head(&wl->fwlog_waitq);
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005187
Eliad Pellerf4df1bd2011-08-14 13:17:15 +03005188 /* The system link is always allocated */
5189 __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
5190
Ido Yariv25eeb9e2010-10-12 16:20:06 +02005191 memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
Juuso Oikarinenbe7078c2009-10-08 21:56:26 +03005192 for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005193 wl->tx_frames[i] = NULL;
5194
5195 spin_lock_init(&wl->wl_lock);
5196
Luciano Coelhof5fc0f82009-08-06 16:25:28 +03005197 wl->state = WL1271_STATE_OFF;
5198 mutex_init(&wl->mutex);
5199
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005200 /* Apply default driver configuration. */
5201 wl1271_conf_init(wl);
5202
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005203 order = get_order(WL1271_AGGR_BUFFER_SIZE);
5204 wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
5205 if (!wl->aggr_buf) {
5206 ret = -ENOMEM;
Eliad Peller92ef8962011-06-07 12:50:46 +03005207 goto err_wq;
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005208 }
5209
Ido Yariv990f5de2011-03-31 10:06:59 +02005210 wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
5211 if (!wl->dummy_packet) {
5212 ret = -ENOMEM;
5213 goto err_aggr;
5214 }
5215
Ido Yariv95dac04f2011-06-06 14:57:06 +03005216 /* Allocate one page for the FW log */
5217 wl->fwlog = (u8 *)get_zeroed_page(GFP_KERNEL);
5218 if (!wl->fwlog) {
5219 ret = -ENOMEM;
5220 goto err_dummy_packet;
5221 }
5222
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005223 return hw;
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005224
Ido Yariv990f5de2011-03-31 10:06:59 +02005225err_dummy_packet:
5226 dev_kfree_skb(wl->dummy_packet);
5227
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005228err_aggr:
5229 free_pages((unsigned long)wl->aggr_buf, order);
5230
Eliad Peller92ef8962011-06-07 12:50:46 +03005231err_wq:
5232 destroy_workqueue(wl->freezable_wq);
5233
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005234err_hw:
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005235 wl1271_debugfs_exit(wl);
Teemu Paasikivi3b56dd62010-03-18 12:26:46 +02005236 ieee80211_free_hw(hw);
5237
5238err_hw_alloc:
5239
Juuso Oikarinena1dd8182010-03-18 12:26:31 +02005240 return ERR_PTR(ret);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005241}
5242
Felipe Balbi4b32a2c2011-10-06 10:46:20 +03005243static int wl1271_free_hw(struct wl1271 *wl)
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005244{
Ido Yariv95dac04f2011-06-06 14:57:06 +03005245 /* Unblock any fwlog readers */
5246 mutex_lock(&wl->mutex);
5247 wl->fwlog_size = -1;
5248 wake_up_interruptible_all(&wl->fwlog_waitq);
5249 mutex_unlock(&wl->mutex);
5250
Felipe Balbif79f8902011-10-06 13:05:25 +03005251 device_remove_bin_file(wl->dev, &fwlog_attr);
Gery Kahn6f07b722011-07-18 14:21:49 +03005252
Felipe Balbif79f8902011-10-06 13:05:25 +03005253 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
Gery Kahn6f07b722011-07-18 14:21:49 +03005254
Felipe Balbif79f8902011-10-06 13:05:25 +03005255 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
Ido Yariv95dac04f2011-06-06 14:57:06 +03005256 free_page((unsigned long)wl->fwlog);
Ido Yariv990f5de2011-03-31 10:06:59 +02005257 dev_kfree_skb(wl->dummy_packet);
Ido Yariv1f37cbc2010-09-30 13:28:27 +02005258 free_pages((unsigned long)wl->aggr_buf,
5259 get_order(WL1271_AGGR_BUFFER_SIZE));
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005260
5261 wl1271_debugfs_exit(wl);
5262
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005263 vfree(wl->fw);
5264 wl->fw = NULL;
5265 kfree(wl->nvs);
5266 wl->nvs = NULL;
5267
5268 kfree(wl->fw_status);
5269 kfree(wl->tx_res_if);
Eliad Peller92ef8962011-06-07 12:50:46 +03005270 destroy_workqueue(wl->freezable_wq);
Teemu Paasikivic332a4b2010-02-18 13:25:57 +02005271
5272 ieee80211_free_hw(wl->hw);
5273
5274 return 0;
5275}
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005276
Felipe Balbia390e852011-10-06 10:07:44 +03005277static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
5278{
5279 struct wl1271 *wl = cookie;
5280 unsigned long flags;
5281
5282 wl1271_debug(DEBUG_IRQ, "IRQ");
5283
5284 /* complete the ELP completion */
5285 spin_lock_irqsave(&wl->wl_lock, flags);
5286 set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
5287 if (wl->elp_compl) {
5288 complete(wl->elp_compl);
5289 wl->elp_compl = NULL;
5290 }
5291
5292 if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
5293 /* don't enqueue a work right now. mark it as pending */
5294 set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
5295 wl1271_debug(DEBUG_IRQ, "should not enqueue work");
5296 disable_irq_nosync(wl->irq);
5297 pm_wakeup_event(wl->dev, 0);
5298 spin_unlock_irqrestore(&wl->wl_lock, flags);
5299 return IRQ_HANDLED;
5300 }
5301 spin_unlock_irqrestore(&wl->wl_lock, flags);
5302
5303 return IRQ_WAKE_THREAD;
5304}
5305
Felipe Balbice2a2172011-10-05 14:12:55 +03005306static int __devinit wl12xx_probe(struct platform_device *pdev)
5307{
Felipe Balbia390e852011-10-06 10:07:44 +03005308 struct wl12xx_platform_data *pdata = pdev->dev.platform_data;
5309 struct ieee80211_hw *hw;
5310 struct wl1271 *wl;
5311 unsigned long irqflags;
5312 int ret = -ENODEV;
5313
5314 hw = wl1271_alloc_hw();
5315 if (IS_ERR(hw)) {
5316 wl1271_error("can't allocate hw");
5317 ret = PTR_ERR(hw);
5318 goto out;
5319 }
5320
5321 wl = hw->priv;
5322 wl->irq = platform_get_irq(pdev, 0);
5323 wl->ref_clock = pdata->board_ref_clock;
5324 wl->tcxo_clock = pdata->board_tcxo_clock;
5325 wl->platform_quirks = pdata->platform_quirks;
5326 wl->set_power = pdata->set_power;
5327 wl->dev = &pdev->dev;
5328 wl->if_ops = pdata->ops;
5329
5330 platform_set_drvdata(pdev, wl);
5331
5332 if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
5333 irqflags = IRQF_TRIGGER_RISING;
5334 else
5335 irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
5336
5337 ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq,
5338 irqflags,
5339 pdev->name, wl);
5340 if (ret < 0) {
5341 wl1271_error("request_irq() failed: %d", ret);
5342 goto out_free_hw;
5343 }
5344
5345 ret = enable_irq_wake(wl->irq);
5346 if (!ret) {
5347 wl->irq_wake_enabled = true;
5348 device_init_wakeup(wl->dev, 1);
5349 if (pdata->pwr_in_suspend)
5350 hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
5351
5352 }
5353 disable_irq(wl->irq);
5354
5355 ret = wl1271_init_ieee80211(wl);
5356 if (ret)
5357 goto out_irq;
5358
5359 ret = wl1271_register_hw(wl);
5360 if (ret)
5361 goto out_irq;
5362
Felipe Balbif79f8902011-10-06 13:05:25 +03005363 /* Create sysfs file to control bt coex state */
5364 ret = device_create_file(wl->dev, &dev_attr_bt_coex_state);
5365 if (ret < 0) {
5366 wl1271_error("failed to create sysfs file bt_coex_state");
5367 goto out_irq;
5368 }
5369
5370 /* Create sysfs file to get HW PG version */
5371 ret = device_create_file(wl->dev, &dev_attr_hw_pg_ver);
5372 if (ret < 0) {
5373 wl1271_error("failed to create sysfs file hw_pg_ver");
5374 goto out_bt_coex_state;
5375 }
5376
5377 /* Create sysfs file for the FW log */
5378 ret = device_create_bin_file(wl->dev, &fwlog_attr);
5379 if (ret < 0) {
5380 wl1271_error("failed to create sysfs file fwlog");
5381 goto out_hw_pg_ver;
5382 }
5383
Felipe Balbice2a2172011-10-05 14:12:55 +03005384 return 0;
Felipe Balbia390e852011-10-06 10:07:44 +03005385
Felipe Balbif79f8902011-10-06 13:05:25 +03005386out_hw_pg_ver:
5387 device_remove_file(wl->dev, &dev_attr_hw_pg_ver);
5388
5389out_bt_coex_state:
5390 device_remove_file(wl->dev, &dev_attr_bt_coex_state);
5391
Felipe Balbia390e852011-10-06 10:07:44 +03005392out_irq:
5393 free_irq(wl->irq, wl);
5394
5395out_free_hw:
5396 wl1271_free_hw(wl);
5397
5398out:
5399 return ret;
Felipe Balbice2a2172011-10-05 14:12:55 +03005400}
5401
5402static int __devexit wl12xx_remove(struct platform_device *pdev)
5403{
Felipe Balbia390e852011-10-06 10:07:44 +03005404 struct wl1271 *wl = platform_get_drvdata(pdev);
5405
5406 if (wl->irq_wake_enabled) {
5407 device_init_wakeup(wl->dev, 0);
5408 disable_irq_wake(wl->irq);
5409 }
5410 wl1271_unregister_hw(wl);
5411 free_irq(wl->irq, wl);
5412 wl1271_free_hw(wl);
5413
Felipe Balbice2a2172011-10-05 14:12:55 +03005414 return 0;
5415}
5416
5417static const struct platform_device_id wl12xx_id_table[] __devinitconst = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005418 { "wl12xx", 0 },
Felipe Balbice2a2172011-10-05 14:12:55 +03005419 { } /* Terminating Entry */
5420};
5421MODULE_DEVICE_TABLE(platform, wl12xx_id_table);
5422
5423static struct platform_driver wl12xx_driver = {
5424 .probe = wl12xx_probe,
5425 .remove = __devexit_p(wl12xx_remove),
5426 .id_table = wl12xx_id_table,
5427 .driver = {
Luciano Coelhoccb62002011-10-07 15:54:15 +03005428 .name = "wl12xx_driver",
Felipe Balbice2a2172011-10-05 14:12:55 +03005429 .owner = THIS_MODULE,
5430 }
5431};
5432
5433static int __init wl12xx_init(void)
5434{
5435 return platform_driver_register(&wl12xx_driver);
5436}
5437module_init(wl12xx_init);
5438
5439static void __exit wl12xx_exit(void)
5440{
5441 platform_driver_unregister(&wl12xx_driver);
5442}
5443module_exit(wl12xx_exit);
5444
Guy Eilam491bbd62011-01-12 10:33:29 +01005445u32 wl12xx_debug_level = DEBUG_NONE;
Eliad Peller17c17552010-12-12 12:15:35 +02005446EXPORT_SYMBOL_GPL(wl12xx_debug_level);
Guy Eilam491bbd62011-01-12 10:33:29 +01005447module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR);
Eliad Peller17c17552010-12-12 12:15:35 +02005448MODULE_PARM_DESC(debug_level, "wl12xx debugging level");
5449
Ido Yariv95dac04f2011-06-06 14:57:06 +03005450module_param_named(fwlog, fwlog_param, charp, 0);
Luciano Coelho2c882fa2012-02-07 12:37:33 +02005451MODULE_PARM_DESC(fwlog,
Ido Yariv95dac04f2011-06-06 14:57:06 +03005452 "FW logger options: continuous, ondemand, dbgpins or disable");
5453
Eliad Peller2a5bff02011-08-25 18:10:59 +03005454module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
5455MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
5456
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005457MODULE_LICENSE("GPL");
Luciano Coelhob1a48ca2011-02-22 14:19:28 +02005458MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
Teemu Paasikivi50b3eb42010-02-22 08:38:26 +02005459MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");